Compare commits
40 Commits
v0.0.4-rc1
...
v0.0.4-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa93e0cbb1 | ||
|
|
ead5978b34 | ||
|
|
bfb112dad1 | ||
|
|
2d3ba3e5dd | ||
|
|
36b736482a | ||
|
|
dbc98f758e | ||
|
|
84db3351ab | ||
|
|
3a54d322ab | ||
|
|
f9773fa908 | ||
|
|
2dc6d773ee | ||
|
|
402d8e833d | ||
|
|
d498db1106 | ||
|
|
e93159b047 | ||
|
|
d989166044 | ||
|
|
c96defb80d | ||
|
|
06275885f1 | ||
|
|
206e7af162 | ||
|
|
cdf4ce07bc | ||
|
|
2f591d33d3 | ||
|
|
e4b0c03a22 | ||
|
|
9582dfffee | ||
|
|
cf9f78636a | ||
|
|
ae46778cc3 | ||
|
|
c31761ab75 | ||
|
|
b50f8c620b | ||
|
|
fa718acfbe | ||
|
|
ce0a299bdb | ||
|
|
d3dbabcfc7 | ||
|
|
effe8109a7 | ||
|
|
2924297790 | ||
|
|
5c6aaa7eb1 | ||
|
|
83c162d80d | ||
|
|
1a2d1821b5 | ||
|
|
a9b87077f8 | ||
|
|
2e092d5f5d | ||
|
|
a5996c7511 | ||
|
|
1c57172524 | ||
|
|
d34b44ce39 | ||
|
|
ecf7af0cde | ||
|
|
6b01c13975 |
@@ -4,7 +4,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# specify full path if dupes may exist
|
||||
EXCLUDE_FILES="CPM.cmake CPMUtil.cmake GetSCMRev.cmake sse2neon.h renderdoc_app.h tools/cpm tools/shellcheck.sh tools/update-cpm.sh externals/stb externals/glad externals/getopt externals/gamemode externals/FidelityFX-FSR externals/demangle externals/bc_decoder"
|
||||
EXCLUDE_FILES="CPM.cmake CPMUtil.cmake GetSCMRev.cmake renderdoc_app.h tools/cpm tools/shellcheck.sh tools/update-cpm.sh externals/stb externals/glad externals/getopt externals/gamemode externals/FidelityFX-FSR externals/demangle externals/bc_decoder"
|
||||
|
||||
# license header constants, please change when needed :))))
|
||||
YEAR=2025
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
From d765ebed3598ddfd7167fc546474626ac5ef9498 Mon Sep 17 00:00:00 2001
|
||||
From: Anthony Roberts <anthony.roberts@linaro.org>
|
||||
Date: Fri, 2 Aug 2024 16:55:57 +0100
|
||||
Subject: [PATCH] Add support for clang-cl on Windows (#633)
|
||||
|
||||
This commit adds support for clang-cl (clang, pretending to be MSVC) to
|
||||
SSE2NEON on Windows ARM64 platforms. This change is part of some Blender
|
||||
work, as using clang-cl provides a ~20-40% speedup compared to MSVC.
|
||||
|
||||
Compiled with the following command line (via a VS2022 Native ARM64 Tools
|
||||
CMD window):
|
||||
msbuild sse2neon.vcxproj /p:Configuration=Release /p:CLToolExe=clang-cl.exe
|
||||
/p:CLToolPath="C:\Program Files\LLVM\bin\"
|
||||
|
||||
Known failures in test suite:
|
||||
Test mm_cvttpd_epi32
|
||||
Test rdtsc
|
||||
|
||||
Co-authored-by: Anthony Roberts <anthony.roberts@linaro.org>
|
||||
---
|
||||
sse2neon.h | 22 +++++++++++-----------
|
||||
1 file changed, 11 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/sse2neon.h b/sse2neon.h
|
||||
index 56254b5..76cf8e3 100644
|
||||
--- a/sse2neon.h
|
||||
+++ b/sse2neon.h
|
||||
@@ -180,7 +180,7 @@
|
||||
}
|
||||
|
||||
/* Compiler barrier */
|
||||
-#if defined(_MSC_VER)
|
||||
+#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define SSE2NEON_BARRIER() _ReadWriteBarrier()
|
||||
#else
|
||||
#define SSE2NEON_BARRIER() \
|
||||
@@ -856,7 +856,7 @@ FORCE_INLINE uint64x2_t _sse2neon_vmull_p64(uint64x1_t _a, uint64x1_t _b)
|
||||
{
|
||||
poly64_t a = vget_lane_p64(vreinterpret_p64_u64(_a), 0);
|
||||
poly64_t b = vget_lane_p64(vreinterpret_p64_u64(_b), 0);
|
||||
-#if defined(_MSC_VER)
|
||||
+#if defined(_MSC_VER) && !defined(__clang__)
|
||||
__n64 a1 = {a}, b1 = {b};
|
||||
return vreinterpretq_u64_p128(vmull_p64(a1, b1));
|
||||
#else
|
||||
@@ -1767,7 +1767,7 @@ FORCE_INLINE void _mm_free(void *addr)
|
||||
FORCE_INLINE uint64_t _sse2neon_get_fpcr(void)
|
||||
{
|
||||
uint64_t value;
|
||||
-#if defined(_MSC_VER)
|
||||
+#if defined(_MSC_VER) && !defined(__clang__)
|
||||
value = _ReadStatusReg(ARM64_FPCR);
|
||||
#else
|
||||
__asm__ __volatile__("mrs %0, FPCR" : "=r"(value)); /* read */
|
||||
@@ -1777,7 +1777,7 @@ FORCE_INLINE uint64_t _sse2neon_get_fpcr(void)
|
||||
|
||||
FORCE_INLINE void _sse2neon_set_fpcr(uint64_t value)
|
||||
{
|
||||
-#if defined(_MSC_VER)
|
||||
+#if defined(_MSC_VER) && !defined(__clang__)
|
||||
_WriteStatusReg(ARM64_FPCR, value);
|
||||
#else
|
||||
__asm__ __volatile__("msr FPCR, %0" ::"r"(value)); /* write */
|
||||
@@ -2246,7 +2246,7 @@ FORCE_INLINE __m128 _mm_or_ps(__m128 a, __m128 b)
|
||||
FORCE_INLINE void _mm_prefetch(char const *p, int i)
|
||||
{
|
||||
(void) i;
|
||||
-#if defined(_MSC_VER)
|
||||
+#if defined(_MSC_VER) && !defined(__clang__)
|
||||
switch (i) {
|
||||
case _MM_HINT_NTA:
|
||||
__prefetch2(p, 1);
|
||||
@@ -4817,7 +4817,7 @@ FORCE_INLINE __m128i _mm_packus_epi16(const __m128i a, const __m128i b)
|
||||
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_pause
|
||||
FORCE_INLINE void _mm_pause(void)
|
||||
{
|
||||
-#if defined(_MSC_VER)
|
||||
+#if defined(_MSC_VER) && !defined(__clang__)
|
||||
__isb(_ARM64_BARRIER_SY);
|
||||
#else
|
||||
__asm__ __volatile__("isb\n");
|
||||
@@ -5713,7 +5713,7 @@ FORCE_INLINE __m128d _mm_undefined_pd(void)
|
||||
#pragma GCC diagnostic ignored "-Wuninitialized"
|
||||
#endif
|
||||
__m128d a;
|
||||
-#if defined(_MSC_VER)
|
||||
+#if defined(_MSC_VER) && !defined(__clang__)
|
||||
a = _mm_setzero_pd();
|
||||
#endif
|
||||
return a;
|
||||
@@ -8127,7 +8127,7 @@ FORCE_INLINE int _sse2neon_sido_negative(int res, int lb, int imm8, int bound)
|
||||
|
||||
FORCE_INLINE int _sse2neon_clz(unsigned int x)
|
||||
{
|
||||
-#ifdef _MSC_VER
|
||||
+#if defined(_MSC_VER) && !defined(__clang__)
|
||||
unsigned long cnt = 0;
|
||||
if (_BitScanReverse(&cnt, x))
|
||||
return 31 - cnt;
|
||||
@@ -8139,7 +8139,7 @@ FORCE_INLINE int _sse2neon_clz(unsigned int x)
|
||||
|
||||
FORCE_INLINE int _sse2neon_ctz(unsigned int x)
|
||||
{
|
||||
-#ifdef _MSC_VER
|
||||
+#if defined(_MSC_VER) && !defined(__clang__)
|
||||
unsigned long cnt = 0;
|
||||
if (_BitScanForward(&cnt, x))
|
||||
return cnt;
|
||||
@@ -9055,7 +9055,7 @@ FORCE_INLINE __m128i _mm_aeskeygenassist_si128(__m128i a, const int rcon)
|
||||
// AESE does ShiftRows and SubBytes on A
|
||||
uint8x16_t u8 = vaeseq_u8(vreinterpretq_u8_m128i(a), vdupq_n_u8(0));
|
||||
|
||||
-#ifndef _MSC_VER
|
||||
+#if !defined(_MSC_VER) || defined(__clang__)
|
||||
uint8x16_t dest = {
|
||||
// Undo ShiftRows step from AESE and extract X1 and X3
|
||||
u8[0x4], u8[0x1], u8[0xE], u8[0xB], // SubBytes(X1)
|
||||
@@ -9242,7 +9242,7 @@ FORCE_INLINE uint64_t _rdtsc(void)
|
||||
* bits wide and it is attributed with the flag 'cap_user_time_short'
|
||||
* is true.
|
||||
*/
|
||||
-#if defined(_MSC_VER)
|
||||
+#if defined(_MSC_VER) && !defined(__clang__)
|
||||
val = _ReadStatusReg(ARM64_SYSREG(3, 3, 14, 0, 2));
|
||||
#else
|
||||
__asm__ __volatile__("mrs %0, cntvct_el0" : "=r"(val));
|
||||
--
|
||||
2.48.1
|
||||
|
||||
@@ -231,7 +231,7 @@ if(USE_CCACHE)
|
||||
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_BINARY})
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_BINARY})
|
||||
else()
|
||||
message(WARNING "USE_CCACHE enabled, but no executable found at: ${CCACHE_PATH}")
|
||||
message(FATAL_ERROR "USE_CCACHE enabled, but no executable found at: ${CCACHE_PATH}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -344,10 +344,6 @@ if (NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.
|
||||
file(WRITE ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json "")
|
||||
endif()
|
||||
|
||||
if (UNIX)
|
||||
add_compile_definitions(YUZU_UNIX=1)
|
||||
endif()
|
||||
|
||||
if (YUZU_LEGACY)
|
||||
message(WARNING "Making legacy build. Performance may suffer.")
|
||||
add_compile_definitions(YUZU_LEGACY)
|
||||
@@ -377,6 +373,8 @@ endif()
|
||||
# Build/optimization presets
|
||||
if (PLATFORM_LINUX OR CXX_CLANG)
|
||||
if (ARCHITECTURE_x86_64)
|
||||
# See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
|
||||
# Generic supports Pentium Pro instruction set and above
|
||||
set(YUZU_BUILD_PRESET "custom" CACHE STRING "Build preset to use. One of: custom, generic, v3, zen2, zen4, native")
|
||||
if (${YUZU_BUILD_PRESET} STREQUAL "generic")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -mtune=generic")
|
||||
@@ -395,13 +393,17 @@ if (PLATFORM_LINUX OR CXX_CLANG)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native -mtune=native")
|
||||
endif()
|
||||
elseif(ARCHITECTURE_arm64)
|
||||
set(YUZU_BUILD_PRESET "custom" CACHE STRING "Build preset to use. One of: custom, generic, armv9")
|
||||
# See https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html
|
||||
set(YUZU_BUILD_PRESET "custom" CACHE STRING "Build preset to use. One of: custom, generic, armv9, native")
|
||||
if (${YUZU_BUILD_PRESET} STREQUAL "generic")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv8-a -mtune=generic")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv8-a -mtune=generic")
|
||||
elseif (${YUZU_BUILD_PRESET} STREQUAL "armv9")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv9-a -mtune=generic")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv9-a -mtune=generic")
|
||||
elseif (${YUZU_BUILD_PRESET} STREQUAL "native")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -mtune=native")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native -mtune=native")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -611,9 +613,6 @@ find_package(VulkanUtilityLibraries)
|
||||
find_package(SimpleIni)
|
||||
find_package(SPIRV-Tools)
|
||||
find_package(sirit)
|
||||
if (ARCHITECTURE_arm64)
|
||||
find_package(sse2neon)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
|
||||
find_package(xbyak)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# SPDX-FileCopyrightText: 2022 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
||||
107
dist/dev.eden_emu.eden.svg
vendored
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 13 KiB |
BIN
dist/eden.ico
vendored
|
Before Width: | Height: | Size: 316 KiB After Width: | Height: | Size: 403 KiB |
BIN
dist/eden_named.ico
vendored
|
Before Width: | Height: | Size: 54 KiB |
117
dist/eden_named.svg
vendored
|
Before Width: | Height: | Size: 4.9 MiB After Width: | Height: | Size: 39 KiB |
1
dist/icon_variations/base.svg
vendored
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
81
dist/icon_variations/base_named.svg
vendored
Normal file
|
After Width: | Height: | Size: 37 KiB |
106
dist/icon_variations/halloween2025.svg
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="512"
|
||||
height="512"
|
||||
fill="none"
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg7"
|
||||
sodipodi:docname="dev.eden_emu.eden.svg"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs7" />
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="1.25"
|
||||
inkscape:cx="186.8"
|
||||
inkscape:cy="210.4"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="849"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg7" />
|
||||
<path
|
||||
fill="#bf42f6"
|
||||
d="M346.71 255.306c.788.006 1.577.013 3.124.059 4.006.027 7.253.015 10.501.003 33.391.022 66.783.028 100.175.078 8.174.013 16.349.279 24.522.209 3.084-.026 4.596.75 4.356 4.156-.293 4.157-.31 8.343-.259 12.513.049 3.964-1.248 5.539-5.679 5.524-48.85-.158-97.701-.071-146.552-.056-22.107.007-44.214 0-66.321 0h-5.43v7.117h223.011c-1.553 8.254-2.894 15.76-4.475 23.215-.17.802-1.666 1.617-2.685 1.87-1.312.327-2.763.099-4.155.099H265.099v6.701h216.666c-1.609 5.425-2.887 10.074-4.367 14.658-2.758 8.54-2.807 8.524-11.564 8.524-64.929 0-129.859.014-194.788-.04-3.401-.003-6.19.251-4.758 4.652.349 1.075 1.875 2.026 3.071 2.491 1.075.418 2.439.092 3.676.092l191.542.001h7.17c-3.533 7.29-6.399 13.72-9.834 19.83-.651 1.157-3.562 1.448-5.432 1.454-27.981.088-55.963.061-83.944.061-31.692 0-63.384.005-95.075-.008-2.61-.002-5.219-.124-8.53-.021-3.11.173-5.518.177-7.926.181-.849-7.032-2.289-14.051-2.44-21.098-.547-25.616-.773-51.242-.844-76.864-.014-4.88 1.228-9.763 2.52-14.927 2.88-.296 5.132-.31 7.81-.259 22.492.021 44.557-.024 67.034-.066 4.149-.049 7.886-.099 11.624-.149"
|
||||
id="path1"
|
||||
style="fill:#fea265;fill-opacity:1" />
|
||||
<path
|
||||
fill="#ff44c4"
|
||||
d="M168.124 257.114v-9.301c-2.407 0-4.67-.001-6.933.001-44.522.025-89.044.01-133.566.146-3.858.012-5.358-1.03-4.744-5 .683-4.418 1.254-8.885 1.393-13.346.106-3.386 1.603-4.005 4.608-4.012 45.9-.11 91.801-.344 137.702-.452 3.865-.009 6.842-.344 6.032-5.831H25.546c1.39-6.599 2.354-12.681 4.138-18.513.413-1.35 3.628-2.615 5.555-2.618 47.458-.084 94.917-.01 142.375.109 3.275.008 5.855-.38 6.138-5.045H31.147c3.43-9.311 6.348-17.71 9.74-25.913.483-1.166 3.265-1.942 4.987-1.95 24.582-.124 49.165-.21 73.745.014 5.283.048 8.073-2.583 11.128-7.248h-86.45c4.35-7.835 8.002-14.753 12.077-21.412.67-1.096 3.197-1.473 4.868-1.478 30.611-.083 61.226-.291 91.832.113 7.185.094 12.719-2.619 18.321-6.774H61.385c2.592-3.805 4.355-6.546 6.268-9.178 8.88-12.216 8.896-12.209 24.069-12.21q60.991-.002 121.982-.001h5.885c-3.968-4.128-7.007-6.966-12.321-6.944-38.959.165-77.92.09-116.88.09H85.03l-.741-1.31c3.832-3.852 7.564-7.81 11.514-11.537 11.456-10.807 11.495-10.996 27.246-10.717 23.209.411 45.103 6.8 66.234 15.885 5.657 2.432 10.56 3.715 16.604.944 4.726-2.166 10.217-2.664 16.034-3.521-4.411 8.139.887 12.041 5.52 16.414 5.73 5.408 11.223 11.07 16.751 16.688 1.165 1.185 2.035 2.659 3.685 4.857-2.256.128-3.665.274-5.075.275-9.739.008-19.489.286-29.214-.085-28.045-1.07-51.592 9.244-71.602 28.209-7.152 6.778-13.525 14.379-20.212 21.643-.683.742-1.079 1.748-2.209 3.632 33.94-11.926 65.876-27.377 101.589-28.637l.859 1.395c-4.228 4.943-8.188 10.148-12.73 14.783-18.091 18.461-28.905 40.673-33.892 65.773-1.402 7.057-1.306 14.412-2.504 21.941-1.992.248-3.377.184-4.762.121m19.995-91.726c3.865.004 7.763-.315 11.585.09 5.562.589 8.92-2.178 12.525-7.52-9.134 2.152-17.144 4.039-25.139 5.988-.008.002.209.928 1.029 1.442"
|
||||
id="path2"
|
||||
style="fill:#ff7f2a;fill-opacity:1" />
|
||||
<path
|
||||
fill="#bf43f5"
|
||||
d="M167.719 257.136c1.79.041 3.175.105 4.979.185.569 3.091.719 6.166.87 9.24l1.623.577c2.3-3.392 4.599-6.785 7.467-10.458 2.456-.382 4.343-.483 6.573-.598 1.405-.133 2.466-.342 3.53-.356 12.08-.162 24.16-.295 36.693-.368 3.463.111 6.473.155 9.484.2-1.12 6.677-2.306 13.345-3.347 20.035-4.715 30.285-5.404 60.697-3.186 91.651-2.469.746-4.517 1.048-6.565 1.35-56.117-.025-112.236-.135-168.353.061-5.334.018-8.298-1.559-10.185-6.415-1.874-4.824-4.295-9.436-6.907-15.069h17.147c53.955 0 107.909.013 161.863-.044 2.026-.002 4.864 1.218 5.327-2.599.469-3.862-1.271-4.625-4.781-4.616-38.803.103-77.607.061-116.411.068-20.405.003-40.811-.065-61.215.125-3.545.033-5.36-1.044-6.324-4.419-1.642-5.75-3.577-11.416-5.879-18.659 65.363-.259 129.677-.027 194.424-.144l.372-6.533c-1.901-.099-3.398-.244-4.896-.245-58.283-.032-116.565-.056-174.848-.06-4.48 0-8.964.279-13.439.163-1.138-.029-3.078-.897-3.247-1.681-1.676-7.766-3.056-15.595-4.624-23.961 8.433 0 15.808-.031 23.182.02 1.998.014 3.995.4 5.992.401 55.964.023 111.928.02 167.892.017 6.075 0 6.307-.256 6.266-7.198H23.431c-.284-6.643-.72-12.739-.592-18.823.016-.786 2.94-2.144 4.53-2.165 15.149-.197 30.3-.177 45.45-.191 17.623-.016 35.248-.072 52.871.018 13.876.07 27.75.335 42.029.491"
|
||||
id="path3"
|
||||
style="fill:#fea265;fill-opacity:1" />
|
||||
<path
|
||||
fill="#985ded"
|
||||
d="M225.868 369.021c2.02-.729 4.068-1.031 6.551-1.351 2.672 17.851 4.169 35.853 7.334 53.556 4.047 22.64 9.785 44.94 18.63 66.298.29.699.498 1.433.742 2.142-25.39 10.452-124.622-22.609-146.929-49.453h122.669c.302-4.81-.85-6.915-5.85-6.891-39.883.193-79.768.055-119.652.182-4.441.014-8.036-.845-11.208-4.17-6.87-7.203-13.99-14.166-21.008-21.228l.69-1.319H229.63l-1.24-7.289h-5.726c-42.821 0-85.642.011-128.464-.013-6.18-.003-12.371-.428-18.537-.173-3.704.154-6.14-1.066-8.104-4.073-4.111-6.292-8.367-12.489-13.256-19.755h171.593c0-2.433 0-4.234-.027-6.463m35.103.062c2.442-.418 4.85-.422 7.641-.431.482 1.987.581 3.979.706 6.499H457.62c-3.126 4.951-5.544 8.946-8.123 12.835-7.64 11.521-7.665 11.508-21.226 11.509l-147.5.003h-5.407c-.602 6.688-.15 7.214 5.824 7.214q73.75.004 147.5.004h6.891c-4.048 4.533-7.454 7.812-10.233 11.556-9.047 12.19-20.575 16.124-35.967 15.542-33.039-1.25-66.159-.384-99.246-.384h-5.45c-.275 5.77.583 6.774 5.594 6.776 34.478.012 68.957.006 103.435.007h5.302l.443 1.274c-3.495 2.62-6.91 5.358-10.5 7.842-23.505 16.265-49.192 27.744-76.893 34.696-3.263.819-6.763 1.374-10.069 1.085-1.874-.164-4.144-1.915-5.266-3.597-9.503-14.258-15.474-30.133-21.055-46.227-7.418-21.394-11.59-43.465-14.702-66.203"
|
||||
id="path4"
|
||||
style="fill:#fe8463;fill-opacity:1" />
|
||||
<path
|
||||
fill="#ff43c4"
|
||||
d="M360.319 254.985c-3.232.395-6.479.407-10.189.359 2.612-14.328 2.295-28.523-1.162-42.703-4.74-19.439-15.808-34.254-32.502-45.039-.639-.413-1.27-.839-1.852-2.137h52.547l.213-1.506c-7.026-2.665-13.978-5.752-21.733-5.819-15.455-.136-30.914.047-46.369-.12-3.092-.034-6.173-1.044-9.202-2.411 18.374-7.385 37.172-6.583 56.061-3.6 19.128 3.021 35.771 12.957 54.614 20.622l-3.662-6.95c1.846-.148 3.252-.359 4.658-.36 21.485-.021 42.97.048 64.454-.082 3.262-.019 5.062.848 6.121 4.101 2.319 7.128 5.012 14.134 7.891 22.129h-127.22c.144 4.537 2.105 5.796 5.897 5.783q43.588-.154 87.175-.028c10.803.031 21.607.309 32.402.688 1.327.047 3.486 1.183 3.763 2.215 1.549 5.774 2.638 11.671 4.021 18.169H361.127c-.548 6.29-.254 6.61 5.207 6.619 38.949.061 77.898.158 116.847.146 2.863-.001 4.211.672 4.397 3.772.304 5.076.956 10.136 1.609 15.183.414 3.199-.637 4.443-4.005 4.328-6.635-.228-13.283-.105-19.926-.106q-49.152-.005-98.304.001c-6.266.001-6.266.007-6.633 6.746"
|
||||
id="path5"
|
||||
style="fill:#ff7f2a;fill-opacity:1" />
|
||||
<path
|
||||
fill="#ff42c3"
|
||||
d="M214.837 27.347c41.832-7.02 81.069-2.12 103 5.453-3.084 7.222-6.153 14.42-9.231 21.612-1.64 3.833-3.549 7.574-4.869 11.513-1.091 3.256-2.992 4.06-6.217 4.042-22.092-.119-44.185-.062-67.454-.062 3.94 4.046 6.873 7.296 12.308 7.245 16.689-.157 33.381-.056 50.072-.055h6.745c-3.661 6.1-6.056 11.84-9.975 16.217-6.139 6.856-13.44 12.659-19.972 19.184-2.516 2.514-3.687 2.416-6.101-.229-9.873-10.813-19.809-21.593-30.196-31.908-11.454-11.376-25.983-16.088-41.742-17.908-14.011-1.618-27.312.965-40.451 5.507a34.7 34.7 0 0 1-9.886 1.86c-7.248.275-14.513.085-21.995-.508 28.501-21.58 60.452-35.31 95.964-41.963m53.746 77.311 3.605-4.283h-11.056c1.525 2.155 2.339 3.846 3.653 4.931.643.531 2.216-.065 3.798-.648"
|
||||
id="path6"
|
||||
style="fill:#63915a;fill-opacity:1" />
|
||||
<path
|
||||
fill="#ff44c4"
|
||||
d="M377.152 144.943c-12.092-9.869-26.287-13.386-40.919-15.513-16.956-2.465-33.583-1.51-50.074 5.653.952-1.742 1.722-3.617 2.884-5.206 15.646-21.395 34.923-38.76 58.357-51.192 3.545-1.881 8.365-1.78 12.607-1.849 13.445-.22 26.898-.165 40.345-.002 2.017.024 4.514.652 5.947 1.938 7.01 6.292 13.741 12.894 20.545 19.414.386.37.542.98 1.172 2.175h-5.468c-30.918 0-61.837.116-92.753-.114-5.213-.039-8.095 2.606-11.98 6.969h6.295c35.092-.001 70.184.065 105.275-.091 4.005-.018 6.738 1.186 8.994 4.365 3.728 5.252 7.642 10.372 12.234 16.566h-90.207l-.153 1.134c6.582 2.444 12.387 6.339 20.175 6.183 23.179-.463 46.374-.087 69.561-.245 3.754-.026 6.054 1.177 7.725 4.48 2.979 5.887 6.211 11.646 9.711 18.154-2.304.15-3.753.325-5.203.326-22.415.017-44.831-.042-67.246.074-3.19.016-5.54-.802-7.705-3.211-3.093-3.441-6.561-6.545-10.119-10.008M267.626 255.455a972 972 0 0 1-7.18.028c2.056-26.604 4.319-53.217 12.215-78.952 1.17-3.813 2.458-5.484 6.241-2.773 3.757 2.69 8.105 4.741 11.346 7.934 22.076 21.743 42.878 44.52 56.347 73.308-3.623.356-7.36.406-11.542.092-1.222-4.579-3.365-6.359-8.021-6.284-17.697.286-35.402.122-53.104.126h-6.302zm2.176-30.951h44.834l.519-1.678c-1.826-.906-3.637-2.562-5.479-2.597-12.466-.234-24.937-.104-37.407-.144-2.831-.009-4.108.992-2.467 4.419m10.378-31.312c-3.285-.223-6.209-.007-5.651 4.577h16.788c-2.211-5.078-6.298-4.716-11.137-4.577m-41.043 62.082c-3.21.24-6.22.195-9.566-.301-.214-2.054-.093-3.657.08-5.95-11.47 0-22.329-.006-33.188.003-5.917.004-6.716.761-7.574 7.07-1.888.101-3.775.202-6.063.302 4.551-9.736 8.81-19.906 14.604-29.11 10.304-16.372 21.983-31.76 37.616-43.656 7.217-5.492 15.096-9.592 23.847-11.977 1.13-.308 2.333-.345 4.833-.691-10.43 27.968-18.906 55.583-24.589 84.31m-25.72-36.778c-4.442-.439-5.459 2.888-7.32 6.624 9.882 0 19.096-.135 28.302.061 4.188.089 5.338-1.767 4.777-6.598-8.393 0-16.684 0-25.759-.087m33.855-22.914c-1.112-.66-2.178-1.777-3.343-1.89-2.903-.28-5.86.032-8.779-.147-3.761-.229-5.839 1.749-7.932 5.507 6.203 0 11.685.126 17.15-.12.95-.043 1.829-1.662 2.904-3.35m96.491-154.518c17.922 7.326 34.473 16.35 49.706 28.527-30.671-2.027-59.888 3.402-88.579 15.8.855-4.673 2.395-7.566 6.408-8.806 5.86-1.811 11.674-3.77 17.472-6.488h-16.478c5.867-11.505 11.161-22.041 16.71-32.442.395-.74 2.807-.966 4.029-.597 3.534 1.07 6.939 2.564 10.732 4.006"
|
||||
id="path7"
|
||||
style="fill:#ff7f2a;fill-opacity:1" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="m 130,278.4 c 69.2,16 30.4,65.6 30.4,65.6 0,0 -14.8,-92.4 28.8,-46.4 43.6,46 -59.2,-19.2 -59.2,-19.2 z"
|
||||
id="path8" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="m 76.08469,213.54625 c 17.819091,7.91959 0.282842,24.32447 22.061731,7.91959 21.778889,-16.40487 53.174429,-48.3661 21.778889,-16.40487 -31.395541,31.96122 -43.84062,8.48528 -43.84062,8.48528 z"
|
||||
id="path9" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="m 310.4,292.8 c 36,20.8 16,50.4 40,18.8 24,-31.6 46.8,-57.2 14.8,-33.6 -32,23.6 -54.8,14.8 -54.8,14.8 z"
|
||||
id="path10" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="m 380.8,197.2 c 41.6,30.4 18.4,62.8 42,30.4 23.6,-32.4 10,-68.8 23.6,-32.4 13.6,36.4 58,64.4 13.6,36.4 -44.4,-28 -79.2,-34.4 -79.2,-34.4 z"
|
||||
id="path11" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="M 99.6,145.2 C 146,120.4 170.4,80.8 146,120.4 121.6,160 121.2,187.6 120.4,159.6 119.6,131.6 99.6,145.2 99.6,145.2 Z"
|
||||
id="path12" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="m 166.4,395.2 c 36.4,-34.4 26.8,-68.4 35.2,-32.8 8.4,35.6 -36,4.8 -36,4.8 z"
|
||||
id="path13" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="M 325.6,419.2 C 390,378.4 402,310 388.8,379.6 c -13.2,69.6 7.6,39.6 -15.6,67.6 -23.2,28 81.6,-113.2 50,-90.8 -31.6,22.4 -97.6,62.8 -97.6,62.8 z"
|
||||
id="path14" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="m 298.11622,232.77955 c 9.33381,30.82986 27.43574,16.68772 9.05097,29.41564 -18.38478,12.72793 -23.19311,44.12347 -17.53625,11.59656 5.65685,-32.52692 8.48528,-41.0122 8.48528,-41.0122 z"
|
||||
id="path15" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="M 54.305801,291.32799 C 110.5915,257.10403 141.42136,225.1428 108.89444,258.51824 76.367532,291.89368 96.166522,307.73287 78.913117,291.04515 61.659711,274.35743 54.022958,289.06525 54.022958,289.06525 l 53.174432,-31.1127 z"
|
||||
id="path16" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 13 KiB |
110
dist/icon_variations/halloween2025_named.svg
vendored
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
dist/qt_themes/default/icons/256x256/eden.png
vendored
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 27 KiB |
BIN
dist/qt_themes/default/icons/256x256/eden_named.png
vendored
|
Before Width: | Height: | Size: 2.7 MiB After Width: | Height: | Size: 38 KiB |
BIN
dist/yuzu.bmp
vendored
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 256 KiB |
@@ -1,5 +1,23 @@
|
||||
# Debug Guidelines
|
||||
|
||||
## Issue reports
|
||||
|
||||
When reporting issues or finding bugs, we often need backtraces, debug logs, or both in order to track down the issue.
|
||||
|
||||
### Graphics Debugging
|
||||
|
||||
If your bug is related to a graphical issue--e.g. mismatched colors, vertex explosions, flickering, etc.--then you are required to include graphical debugging logs in your issue reports.
|
||||
|
||||
Graphics Debugging is found in General -> Debug on desktop, and Advanced Settings -> Debug on Android. Android users are all set; however, desktop users may need to install the Vulkan Validation Layers:
|
||||
- Windows: Install the [Vulkan SDK](https://vulkan.lunarg.com/sdk/home)
|
||||
- Linux, BSD, etc: Install `vulkan-validation-layers`, `vulkan-layers`, or similar from your package manager. It should be located in e.g. `/usr/lib64/libVkLayer_khronos_validation.so`
|
||||
|
||||
Once Graphics Debugging is enabled, run the problematic game again and continue. Note that the game may run extremely slow on weak hardware.
|
||||
|
||||
### Debug Logs
|
||||
|
||||
Debug logs can be found in General -> Debug -> Open Log Location on desktop, and Share Debug Logs on Android. This MUST be included in all bug reports, except for certain UI bugs--but we still highly recommend them even for UI bugs.
|
||||
|
||||
## Debugging (host code)
|
||||
|
||||
Ignoring SIGSEGV when debugging in host:
|
||||
@@ -47,10 +65,10 @@ Renderdoc is a free, cross platform, multi-graphics API debugger. It is an inval
|
||||
|
||||
Before using renderdoc to diagnose issues, it is always good to make sure there are no validation errors. Any errors means the behavior of the application is undefined. That said, renderdoc can help debug validation errors if you do have them.
|
||||
|
||||
When debugging a black screen, there are many ways the application could have setup Vulkan wrong.
|
||||
When debugging a black screen, there are many ways the application could have setup Vulkan wrong.
|
||||
Here is a short checklist of items to look at to make sure are appropriate:
|
||||
* Draw call counts are correct (aka not zero, or if rendering many triangles, not 3)
|
||||
* Vertex buffers are bound
|
||||
* Vertex buffers are bound
|
||||
* vertex attributes are correct - Make sure the size & offset of each attribute matches what should it should be
|
||||
* Any bound push constants and descriptors have the right data - including:
|
||||
* Matrices have correct values - double check the model, view, & projection matrices are uploaded correctly
|
||||
@@ -63,6 +81,6 @@ Here is a short checklist of items to look at to make sure are appropriate:
|
||||
* Blend state is correct
|
||||
* Depth state is correct - typically enabled with Function set to Less than or Equal
|
||||
* Swapchain images are bound when rendering to the swapchain
|
||||
* Image being rendered to is the same as the one being presented when rendering to the swapchain
|
||||
* Image being rendered to is the same as the one being presented when rendering to the swapchain
|
||||
|
||||
Alternatively, a [RenderDoc Extension](https://github.com/baldurk/renderdoc-contrib/tree/main/baldurk/whereismydraw) ([Archive](https://web.archive.org/web/20250000000000*/https://github.com/baldurk/renderdoc-contrib/tree/main/baldurk/whereismydraw)) exists which automates doing a lot of these manual steps.
|
||||
|
||||
13
docs/Deps.md
@@ -72,9 +72,6 @@ Certain other dependencies will be fetched by CPM regardless. System packages *c
|
||||
|
||||
On amd64:
|
||||
* [xbyak](https://github.com/herumi/xbyak) - 7.22 or earlier is recommended
|
||||
* [zycore](https://github.com/zyantific/zycore-c)
|
||||
* [zydis](https://github.com/zyantific/zydis) 4+
|
||||
* Note: zydis and zycore-c MUST match. Using one as a system dependency and the other as a bundled dependency WILL break things
|
||||
|
||||
On aarch64 OR if `DYNARMIC_TESTS` is on:
|
||||
* [oaknut](https://github.com/merryhime/oaknut) 2.0.1+
|
||||
@@ -94,7 +91,7 @@ Click on the arrows to expand.
|
||||
<summary>Arch Linux</summary>
|
||||
|
||||
```sh
|
||||
sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glslang libzip lz4 mbedtls ninja nlohmann-json openssl opus qt6-base qt6-multimedia sdl2 zlib zstd zip unzip zydis zycore vulkan-headers vulkan-utility-libraries libusb spirv-tools spirv-headers
|
||||
sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glslang libzip lz4 mbedtls ninja nlohmann-json openssl opus qt6-base qt6-multimedia sdl2 zlib zstd zip unzip vulkan-headers vulkan-utility-libraries libusb spirv-tools spirv-headers
|
||||
```
|
||||
|
||||
* Building with QT Web Engine requires `qt6-webengine` as well.
|
||||
@@ -106,7 +103,7 @@ sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glsl
|
||||
<summary>Ubuntu, Debian, Mint Linux</summary>
|
||||
|
||||
```sh
|
||||
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev libzydis-dev zydis-tools libzycore-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev libboost-dev libboost-fiber-dev libboost-context-dev libsdl2-dev libopus-dev libasound2t64 vulkan-utility-libraries-dev
|
||||
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev libboost-dev libboost-fiber-dev libboost-context-dev libsdl2-dev libopus-dev libasound2t64 vulkan-utility-libraries-dev
|
||||
```
|
||||
|
||||
* Ubuntu 22.04, Linux Mint 20, or Debian 12 or later is required.
|
||||
@@ -189,7 +186,7 @@ brew install molten-vk vulkan-loader
|
||||
<details>
|
||||
<summary>FreeBSD</summary>
|
||||
|
||||
As root run: `pkg install devel/cmake devel/sdl20 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib devel/jwt-cpp devel/unordered-dense devel/zydis`
|
||||
As root run: `pkg install devel/cmake devel/sdl20 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib devel/jwt-cpp devel/unordered-dense`
|
||||
|
||||
If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
|
||||
|
||||
@@ -237,7 +234,7 @@ Then install the libraries: `sudo pkg install qt6 boost glslang libzip library/l
|
||||
* Download and install all dependencies:
|
||||
```
|
||||
BASE="git make autoconf libtool automake-wrapper jq patch"
|
||||
MINGW="SDL2 cmake python-pip qt6-base toolchain ffmpeg boost catch fmt lz4 nlohmann-json openssl zlib zstd enet opus mbedtls vulkan-devel libusb vulkan-memory-allocator unordered_dense zydis clang ccache"
|
||||
MINGW="SDL2 cmake python-pip qt6-base toolchain ffmpeg boost catch fmt lz4 nlohmann-json openssl zlib zstd enet opus mbedtls vulkan-devel libusb vulkan-memory-allocator unordered_dense clang ccache"
|
||||
|
||||
packages="$BASE"
|
||||
for pkg in $MINGW; do
|
||||
@@ -260,7 +257,7 @@ pacman -Syu --needed --noconfirm $packages
|
||||
<summary>HaikuOS</summary>
|
||||
|
||||
```sh
|
||||
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.89_devel vulkan_devel qt6_base_devel libsdl2_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt6_devel qt6_5compat_devel zydis_devel libusb1_devel libz_devel glslang mbedtls3
|
||||
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.89_devel vulkan_devel qt6_base_devel libsdl2_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt6_devel qt6_5compat_devel libusb1_devel libz_devel mbedtls3_devel glslang
|
||||
```
|
||||
|
||||
[Caveats](./Caveats.md#haikuos).
|
||||
|
||||
@@ -10,4 +10,4 @@ This contains documentation created by developers. This contains build instructi
|
||||
- **[Debug Guidelines](./Debug.md)**
|
||||
- **[CPM - CMake Package Manager](CPMUtil.md)**
|
||||
- **[Platform-Specific Caveats](Caveats.md)**
|
||||
- **[User Handbook](User.md)**
|
||||
- **[User Handbook](./user)**
|
||||
|
||||
12
docs/User.md
@@ -1,12 +0,0 @@
|
||||
# User Handbook
|
||||
|
||||
The "FAQ".
|
||||
|
||||
This handbook is primarily aimed at the end-user - baking useful knowledge for enhancing their emulation experience.
|
||||
|
||||
- **[The Basics](user/Basics.md)**
|
||||
- **[Audio](user/Audio.md)**
|
||||
- **[Graphics](user/Graphics.md)**
|
||||
- **[Platforms and Architectures](user/Architectures.md)**
|
||||
- **[Testing](user/Testing.md)**
|
||||
- **[Data, savefiles and storage](user/Storage.md)**
|
||||
31
docs/user/Orphaned.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Orphaned Profiles
|
||||
|
||||
A bug present in earlier versions of Eden and Yuzu caused some profiles to be read from the incorrect location if your NAND directory was set to anything other than the default. This bug was fixed in Eden v0.0.4-rc1, but it can be destructive if you're not careful.
|
||||
|
||||
## What are they?
|
||||
|
||||
Orphaned profiles refer to emulated user profiles that may or may not contain valid save data, but are not referenced by the internal profile map. This means the save data is effectively inaccessible, and should be fixed in order to access your save data.
|
||||
|
||||
## How do I fix it?
|
||||
|
||||
There are lots of different cases of varying complexity.
|
||||
|
||||
Remember to ALWAYS back up your saves!
|
||||
|
||||
### Simple Copy
|
||||
|
||||
Sometimes, a simple copying is all you need. For example, if the orphaned profile folder contains game saves, BUT the good profile is completely empty, then you can simply remove the empty folder and rename the orphaned profile to the same name as the good one.
|
||||
|
||||
### Combination
|
||||
|
||||
In more extreme cases, game saves can be strewn all throughout different profiles. In this case, you must look at each profile individually.
|
||||
|
||||
Typically, one folder will clearly have more recent/numerous save data, in which case you can remove all the other profile folders and follow the same procedure as the simple copy.
|
||||
|
||||
If multiple profile folders contain valid data, the recommended approach is to copy the contents of one folder into the other. There are likely to be file conflicts, the resolution of which is up to you.
|
||||
|
||||
An alternate method for dealing with multiple valid profiles is to go into System -> Profiles, and create a new profile. From there, you can copy the contents of each previously-orphaned profile into a new profile.
|
||||
|
||||
### Edge Cases
|
||||
|
||||
There are way too many edge cases to cover here, but in general, make backups! You can never go wrong if you always have a backup of your saves.
|
||||
13
docs/user/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# User Handbook
|
||||
|
||||
The "FAQ".
|
||||
|
||||
This handbook is primarily aimed at the end-user - baking useful knowledge for enhancing their emulation experience.
|
||||
|
||||
- **[The Basics](Basics.md)**
|
||||
- **[Audio](Audio.md)**
|
||||
- **[Graphics](Graphics.md)**
|
||||
- **[Platforms and Architectures](Architectures.md)**
|
||||
- **[Testing](Testing.md)**
|
||||
- **[Data, savefiles and storage](Storage.md)**
|
||||
- **[Orphaned Profiles](Orphaned.md)**
|
||||
@@ -27,6 +27,8 @@ When you report your results:
|
||||
2. "Tested on based master — issue already present. Good result for PR, not a regression."
|
||||
```
|
||||
|
||||
This approach helps maintain clarity and accountability in the testing process and ensures regressions are caught and addressed efficiently. If the behavior seems normal for a certain game/feature then it may not be always required to check against the based master.
|
||||
This approach helps maintain clarity and accountability in the testing process and ensures regressions are caught and addressed efficiently. If the behavior seems normal for a certain game/feature then it may not be always required to check against the based master.
|
||||
|
||||
If a master build for the PR' based master does not exist. It will be helpful to just test past and future builds nearby. That would help with gathering more information about the problem.
|
||||
|
||||
**Always include [debugging info](../Debug.md) as needed**.
|
||||
9
externals/CMakeLists.txt
vendored
@@ -219,7 +219,7 @@ if (ENABLE_WEB_SERVICE OR ENABLE_UPDATE_CHECKER)
|
||||
endif()
|
||||
|
||||
# cpp-jwt
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
if (ENABLE_WEB_SERVICE OR ENABLE_UPDATE_CHECKER)
|
||||
AddJsonPackage(cpp-jwt)
|
||||
endif()
|
||||
|
||||
@@ -399,10 +399,3 @@ if (ANDROID)
|
||||
|
||||
add_library(oboe::oboe ALIAS oboe)
|
||||
endif()
|
||||
|
||||
# sse2neon
|
||||
if (ARCHITECTURE_arm64 AND NOT TARGET sse2neon)
|
||||
AddJsonPackage(sse2neon)
|
||||
add_library(sse2neon INTERFACE)
|
||||
target_include_directories(sse2neon INTERFACE ${sse2neon_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
9
externals/cpmfile.json
vendored
@@ -213,14 +213,5 @@
|
||||
"key": "steamdeck",
|
||||
"bundled": true,
|
||||
"skip_updates": "true"
|
||||
},
|
||||
"sse2neon": {
|
||||
"repo": "DLTcollab/sse2neon",
|
||||
"sha": "66267b52fd",
|
||||
"hash": "3aed8676e1b8c428acb076464663e3968a721457b08710a7c5f8df2fbdaa5601053c1606169a55e987e7a58dd17e3cc3b7fbf953aa891c5ac5f8ce2941862e4b",
|
||||
"download_only": "true",
|
||||
"patches": [
|
||||
"0001-Add-support-for-clang-cl-on-Windows-633.patch"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ pkgs.mkShellNoCC {
|
||||
openssl boost fmt nlohmann_json lz4 zlib zstd
|
||||
enet libopus vulkan-headers vulkan-utility-libraries
|
||||
spirv-tools spirv-headers simpleini vulkan-memory-allocator
|
||||
vulkan-loader unzip mbedtls zydis glslang python3 httplib
|
||||
vulkan-loader unzip mbedtls glslang python3 httplib
|
||||
cpp-jwt ffmpeg-headless libusb1 cubeb
|
||||
qt6.full # eden
|
||||
SDL2 # eden-cli
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -20,18 +23,22 @@ class AddonAdapter(val addonViewModel: AddonViewModel) :
|
||||
inner class AddonViewHolder(val binding: ListItemAddonBinding) :
|
||||
AbstractViewHolder<Patch>(binding) {
|
||||
override fun bind(model: Patch) {
|
||||
binding.root.setOnClickListener {
|
||||
binding.addonCheckbox.isChecked = !binding.addonCheckbox.isChecked
|
||||
binding.addonCard.setOnClickListener {
|
||||
binding.addonSwitch.performClick()
|
||||
}
|
||||
binding.title.text = model.name
|
||||
binding.version.text = model.version
|
||||
binding.addonCheckbox.setOnCheckedChangeListener { _, checked ->
|
||||
binding.addonSwitch.isChecked = model.enabled
|
||||
|
||||
binding.addonSwitch.setOnCheckedChangeListener { _, checked ->
|
||||
model.enabled = checked
|
||||
}
|
||||
binding.addonCheckbox.isChecked = model.enabled
|
||||
binding.buttonDelete.setOnClickListener {
|
||||
|
||||
val deleteAction = {
|
||||
addonViewModel.setAddonToDelete(model)
|
||||
}
|
||||
binding.deleteCard.setOnClickListener { deleteAction() }
|
||||
binding.buttonDelete.setOnClickListener { deleteAction() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 74 KiB |
@@ -4,7 +4,8 @@
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="16dp">
|
||||
android:padding="16dp"
|
||||
android:background="?attr/colorSurface">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_title"
|
||||
@@ -13,7 +14,8 @@
|
||||
android:text="@string/chat"
|
||||
android:textAppearance="?attr/textAppearanceHeadline6"
|
||||
android:gravity="center"
|
||||
android:layout_marginBottom="16dp" />
|
||||
android:layout_marginBottom="16dp"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/chat_recycler_view"
|
||||
@@ -39,7 +41,9 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text"
|
||||
android:imeOptions="actionSend" />
|
||||
android:imeOptions="actionSend"
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
android:textColorHint="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
@@ -50,6 +54,7 @@
|
||||
android:layout_gravity="bottom"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_send"
|
||||
android:contentDescription="@string/send_message" />
|
||||
android:contentDescription="@string/send_message"
|
||||
app:tint="?attr/colorPrimary" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -3,13 +3,14 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:background="?attr/colorSurface"
|
||||
android:elevation="0dp">
|
||||
|
||||
<LinearLayout
|
||||
@@ -37,7 +38,8 @@
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:text="@string/multiplayer_room_browser"
|
||||
android:textAppearance="@style/TextAppearance.Material3.TitleLarge" />
|
||||
android:textAppearance="@style/TextAppearance.Material3.TitleLarge"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="48dp"
|
||||
@@ -75,7 +77,8 @@
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
app:cardCornerRadius="24dp">
|
||||
app:cardCornerRadius="24dp"
|
||||
app:cardBackgroundColor="?attr/colorSurfaceVariant">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/search_container"
|
||||
@@ -91,6 +94,7 @@
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="@drawable/ic_search"
|
||||
android:contentDescription="@string/home_search"
|
||||
app:tint="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
<EditText
|
||||
@@ -101,7 +105,9 @@
|
||||
android:hint="@string/multiplayer_search_public_lobbies"
|
||||
android:imeOptions="flagNoFullscreen"
|
||||
android:inputType="text"
|
||||
android:maxLines="1" />
|
||||
android:maxLines="1"
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
android:autofillHints="" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -113,6 +119,7 @@
|
||||
android:layout_marginEnd="48dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_clear"
|
||||
android:contentDescription="@string/clear"
|
||||
android:visibility="invisible"
|
||||
app:tint="?attr/colorOnSurfaceVariant"
|
||||
tools:visibility="visible" />
|
||||
@@ -154,19 +161,33 @@
|
||||
android:id="@+id/chip_hide_empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:checkable="true"
|
||||
android:checked="false"
|
||||
android:text="@string/multiplayer_hide_empty_rooms"
|
||||
app:chipCornerRadius="16dp" />
|
||||
app:chipCornerRadius="16dp"
|
||||
app:chipIconTint="?attr/colorOnSurface"
|
||||
app:chipIconSize="18dp"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingBottom="6dp" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip_hide_full"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:checkable="true"
|
||||
android:checked="false"
|
||||
android:text="@string/multiplayer_hide_full_rooms"
|
||||
app:chipCornerRadius="16dp" />
|
||||
app:chipCornerRadius="16dp"
|
||||
app:chipIconTint="?attr/colorOnSurface"
|
||||
app:chipIconSize="18dp"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingBottom="6dp" />
|
||||
|
||||
</LinearLayout>
|
||||
</HorizontalScrollView>
|
||||
@@ -198,6 +219,7 @@
|
||||
android:layout_height="72dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:src="@drawable/ic_refresh"
|
||||
android:contentDescription="@string/refresh"
|
||||
android:alpha="0.5"
|
||||
app:tint="?attr/colorOnSurface" />
|
||||
|
||||
@@ -205,14 +227,16 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/multiplayer_no_rooms_found"
|
||||
android:textAppearance="@style/TextAppearance.Material3.TitleMedium" />
|
||||
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/multiplayer_tap_refresh_to_check_again"
|
||||
android:textAppearance="@style/TextAppearance.Material3.BodyMedium" />
|
||||
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/empty_refresh_button"
|
||||
@@ -220,7 +244,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/refresh"
|
||||
app:icon="@drawable/ic_refresh" />
|
||||
app:icon="@drawable/ic_refresh"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton" />
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -3,7 +3,8 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/theme_dialog_background">
|
||||
|
||||
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
|
||||
android:id="@+id/drag_handle"
|
||||
@@ -33,6 +34,7 @@
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:src="@drawable/ic_network"
|
||||
android:contentDescription="@string/multiplayer"
|
||||
app:tint="?attr/colorPrimary" />
|
||||
|
||||
<LinearLayout
|
||||
@@ -47,13 +49,18 @@
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_lobby_browser"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton"
|
||||
style="@style/Widget.Material3.Button.TonalButton"
|
||||
android:layout_width="175dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minHeight="56dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/multiplayer_public_room"
|
||||
app:cornerRadius="16dp"
|
||||
app:icon="@drawable/ic_search" />
|
||||
app:icon="@drawable/ic_search"
|
||||
app:iconPadding="12dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="20dp"
|
||||
@@ -74,12 +81,16 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minHeight="56dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:text="@string/multiplayer_join_room"
|
||||
app:cornerRadius="16dp"
|
||||
app:icon="@drawable/ic_install" />
|
||||
app:icon="@drawable/ic_install"
|
||||
app:iconPadding="12dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="16dp"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
@@ -88,9 +99,13 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minHeight="56dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:text="@string/multiplayer_create_room"
|
||||
app:cornerRadius="16dp"
|
||||
app:icon="@drawable/ic_add" />
|
||||
app:icon="@drawable/ic_add"
|
||||
app:iconPadding="12dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/theme_dialog_background">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/theme_dialog_background">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
@@ -149,6 +150,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@android:string/ok"
|
||||
android:layout_gravity="center" />
|
||||
android:layout_gravity="center"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
@@ -8,7 +8,7 @@
|
||||
android:layout_marginBottom="24dp"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:backgroundTint="?attr/colorSurfaceVariant"
|
||||
app:cardBackgroundColor="?attr/colorSurfaceVariant"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
android:textAlignment="viewStart"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
tools:text="Room Name" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
@@ -56,6 +57,7 @@
|
||||
android:layout_marginTop="5dp"
|
||||
android:textAlignment="viewStart"
|
||||
android:textSize="14sp"
|
||||
android:textColor="?attr/colorOnSurfaceVariant"
|
||||
tools:text="Hosted by: Owner" />
|
||||
|
||||
<LinearLayout
|
||||
@@ -70,7 +72,8 @@
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:contentDescription="@string/multiplayer_game"
|
||||
android:src="@drawable/ic_controller" />
|
||||
android:src="@drawable/ic_controller"
|
||||
app:tint="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/game_name"
|
||||
@@ -81,6 +84,7 @@
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textStyle="bold"
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
tools:text="Game Name" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -98,7 +102,7 @@
|
||||
android:layout_height="16dp"
|
||||
android:src="@drawable/ic_user"
|
||||
android:contentDescription="@string/multiplayer_player_count"
|
||||
app:tint="?attr/colorAccent" />
|
||||
app:tint="?attr/colorPrimary" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/player_count"
|
||||
@@ -106,7 +110,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:textColor="?attr/colorAccent"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
tools:text="2/4" />
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -2,68 +2,109 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/addon_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:focusable="false"
|
||||
android:paddingHorizontal="20dp"
|
||||
android:paddingVertical="16dp">
|
||||
android:padding="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/text_container"
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/addon_card"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/addon_checkbox"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextAppearance.Material3.HeadlineMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="viewStart"
|
||||
android:textSize="17sp"
|
||||
app:lineHeight="28dp"
|
||||
tools:text="1440p Resolution" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/version"
|
||||
style="@style/TextAppearance.Material3.BodySmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/spacing_small"
|
||||
android:textAlignment="viewStart"
|
||||
tools:text="1.0.0" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.checkbox.MaterialCheckBox
|
||||
android:id="@+id/addon_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardElevation="2dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:layout_constraintTop_toTopOf="@+id/text_container"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/text_container"
|
||||
app:layout_constraintEnd_toStartOf="@+id/button_delete" />
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/delete_card"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_delete"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:contentDescription="@string/delete"
|
||||
android:tooltipText="@string/delete"
|
||||
app:icon="@drawable/ic_delete"
|
||||
app:iconTint="?attr/colorControlNormal"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextAppearance.Material3.HeadlineSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="viewStart"
|
||||
android:textSize="16sp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
app:lineHeight="20dp"
|
||||
tools:text="1440p Resolution"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/addon_switch"
|
||||
android:layout_marginEnd="8dp" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/version"
|
||||
style="@style/TextAppearance.Material3.BodySmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:textAlignment="viewStart"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
tools:text="1.0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title"
|
||||
app:layout_constraintEnd_toStartOf="@+id/addon_switch" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/addon_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusable="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginEnd="4dp" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/delete_card"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:cardCornerRadius="10dp"
|
||||
app:cardElevation="2dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||
app:layout_constraintStart_toEndOf="@id/addon_card"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/addon_checkbox"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/addon_checkbox" />
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:foregroundGravity="center">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/button_delete"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@null"
|
||||
android:src="@drawable/ic_delete"
|
||||
app:tint="@color/eden_border_gradient_end"
|
||||
android:contentDescription="@string/delete" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -374,9 +374,6 @@
|
||||
<string name="firmware_uninstalling">إلغاء تثبيت الفريموير</string>
|
||||
<string name="firmware_uninstalled_success">تم إزالة الفريموير بنجاح</string>
|
||||
|
||||
<string name="error_firmware_missing">الفريموير مطلوب لتشغيل بعض الألعاب واستخدام التطبيقات. يعمل عدن فقط مع الفريموير 19.0.1 أو الأقدم.</string>
|
||||
<string name="error_firmware_corrupted">الفريموير موجود ولكن لا يمكن قراءته. تحقق من مفاتيح التشفير وأعد نسخ الفريموير إذا لزم الأمر.</string>
|
||||
<string name="error_firmware_too_new">الفريموير جديد جداً أو لا يمكن قراءته. يعمل عدن فقط مع الفريموير 19.0.1 أو الأقدم.</string>
|
||||
|
||||
<string name="keys_failed">فشل تثبيت المفاتيح</string>
|
||||
<string name="keys_install_success">تم تثبيت المفاتيح بنجاح</string>
|
||||
|
||||
@@ -322,9 +322,6 @@
|
||||
<string name="firmware_uninstalling">جاري إزالة البرنامج الثابت</string>
|
||||
<string name="firmware_uninstalled_success">تم إزالة البرنامج الثابت بنجاح</string>
|
||||
|
||||
<string name="error_firmware_missing">فریموێر پێویستە بۆ کارپێکردنی هەندێک یاری و بەکارهێنانی بەرنامەکان. ئێدین تەنها لەگەڵ فریموێری 19.0.1 یان کۆنتر کار دەکات.</string>
|
||||
<string name="error_firmware_corrupted">فریموێر هەیە بەڵام ناتوانرێت بخوێنرێتەوە. پشکنین بکە بۆ کلیلی شیکردنەوە و دووبارە فریموێرەکە دامپ بکە ئەگەر پێویست بوو.</string>
|
||||
<string name="error_firmware_too_new">فریموێر زۆر نوێ یان ناتوانرێت بخوێنرێتەوە. ئێدین تەنها لەگەڵ فریموێری 19.0.1 یان کۆنتر کار دەکات.</string>
|
||||
|
||||
<string name="keys_failed">سەرکەوتوو نەبوو لە ناساندنی کلیلی</string>
|
||||
<string name="keys_install_success">کلیلەکان بە سەرکەوتوویی ناسێندران</string>
|
||||
|
||||
@@ -301,9 +301,6 @@
|
||||
<string name="firmware_uninstalling">Odstraňování firmwaru</string>
|
||||
<string name="firmware_uninstalled_success">Firmware byl úspěšně odinstalován</string>
|
||||
|
||||
<string name="error_firmware_missing">Firmware je vyžadován pro spuštění některých her a aplikací. Eden funguje pouze s firmwarem 19.0.1 nebo starším.</string>
|
||||
<string name="error_firmware_corrupted">Firmware byl nahlášen jako přítomný, ale nelze jej přečíst. Zkontrolujte šifrovací klíče a v případě potřeby firmware převezměte znovu.</string>
|
||||
<string name="error_firmware_too_new">Firmware je příliš nový nebo nelze přečíst. Eden funguje pouze s firmwarem 19.0.1 nebo starším.</string>
|
||||
|
||||
<string name="keys_failed">Selhání instalace klíčů</string>
|
||||
<string name="keys_install_success">Klíče úspěšně nainstalovány</string>
|
||||
|
||||
@@ -353,9 +353,6 @@ Wirklich fortfahren?</string>
|
||||
<string name="firmware_uninstalling">Firmware wird deinstalliert...</string>
|
||||
<string name="firmware_uninstalled_success">Firmware erfolgreich deinstalliert</string>
|
||||
|
||||
<string name="error_firmware_missing">Firmware wird benötigt, um bestimmte Spiele und Applikationen zu nutzen. Eden funktioniert nur mit Firmware 19.0.1 oder älter.</string>
|
||||
<string name="error_firmware_corrupted">Firmware wurde als vorhanden gemeldet, konnte aber nicht gelesen werden. Überprüfen Sie die Entschlüsselungsschlüssel und dumpen Sie die Firmware bei Bedarf neu.</string>
|
||||
<string name="error_firmware_too_new">Firmware ist zu neu oder konnte nicht gelesen werden. Eden funktioniert nur mit Firmware 19.0.1 oder älter.</string>
|
||||
|
||||
<string name="keys_failed">Schlüsselinstallation fehlgeschlagen</string>
|
||||
<string name="keys_install_success">Schlüssel erfolgreich installiert</string>
|
||||
|
||||
@@ -368,9 +368,6 @@
|
||||
<string name="firmware_uninstalling">Desinstalando firmware...</string>
|
||||
<string name="firmware_uninstalled_success">Firmware desinstalado correctamente</string>
|
||||
|
||||
<string name="error_firmware_missing">Se requiere firmware para ejecutar ciertos juegos y aplicaciones. Eden solo funciona con firmware 19.0.1 o anterior.</string>
|
||||
<string name="error_firmware_corrupted">El firmware está presente pero no se pudo leer. Verifique las claves de descifrado y vuelva a volcar el firmware si es necesario.</string>
|
||||
<string name="error_firmware_too_new">El firmware es demasiado nuevo o no se pudo leer. Eden solo funciona con firmware 19.0.1 o anterior.</string>
|
||||
|
||||
<string name="keys_failed">Error al instalar claves</string>
|
||||
<string name="keys_install_success">Claves instaladas correctamente</string>
|
||||
|
||||
@@ -387,9 +387,6 @@
|
||||
<string name="verify_installed_content_description">تمام محتوای نصب شده را از نظر خرابی بررسی میکند</string>
|
||||
<string name="keys_missing">کلیدهای رمزگذاری وجود ندارند</string>
|
||||
<string name="keys_missing_description">ثابتافزار و بازیهای فروشگاهی قابل رمزگشایی نیستند</string>
|
||||
<string name="error_firmware_missing">برای اجرای برخی بازیها و برنامهها نیاز به فیرمور است. ادن فقط با فیرمور 19.0.1 یا قدیمیتر کار میکند.</string>
|
||||
<string name="error_firmware_corrupted">فیرمور موجود است اما قابل خواندن نیست. کلیدهای رمزگشایی را بررسی کنید و در صورت نیاز فیرمور را دوباره دامپ کنید.</string>
|
||||
<string name="error_firmware_too_new">فیرمور خیلی جدید است یا قابل خواندن نیست. ادن فقط با فیرمور 19.0.1 یا قدیمیتر کار میکند.</string>
|
||||
<string name="keys_failed">خطا در نصب کلیدها</string>
|
||||
<string name="keys_install_success">کلیدها با موفقیت نصب شدند</string>
|
||||
<string name="error_keys_copy_failed">یک یا چند کلید با خطا در کپی مواجه شد.</string>
|
||||
|
||||
@@ -368,9 +368,6 @@
|
||||
<string name="firmware_uninstalling">Désinstallation du firmware...</string>
|
||||
<string name="firmware_uninstalled_success">Firmware désinstallé avec succès</string>
|
||||
|
||||
<string name="error_firmware_missing">Le firmware est requis pour exécuter certains jeux et applications. Eden ne fonctionne qu\'avec le firmware 19.0.1 ou antérieur.</string>
|
||||
<string name="error_firmware_corrupted">Firmware présent mais illisible. Vérifiez les clés de décryptage et redumpz le firmware si nécessaire.</string>
|
||||
<string name="error_firmware_too_new">Firmware trop récent ou illisible. Eden ne supporte que le firmware 19.0.1 ou antérieur.</string>
|
||||
|
||||
<string name="keys_failed">Échec de l\'installation des clés</string>
|
||||
<string name="keys_install_success">Clés installées avec succès</string>
|
||||
|
||||
@@ -334,9 +334,6 @@
|
||||
<string name="firmware_uninstalling">מסיר קושחה...</string>
|
||||
<string name="firmware_uninstalled_success">הקושחה הוסרה בהצלחה</string>
|
||||
|
||||
<string name="error_firmware_missing">נדרש קושחה להפעלת משחקים ויישומים מסוימים. עדן עובד רק עם קושחה 19.0.1 או ישנה יותר.</string>
|
||||
<string name="error_firmware_corrupted">קושחה קיימת אך לא ניתנת לקריאה. בדוק מפתחות פענוח ושמור קושחה מחדש אם needed.</string>
|
||||
<string name="error_firmware_too_new">קושחה חדשה מדי או לא ניתנת לקריאה. עדן תומך רק בקושחה 19.0.1 או ישנה יותר.</string>
|
||||
|
||||
<string name="keys_failed">התקנת מפתחות נכשלה</string>
|
||||
<string name="keys_install_success">מפתחות הותקנו בהצלחה</string>
|
||||
|
||||
@@ -331,9 +331,6 @@
|
||||
<string name="firmware_uninstalling">Firmware eltávolítása...</string>
|
||||
<string name="firmware_uninstalled_success">A firmware sikeresen eltávolítva</string>
|
||||
|
||||
<string name="error_firmware_missing">A firmware szükséges egyes játékok és alkalmazások futtatásához. Az Eden csak 19.0.1 vagy régebbi firmware-ekkel működik.</string>
|
||||
<string name="error_firmware_corrupted">A firmware jelen van, de nem olvasható. Ellenőrizze a visszafejtési kulcsokat és szükség esetén dumpolja újra a firmware-t.</string>
|
||||
<string name="error_firmware_too_new">A firmware túl új vagy nem olvasható. Az Eden csak a 19.0.1 vagy régebbi firmware-ekkel működik.</string>
|
||||
|
||||
<string name="keys_failed">A kulcsok telepítése sikertelen</string>
|
||||
<string name="keys_install_success">A kulcsok sikeresen telepítve</string>
|
||||
|
||||
@@ -364,9 +364,6 @@
|
||||
<string name="firmware_uninstalling">Mencopot firmware...</string>
|
||||
<string name="firmware_uninstalled_success">Firmware berhasil dicopot</string>
|
||||
|
||||
<string name="error_firmware_missing">Firmware diperlukan untuk menjalankan game dan aplikasi tertentu. Eden hanya bekerja dengan firmware 19.0.1 atau lebih lama.</string>
|
||||
<string name="error_firmware_corrupted">Firmware dilaporkan ada tetapi tidak dapat dibaca. Periksa kunci dekripsi dan dump ulang firmware jika diperlukan.</string>
|
||||
<string name="error_firmware_too_new">Firmware terlalu baru atau tidak dapat dibaca. Eden hanya bekerja dengan firmware 19.0.1 atau lebih lama.</string>
|
||||
|
||||
<string name="keys_failed">Gagal menginstal kunci</string>
|
||||
<string name="keys_install_success">Kunci berhasil diinstal</string>
|
||||
|
||||
@@ -360,9 +360,6 @@
|
||||
<string name="firmware_uninstalling">Disinstallazione firmware...</string>
|
||||
<string name="firmware_uninstalled_success">Firmware disinstallato con successo</string>
|
||||
|
||||
<string name="error_firmware_missing">Il firmware è richiesto per eseguire alcuni giochi e applicazioni. Eden funziona solo con firmware 19.0.1 o precedente.</string>
|
||||
<string name="error_firmware_corrupted">Il firmware è presente ma non può essere letto. Controlla le chiavi di decrittazione e ridumpa il firmware se necessario.</string>
|
||||
<string name="error_firmware_too_new">Il firmware è troppo recente o illeggibile. Eden supporta solo firmware 19.0.1 o precedenti.</string>
|
||||
|
||||
<string name="keys_failed">Installazione chiavi fallita</string>
|
||||
<string name="keys_install_success">Chiavi installate con successo</string>
|
||||
|
||||
@@ -333,9 +333,6 @@
|
||||
<string name="firmware_uninstalling">ファームウェアをアンインストール中...</string>
|
||||
<string name="firmware_uninstalled_success">ファームウェアのアンインストールが成功しました</string>
|
||||
|
||||
<string name="error_firmware_missing">一部のゲームとアプリケーションを実行するにはファームウェアが必要です。Edenは19.0.1以前のファームウェアでのみ動作します。</string>
|
||||
<string name="error_firmware_corrupted">ファームウェアは存在しますが読み取れません。復号キーを確認し、必要に応じてファームウェアを再ダンプしてください。</string>
|
||||
<string name="error_firmware_too_new">ファームウェアが新しすぎるか読み取れません。Edenは19.0.1以前のファームウェアのみに対応しています。</string>
|
||||
|
||||
<string name="keys_failed">キーのインストールに失敗</string>
|
||||
<string name="keys_install_success">キーが正常にインストールされました</string>
|
||||
|
||||
@@ -330,9 +330,6 @@
|
||||
<string name="firmware_uninstalling">펌웨어 제거 중...</string>
|
||||
<string name="firmware_uninstalled_success">펌웨어가 성공적으로 제거되었습니다</string>
|
||||
|
||||
<string name="error_firmware_missing">일부 게임 및 애플리케이션 실행을 위해 펌웨어가 필요합니다. Eden은 19.0.1 이하 버전의 펌웨어에서만 작동합니다.</string>
|
||||
<string name="error_firmware_corrupted">펌웨어가 존재하지만 읽을 수 없습니다. 복호화 키를 확인하고 필요한 경우 펌웨어를 다시 덤프하세요.</string>
|
||||
<string name="error_firmware_too_new">펌웨어가 너무 최신이거나 읽을 수 없습니다. Eden은 19.0.1 이전 버전의 펌웨어에서만 작동합니다.</string>
|
||||
|
||||
<string name="keys_failed">키 설치 실패</string>
|
||||
<string name="keys_install_success">키가 성공적으로 설치됨</string>
|
||||
|
||||
@@ -322,9 +322,6 @@
|
||||
<string name="firmware_uninstalling">Avinstallerer firmware...</string>
|
||||
<string name="firmware_uninstalled_success">Firmware avinstallert</string>
|
||||
|
||||
<string name="error_firmware_missing">Fastvare kreves for å kjøre enkelte spill og applikasjoner. Eden fungerer bare med fastvare 19.0.1 eller eldre.</string>
|
||||
<string name="error_firmware_corrupted">Fastvare er til stede, men kan ikke leses. Sjekk dekrypteringsnøklene og dump fastvaren på nytt om nødvendig.</string>
|
||||
<string name="error_firmware_too_new">Fastvaren er for ny eller kan ikke leses. Eden fungerer bare med fastvare 19.0.1 eller eldre.</string>
|
||||
|
||||
<string name="keys_failed">Kunne ikke installere nøkler</string>
|
||||
<string name="keys_install_success">Nøklene ble installert</string>
|
||||
|
||||
@@ -370,9 +370,6 @@
|
||||
<string name="firmware_uninstalling">Odinstalowywanie firmware...</string>
|
||||
<string name="firmware_uninstalled_success">Firmware odinstalowany pomyślnie</string>
|
||||
|
||||
<string name="error_firmware_missing">Firmware jest wymagany do uruchamiania niektórych gier i aplikacji. Eden działa tylko z firmwarem 19.0.1 lub starszym.</string>
|
||||
<string name="error_firmware_corrupted">Oprogramowanie sprzętowe jest obecne, ale nie można go odczytać. Sprawdź klucze deszyfrujące i w razie potrzeby zrzuć oprogramowanie ponownie.</string>
|
||||
<string name="error_firmware_too_new">Oprogramowanie sprzętowe jest zbyt nowe lub nie można go odczytać. Eden działa tylko z oprogramowaniem sprzętowym w wersji 19.0.1 lub starszej.</string>
|
||||
|
||||
<string name="keys_failed">Nie udało się zainstalować kluczy</string>
|
||||
<string name="keys_install_success">Pomyślnie zainstalowano klucze</string>
|
||||
|
||||
@@ -368,9 +368,6 @@
|
||||
<string name="firmware_uninstalling">Desinstalando firmware</string>
|
||||
<string name="firmware_uninstalled_success">Firmware desinstalado com sucesso</string>
|
||||
|
||||
<string name="error_firmware_missing">Firmware é necessário para executar certos jogos e aplicativos. Eden só funciona com firmware 19.0.1 ou anterior.</string>
|
||||
<string name="error_firmware_corrupted">Firmware está presente mas não pode ser lido. Verifique as chaves de descriptografia e refaça o dump do firmware se necessário.</string>
|
||||
<string name="error_firmware_too_new">Firmware é muito novo ou não pode ser lido. Eden só funciona com firmware 19.0.1 ou anterior.</string>
|
||||
|
||||
<string name="keys_failed">Falha ao instalar chaves (keys)</string>
|
||||
<string name="keys_install_success">Chaves (keys) instaladas com sucesso</string>
|
||||
|
||||
@@ -334,9 +334,6 @@
|
||||
<string name="firmware_uninstalling">A desinstalar firmware...</string>
|
||||
<string name="firmware_uninstalled_success">Firmware desinstalado com sucesso</string>
|
||||
|
||||
<string name="error_firmware_missing">É necessário firmware para executar alguns jogos e aplicações. O Eden só funciona com firmware 19.0.1 ou anterior.</string>
|
||||
<string name="error_firmware_corrupted">Firmware está presente mas não pode ser lido. Verifique chaves de descriptografia e volte a fazer dump do firmware se necessário.</string>
|
||||
<string name="error_firmware_too_new">Firmware é demasiado recente ou ilegível. O Eden só funciona com firmware 19.0.1 ou anterior.</string>
|
||||
|
||||
<string name="keys_failed">Falha ao instalar chaves</string>
|
||||
<string name="keys_install_success">Chaves instaladas com sucesso</string>
|
||||
|
||||
@@ -370,9 +370,6 @@
|
||||
<string name="firmware_uninstalling">Удаление прошивки...</string>
|
||||
<string name="firmware_uninstalled_success">Прошивка успешно удалена</string>
|
||||
|
||||
<string name="error_firmware_missing">Для запуска некоторых игр и системных апплетов требуется прошивка. Eden работает только с прошивкой версии 19.0.1 и ниже.</string>
|
||||
<string name="error_firmware_corrupted">Прошивка обнаружена, но не может быть прочитана. Проверьте наличие ключей дешифрования и при необходимости пересохраните прошивку.</string>
|
||||
<string name="error_firmware_too_new">Прошивка слишком новая или не может быть прочитана. Eden работает только с прошивкой версии 19.0.1 и ниже.</string>
|
||||
|
||||
<string name="keys_failed">Ошибка установки ключей</string>
|
||||
<string name="keys_install_success">Ключи успешно установлены</string>
|
||||
|
||||
@@ -334,9 +334,6 @@
|
||||
<string name="firmware_uninstalling">Деинсталирање фирмвера</string>
|
||||
<string name="firmware_uninstalled_success">Фирмваре је успешно деинсталирано</string>
|
||||
|
||||
<string name="error_firmware_missing">Firmware је потребан за покретање одређених игара и апликација. Eden ради само са firmware-ом 19.0.1 или старијим.</string>
|
||||
<string name="error_firmware_corrupted">Firmware је присутан али се не може прочитати. Проверите кључеве за дешифровање и поново направите firmware дамп ако је потребно.</string>
|
||||
<string name="error_firmware_too_new">Firmware је превише нов или се не може прочитати. Eden ради само са firmware-ом 19.0.1 или старијим.</string>
|
||||
|
||||
<string name="keys_failed">Неуспела инсталација кључева</string>
|
||||
<string name="keys_install_success">Кључеви успешно инсталирани</string>
|
||||
|
||||
@@ -370,9 +370,6 @@
|
||||
<string name="firmware_uninstalling">Видалення прошивки...</string>
|
||||
<string name="firmware_uninstalled_success">Прошивку успішно видалено</string>
|
||||
|
||||
<string name="error_firmware_missing">Для запуску деяких ігор та системних аплетів потрібна прошивка. Eden працює лише з прошивкою 19.0.1 або старішою.</string>
|
||||
<string name="error_firmware_corrupted">Прошивка є, але не може бути прочитана. Перевірте ключі дешифрування та повторно зробіть дамп прошивки за необхідності.</string>
|
||||
<string name="error_firmware_too_new">Прошивка занадто нова або нечитабельна. Eden працює лише з прошивкою 19.0.1 або старішою.</string>
|
||||
|
||||
<string name="keys_failed">Не вдалося встановити ключі</string>
|
||||
<string name="keys_install_success">Ключі успішно встановлено</string>
|
||||
|
||||
@@ -320,9 +320,6 @@
|
||||
<string name="firmware_uninstalling">Đang gỡ cài đặt firmware...</string>
|
||||
<string name="firmware_uninstalled_success">Gỡ cài đặt firmware thành công</string>
|
||||
|
||||
<string name="error_firmware_missing">Firmware là cần thiết để chạy một số trò chơi và ứng dụng. Eden chỉ hoạt động với firmware 19.0.1 trở về trước.</string>
|
||||
<string name="error_firmware_corrupted">Firmware được báo cáo là có nhưng không thể đọc được. Kiểm tra khóa giải mã và dump lại firmware nếu cần.</string>
|
||||
<string name="error_firmware_too_new">Firmware quá mới hoặc không thể đọc. Eden chỉ hoạt động với firmware 19.0.1 trở về trước.</string>
|
||||
|
||||
<string name="keys_failed">Không thể cài đặt khóa</string>
|
||||
<string name="keys_install_success">Đã cài đặt khóa thành công</string>
|
||||
|
||||
@@ -335,9 +335,6 @@
|
||||
<string name="firmware_uninstalling">正在卸载固件...</string>
|
||||
<string name="firmware_uninstalled_success">固件卸载成功</string>
|
||||
|
||||
<string name="error_firmware_missing">运行某些游戏和系统应用需要固件。Eden仅支持19.0.1及更早版本的固件。</string>
|
||||
<string name="error_firmware_corrupted">检测到固件存在但无法读取。请检查解密密钥并在必要时重新转储固件。</string>
|
||||
<string name="error_firmware_too_new">固件过新或无法读取。Eden仅支持19.0.1及更早版本的固件。</string>
|
||||
|
||||
<string name="keys_failed">密钥安装失败</string>
|
||||
<string name="keys_install_success">密钥安装成功</string>
|
||||
|
||||
@@ -364,9 +364,6 @@
|
||||
<string name="firmware_uninstalling">正在解除安裝韌體...</string>
|
||||
<string name="firmware_uninstalled_success">韌體解除安裝成功</string>
|
||||
|
||||
<string name="error_firmware_missing">執行某些遊戲和系統應用程式需要韌體。Eden僅支援19.0.1及更早版本的韌體。</string>
|
||||
<string name="error_firmware_corrupted">檢測到韌體存在但無法讀取。請檢查解密金鑰並在必要時重新轉儲韌體。</string>
|
||||
<string name="error_firmware_too_new">韌體過新或無法讀取。Eden僅支援19.0.1及更早版本的韌體。</string>
|
||||
|
||||
<string name="keys_failed">金鑰安裝失敗</string>
|
||||
<string name="keys_install_success">金鑰安裝成功</string>
|
||||
|
||||
@@ -200,6 +200,7 @@
|
||||
<string name="multiplayer_chat">Chat</string>
|
||||
<string name="multiplayer_more_options">More Options</string>
|
||||
<string name="chat">Chat</string>
|
||||
<string name="clear">Clear</string>
|
||||
<string name="type_message">Type message…</string>
|
||||
<string name="send_message">Send Message</string>
|
||||
<string name="multiplayer_moderation">Moderation</string>
|
||||
@@ -376,9 +377,6 @@
|
||||
<string name="firmware_uninstalling">Uninstalling firmware</string>
|
||||
<string name="firmware_uninstalled_success">Firmware uninstalled successfully</string>
|
||||
|
||||
<string name="error_firmware_missing">Firmware is required to run certain games and use system applications. Eden only works with firmware 19.0.1 and earlier.</string>
|
||||
<string name="error_firmware_corrupted">Firmware reported as present, but was unable to be read. Check for decryption keys and redump firmware if necessary.</string>
|
||||
<string name="error_firmware_too_new">Firmware is too new or could not be read. Eden only works with firmware 19.0.1 and earlier.</string>
|
||||
|
||||
<string name="keys_failed">Failed to Install Keys</string>
|
||||
<string name="keys_install_success">Keys successfully installed</string>
|
||||
@@ -689,7 +687,7 @@
|
||||
<string name="copy_details">Copy details</string>
|
||||
<string name="add_ons">Add-ons</string>
|
||||
<string name="add_ons_description">Toggle mods, updates and DLC</string>
|
||||
<string name="playtime">Playtime:</string>
|
||||
<string name="playtime">Playtime: </string>
|
||||
<string name="reset_playtime">Clear Playtime</string>
|
||||
<string name="reset_playtime_description">Reset the current game\'s playtime back to 0 seconds</string>
|
||||
<string name="reset_playtime_warning_description">This will clear the current game\'s playtime data. Are you sure?</string>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -27,19 +28,20 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
|
||||
|
||||
constexpr s32 min = (std::numeric_limits<s16>::min)();
|
||||
constexpr s32 max = (std::numeric_limits<s16>::max)();
|
||||
|
||||
auto yuzu_volume = Settings::Volume();
|
||||
if (yuzu_volume > 1.0f)
|
||||
yuzu_volume = 0.6f + 20.0f * std::log10(yuzu_volume);
|
||||
yuzu_volume = std::max(yuzu_volume, 0.001f);
|
||||
auto const volume = system_volume * device_volume * yuzu_volume;
|
||||
|
||||
if (system_channels > device_channels) {
|
||||
// "Topological" coefficients, basically makes back sounds be less noisy :)
|
||||
// Front = 1.0; Center = 0.596; LFE = 0.354; Back = 0.707
|
||||
static constexpr std::array<f32, 4> tcoeff{1.0f, 0.596f, 0.354f, 0.707f};
|
||||
// We're given 6 channels, but our device only outputs 2, so downmix.
|
||||
for (u32 r_offs = 0, w_offs = 0; r_offs < samples.size(); r_offs += system_channels, w_offs += device_channels) {
|
||||
std::array<f32, 6> ccoeff{0.f};
|
||||
for (u32 i = 0; i < system_channels; ++i)
|
||||
ccoeff[i] = f32(samples[r_offs + i]);
|
||||
|
||||
std::array<f32, 6> rcoeff{
|
||||
ccoeff[u32(Channels::FrontLeft)],
|
||||
ccoeff[u32(Channels::BackLeft)],
|
||||
@@ -48,31 +50,34 @@ void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
|
||||
ccoeff[u32(Channels::BackRight)],
|
||||
ccoeff[u32(Channels::FrontRight)],
|
||||
};
|
||||
std::array<f32, 6> scoeff{
|
||||
rcoeff[0] * tcoeff[0] + rcoeff[2] * tcoeff[1] + rcoeff[3] * tcoeff[2] + rcoeff[1] * tcoeff[3],
|
||||
rcoeff[5] * tcoeff[0] + rcoeff[2] * tcoeff[1] + rcoeff[3] * tcoeff[2] + rcoeff[4] * tcoeff[3],
|
||||
rcoeff[4] * tcoeff[0] + rcoeff[3] * tcoeff[1] + rcoeff[2] * tcoeff[2] + rcoeff[2] * tcoeff[3],
|
||||
rcoeff[3] * tcoeff[0] + rcoeff[3] * tcoeff[1] + rcoeff[2] * tcoeff[2] + rcoeff[3] * tcoeff[3],
|
||||
rcoeff[2] * tcoeff[0] + rcoeff[4] * tcoeff[1] + rcoeff[1] * tcoeff[2] + rcoeff[0] * tcoeff[3],
|
||||
rcoeff[1] * tcoeff[0] + rcoeff[4] * tcoeff[1] + rcoeff[1] * tcoeff[2] + rcoeff[5] * tcoeff[3]
|
||||
};
|
||||
for (u32 i = 0; i < system_channels; ++i)
|
||||
samples[w_offs + i] = s16(std::clamp(s32(scoeff[i] * volume), min, max));
|
||||
|
||||
const f32 left = rcoeff[0] * tcoeff[0] + rcoeff[2] * tcoeff[1] + rcoeff[3] * tcoeff[2] + rcoeff[1] * tcoeff[3];
|
||||
const f32 right = rcoeff[5] * tcoeff[0] + rcoeff[2] * tcoeff[1] + rcoeff[3] * tcoeff[2] + rcoeff[4] * tcoeff[3];
|
||||
|
||||
samples[w_offs + 0] = s16(std::clamp(s32(left * volume), min, max));
|
||||
samples[w_offs + 1] = s16(std::clamp(s32(right * volume), min, max));
|
||||
}
|
||||
|
||||
queue.EmplaceWait(buffer);
|
||||
samples_buffer.Push(samples.subspan(0, samples.size() / system_channels * device_channels));
|
||||
} else if (system_channels < device_channels) {
|
||||
// We need moar samples! Not all games will provide 6 channel audio.
|
||||
std::vector<s16> new_samples(samples.size() / system_channels * device_channels);
|
||||
for (u32 r_offs = 0, w_offs = 0; r_offs < samples.size(); r_offs += system_channels, w_offs += device_channels)
|
||||
for (u32 channel = 0; channel < system_channels; ++channel)
|
||||
new_samples[w_offs + channel] = s16(std::clamp(s32(f32(samples[r_offs + channel]) * volume), min, max));
|
||||
|
||||
queue.EmplaceWait(buffer);
|
||||
samples_buffer.Push(new_samples);
|
||||
} else {
|
||||
for (u32 i = 0; i < samples.size() && volume != 1.0f; ++i)
|
||||
samples[i] = s16(std::clamp(s32(f32(samples[i]) * volume), min, max));
|
||||
if (volume != 1.0f) {
|
||||
for (u32 i = 0; i < samples.size(); ++i)
|
||||
samples[i] = s16(std::clamp(s32(f32(samples[i]) * volume), min, max));
|
||||
}
|
||||
|
||||
queue.EmplaceWait(buffer);
|
||||
samples_buffer.Push(samples);
|
||||
}
|
||||
queue.EmplaceWait(buffer);
|
||||
|
||||
++queued_buffers;
|
||||
}
|
||||
|
||||
@@ -96,10 +101,12 @@ std::vector<s16> SinkStream::ReleaseBuffer(u64 num_samples) {
|
||||
}
|
||||
|
||||
void SinkStream::ClearQueue() {
|
||||
std::scoped_lock lk{release_mutex};
|
||||
|
||||
samples_buffer.Pop();
|
||||
SinkBuffer tmp;
|
||||
while (queue.TryPop(tmp))
|
||||
;
|
||||
while (queue.TryPop(tmp));
|
||||
|
||||
queued_buffers = 0;
|
||||
playing_buffer = {};
|
||||
playing_buffer.consumed = true;
|
||||
@@ -122,8 +129,7 @@ void SinkStream::ProcessAudioIn(std::span<const s16> input_buffer, std::size_t n
|
||||
if (!queue.TryPop(playing_buffer)) {
|
||||
// If no buffer was available we've underrun, just push the samples and
|
||||
// continue.
|
||||
samples_buffer.Push(&input_buffer[frames_written * frame_size],
|
||||
(num_frames - frames_written) * frame_size);
|
||||
samples_buffer.Push(&input_buffer[frames_written * frame_size], (num_frames - frames_written) * frame_size);
|
||||
frames_written = num_frames;
|
||||
continue;
|
||||
}
|
||||
@@ -133,11 +139,9 @@ void SinkStream::ProcessAudioIn(std::span<const s16> input_buffer, std::size_t n
|
||||
|
||||
// Get the minimum frames available between the currently playing buffer, and the
|
||||
// amount we have left to fill
|
||||
size_t frames_available{std::min<u64>(playing_buffer.frames - playing_buffer.frames_played,
|
||||
num_frames - frames_written)};
|
||||
size_t frames_available{std::min<u64>(playing_buffer.frames - playing_buffer.frames_played, num_frames - frames_written)};
|
||||
|
||||
samples_buffer.Push(&input_buffer[frames_written * frame_size],
|
||||
frames_available * frame_size);
|
||||
samples_buffer.Push(&input_buffer[frames_written * frame_size], frames_available * frame_size);
|
||||
|
||||
frames_written += frames_available;
|
||||
playing_buffer.frames_played += frames_available;
|
||||
@@ -158,63 +162,49 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
|
||||
size_t frames_written{0};
|
||||
size_t actual_frames_written{0};
|
||||
|
||||
// If we're paused or going to shut down, we don't want to consume buffers as coretiming is
|
||||
// paused and we'll desync, so just play silence.
|
||||
if (system.IsPaused() || system.IsShuttingDown()) {
|
||||
if (system.IsShuttingDown()) {
|
||||
{
|
||||
std::scoped_lock lk{release_mutex};
|
||||
queued_buffers.store(0);
|
||||
}
|
||||
std::scoped_lock lk{release_mutex};
|
||||
queued_buffers.store(0);
|
||||
release_cv.notify_one();
|
||||
}
|
||||
|
||||
static constexpr std::array<s16, 6> silence{};
|
||||
for (size_t i = frames_written; i < num_frames; i++)
|
||||
std::memcpy(&output_buffer[i * frame_size], &silence[0], frame_size_bytes);
|
||||
for (size_t i = 0; i < num_frames; i++)
|
||||
std::memcpy(&output_buffer[i * frame_size], silence.data(), frame_size_bytes);
|
||||
return;
|
||||
}
|
||||
|
||||
while (frames_written < num_frames) {
|
||||
// If the playing buffer has been consumed or has no frames, we need a new one
|
||||
if (playing_buffer.consumed || playing_buffer.frames == 0) {
|
||||
std::unique_lock lk{release_mutex};
|
||||
|
||||
if (!queue.TryPop(playing_buffer)) {
|
||||
// If no buffer was available we've underrun, fill the remaining buffer with
|
||||
// the last written frame and continue.
|
||||
lk.unlock();
|
||||
for (size_t i = frames_written; i < num_frames; i++)
|
||||
std::memcpy(&output_buffer[i * frame_size], &last_frame[0], frame_size_bytes);
|
||||
std::memcpy(&output_buffer[i * frame_size], last_frame.data(), frame_size_bytes);
|
||||
frames_written = num_frames;
|
||||
continue;
|
||||
}
|
||||
// Successfully dequeued a new buffer.
|
||||
{
|
||||
std::unique_lock lk{release_mutex};
|
||||
queued_buffers--;
|
||||
}
|
||||
|
||||
--queued_buffers;
|
||||
lk.unlock();
|
||||
release_cv.notify_one();
|
||||
}
|
||||
|
||||
// Get the minimum frames available between the currently playing buffer, and the
|
||||
// amount we have left to fill
|
||||
size_t frames_available{std::min<u64>(playing_buffer.frames - playing_buffer.frames_played,
|
||||
num_frames - frames_written)};
|
||||
const size_t frames_available = std::min<u64>(playing_buffer.frames - playing_buffer.frames_played, num_frames - frames_written);
|
||||
|
||||
samples_buffer.Pop(&output_buffer[frames_written * frame_size],
|
||||
frames_available * frame_size);
|
||||
samples_buffer.Pop(&output_buffer[frames_written * frame_size], frames_available * frame_size);
|
||||
|
||||
frames_written += frames_available;
|
||||
actual_frames_written += frames_available;
|
||||
playing_buffer.frames_played += frames_available;
|
||||
|
||||
// If that's all the frames in the current buffer, add its samples and mark it as
|
||||
// consumed
|
||||
if (playing_buffer.frames_played >= playing_buffer.frames) {
|
||||
if (playing_buffer.frames_played >= playing_buffer.frames)
|
||||
playing_buffer.consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::memcpy(&last_frame[0], &output_buffer[(frames_written - 1) * frame_size],
|
||||
frame_size_bytes);
|
||||
std::memcpy(last_frame.data(), &output_buffer[(frames_written - 1) * frame_size], frame_size_bytes);
|
||||
|
||||
{
|
||||
std::scoped_lock lk{sample_count_lock};
|
||||
@@ -228,8 +218,7 @@ u64 SinkStream::GetExpectedPlayedSampleCount() {
|
||||
std::scoped_lock lk{sample_count_lock};
|
||||
auto cur_time{system.CoreTiming().GetGlobalTimeNs()};
|
||||
auto time_delta{cur_time - last_sample_count_update_time};
|
||||
auto exp_played_sample_count{min_played_sample_count +
|
||||
(TargetSampleRate * time_delta) / std::chrono::seconds{1}};
|
||||
auto exp_played_sample_count{min_played_sample_count + (TargetSampleRate * time_delta) / std::chrono::seconds{1}};
|
||||
|
||||
// Add 15ms of latency in sample reporting to allow for some leeway in scheduler timings
|
||||
return std::min<u64>(exp_played_sample_count, max_played_sample_count) + TargetSampleCount * 3;
|
||||
@@ -238,14 +227,14 @@ u64 SinkStream::GetExpectedPlayedSampleCount() {
|
||||
void SinkStream::WaitFreeSpace(std::stop_token stop_token) {
|
||||
std::unique_lock lk{release_mutex};
|
||||
|
||||
const auto has_space = [this]() {
|
||||
const u32 current_size = queued_buffers.load(std::memory_order_relaxed);
|
||||
return paused || max_queue_size == 0 || current_size < max_queue_size;
|
||||
auto can_continue = [this]() {
|
||||
return paused || queued_buffers < max_queue_size;
|
||||
};
|
||||
|
||||
if (!has_space()) {
|
||||
// Wait until the queue falls below the configured limit or the stream is paused/stopped.
|
||||
release_cv.wait(lk, stop_token, has_space);
|
||||
release_cv.wait_for(lk, std::chrono::milliseconds(10), can_continue);
|
||||
|
||||
if (queued_buffers > max_queue_size + 10) {
|
||||
release_cv.wait(lk, stop_token, can_continue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
#include <vector>
|
||||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "common/bounded_threadsafe_queue.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "common/ring_buffer.h"
|
||||
#include "common/bounded_threadsafe_queue.h"
|
||||
#include "common/thread.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
@@ -28,7 +28,6 @@ add_library(
|
||||
announce_multiplayer_room.h
|
||||
assert.cpp
|
||||
assert.h
|
||||
atomic_helpers.h
|
||||
atomic_ops.h
|
||||
bit_field.h
|
||||
bit_util.h
|
||||
|
||||
@@ -1,776 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2013-2016 Cameron Desrochers
|
||||
// SPDX-FileCopyrightText: 2015 Jeff Preshing
|
||||
// SPDX-License-Identifier: BSD-2-Clause AND Zlib
|
||||
|
||||
// Distributed under the simplified BSD license (see the license file that
|
||||
// should have come with this header).
|
||||
// Uses Jeff Preshing's semaphore implementation (under the terms of its
|
||||
// separate zlib license, embedded below).
|
||||
|
||||
#pragma once
|
||||
|
||||
// Provides portable (VC++2010+, Intel ICC 13, GCC 4.7+, and anything C++11 compliant)
|
||||
// implementation of low-level memory barriers, plus a few semi-portable utility macros (for
|
||||
// inlining and alignment). Also has a basic atomic type (limited to hardware-supported atomics with
|
||||
// no memory ordering guarantees). Uses the AE_* prefix for macros (historical reasons), and the
|
||||
// "moodycamel" namespace for symbols.
|
||||
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <type_traits>
|
||||
|
||||
// Platform detection
|
||||
#if defined(__INTEL_COMPILER)
|
||||
#define AE_ICC
|
||||
#elif defined(_MSC_VER)
|
||||
#define AE_VCPP
|
||||
#elif defined(__GNUC__)
|
||||
#define AE_GCC
|
||||
#endif
|
||||
|
||||
#if defined(_M_IA64) || defined(__ia64__)
|
||||
#define AE_ARCH_IA64
|
||||
#elif defined(_WIN64) || defined(__amd64__) || defined(_M_X64) || defined(__x86_64__)
|
||||
#define AE_ARCH_X64
|
||||
#elif defined(_M_IX86) || defined(__i386__)
|
||||
#define AE_ARCH_X86
|
||||
#elif defined(_M_PPC) || defined(__powerpc__)
|
||||
#define AE_ARCH_PPC
|
||||
#else
|
||||
#define AE_ARCH_UNKNOWN
|
||||
#endif
|
||||
|
||||
// AE_UNUSED
|
||||
#define AE_UNUSED(x) ((void)x)
|
||||
|
||||
// AE_NO_TSAN/AE_TSAN_ANNOTATE_*
|
||||
#if defined(__has_feature)
|
||||
#if __has_feature(thread_sanitizer)
|
||||
#if __cplusplus >= 201703L // inline variables require C++17
|
||||
namespace Common {
|
||||
inline int ae_tsan_global;
|
||||
}
|
||||
#define AE_TSAN_ANNOTATE_RELEASE() \
|
||||
AnnotateHappensBefore(__FILE__, __LINE__, (void*)(&::moodycamel::ae_tsan_global))
|
||||
#define AE_TSAN_ANNOTATE_ACQUIRE() \
|
||||
AnnotateHappensAfter(__FILE__, __LINE__, (void*)(&::moodycamel::ae_tsan_global))
|
||||
extern "C" void AnnotateHappensBefore(const char*, int, void*);
|
||||
extern "C" void AnnotateHappensAfter(const char*, int, void*);
|
||||
#else // when we can't work with tsan, attempt to disable its warnings
|
||||
#define AE_NO_TSAN __attribute__((no_sanitize("thread")))
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifndef AE_NO_TSAN
|
||||
#define AE_NO_TSAN
|
||||
#endif
|
||||
#ifndef AE_TSAN_ANNOTATE_RELEASE
|
||||
#define AE_TSAN_ANNOTATE_RELEASE()
|
||||
#define AE_TSAN_ANNOTATE_ACQUIRE()
|
||||
#endif
|
||||
|
||||
// AE_FORCEINLINE
|
||||
#if defined(AE_VCPP) || defined(AE_ICC)
|
||||
#define AE_FORCEINLINE __forceinline
|
||||
#elif defined(AE_GCC)
|
||||
// #define AE_FORCEINLINE __attribute__((always_inline))
|
||||
#define AE_FORCEINLINE inline
|
||||
#else
|
||||
#define AE_FORCEINLINE inline
|
||||
#endif
|
||||
|
||||
// AE_ALIGN
|
||||
#if defined(AE_VCPP) || defined(AE_ICC)
|
||||
#define AE_ALIGN(x) __declspec(align(x))
|
||||
#elif defined(AE_GCC)
|
||||
#define AE_ALIGN(x) __attribute__((aligned(x)))
|
||||
#else
|
||||
// Assume GCC compliant syntax...
|
||||
#define AE_ALIGN(x) __attribute__((aligned(x)))
|
||||
#endif
|
||||
|
||||
// Portable atomic fences implemented below:
|
||||
|
||||
namespace Common {
|
||||
|
||||
enum memory_order {
|
||||
memory_order_relaxed,
|
||||
memory_order_acquire,
|
||||
memory_order_release,
|
||||
memory_order_acq_rel,
|
||||
memory_order_seq_cst,
|
||||
|
||||
// memory_order_sync: Forces a full sync:
|
||||
// #LoadLoad, #LoadStore, #StoreStore, and most significantly, #StoreLoad
|
||||
memory_order_sync = memory_order_seq_cst
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
||||
#if (defined(AE_VCPP) && (_MSC_VER < 1700 || defined(__cplusplus_cli))) || \
|
||||
(defined(AE_ICC) && __INTEL_COMPILER < 1600)
|
||||
// VS2010 and ICC13 don't support std::atomic_*_fence, implement our own fences
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
|
||||
#define AeFullSync _mm_mfence
|
||||
#define AeLiteSync _mm_mfence
|
||||
#elif defined(AE_ARCH_IA64)
|
||||
#define AeFullSync __mf
|
||||
#define AeLiteSync __mf
|
||||
#elif defined(AE_ARCH_PPC)
|
||||
#include <ppcintrinsics.h>
|
||||
#define AeFullSync __sync
|
||||
#define AeLiteSync __lwsync
|
||||
#endif
|
||||
|
||||
#ifdef AE_VCPP
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4365) // Disable erroneous 'conversion from long to unsigned int,
|
||||
// signed/unsigned mismatch' error when using `assert`
|
||||
#ifdef __cplusplus_cli
|
||||
#pragma managed(push, off)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
|
||||
AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN {
|
||||
switch (order) {
|
||||
case memory_order_relaxed:
|
||||
break;
|
||||
case memory_order_acquire:
|
||||
_ReadBarrier();
|
||||
break;
|
||||
case memory_order_release:
|
||||
_WriteBarrier();
|
||||
break;
|
||||
case memory_order_acq_rel:
|
||||
_ReadWriteBarrier();
|
||||
break;
|
||||
case memory_order_seq_cst:
|
||||
_ReadWriteBarrier();
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// x86/x64 have a strong memory model -- all loads and stores have
|
||||
// acquire and release semantics automatically (so only need compiler
|
||||
// barriers for those).
|
||||
#if defined(AE_ARCH_X86) || defined(AE_ARCH_X64)
|
||||
AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN {
|
||||
switch (order) {
|
||||
case memory_order_relaxed:
|
||||
break;
|
||||
case memory_order_acquire:
|
||||
_ReadBarrier();
|
||||
break;
|
||||
case memory_order_release:
|
||||
_WriteBarrier();
|
||||
break;
|
||||
case memory_order_acq_rel:
|
||||
_ReadWriteBarrier();
|
||||
break;
|
||||
case memory_order_seq_cst:
|
||||
_ReadWriteBarrier();
|
||||
AeFullSync();
|
||||
_ReadWriteBarrier();
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
#else
|
||||
AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN {
|
||||
// Non-specialized arch, use heavier memory barriers everywhere just in case :-(
|
||||
switch (order) {
|
||||
case memory_order_relaxed:
|
||||
break;
|
||||
case memory_order_acquire:
|
||||
_ReadBarrier();
|
||||
AeLiteSync();
|
||||
_ReadBarrier();
|
||||
break;
|
||||
case memory_order_release:
|
||||
_WriteBarrier();
|
||||
AeLiteSync();
|
||||
_WriteBarrier();
|
||||
break;
|
||||
case memory_order_acq_rel:
|
||||
_ReadWriteBarrier();
|
||||
AeLiteSync();
|
||||
_ReadWriteBarrier();
|
||||
break;
|
||||
case memory_order_seq_cst:
|
||||
_ReadWriteBarrier();
|
||||
AeFullSync();
|
||||
_ReadWriteBarrier();
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} // namespace Common
|
||||
#else
|
||||
// Use standard library of atomics
|
||||
#include <atomic>
|
||||
|
||||
namespace Common {
|
||||
|
||||
AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN {
|
||||
switch (order) {
|
||||
case memory_order_relaxed:
|
||||
break;
|
||||
case memory_order_acquire:
|
||||
std::atomic_signal_fence(std::memory_order_acquire);
|
||||
break;
|
||||
case memory_order_release:
|
||||
std::atomic_signal_fence(std::memory_order_release);
|
||||
break;
|
||||
case memory_order_acq_rel:
|
||||
std::atomic_signal_fence(std::memory_order_acq_rel);
|
||||
break;
|
||||
case memory_order_seq_cst:
|
||||
std::atomic_signal_fence(std::memory_order_seq_cst);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
AE_FORCEINLINE void fence(memory_order order) AE_NO_TSAN {
|
||||
switch (order) {
|
||||
case memory_order_relaxed:
|
||||
break;
|
||||
case memory_order_acquire:
|
||||
AE_TSAN_ANNOTATE_ACQUIRE();
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
break;
|
||||
case memory_order_release:
|
||||
AE_TSAN_ANNOTATE_RELEASE();
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
break;
|
||||
case memory_order_acq_rel:
|
||||
AE_TSAN_ANNOTATE_ACQUIRE();
|
||||
AE_TSAN_ANNOTATE_RELEASE();
|
||||
std::atomic_thread_fence(std::memory_order_acq_rel);
|
||||
break;
|
||||
case memory_order_seq_cst:
|
||||
AE_TSAN_ANNOTATE_ACQUIRE();
|
||||
AE_TSAN_ANNOTATE_RELEASE();
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(AE_VCPP) || (_MSC_VER >= 1700 && !defined(__cplusplus_cli))
|
||||
#define AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
|
||||
#endif
|
||||
|
||||
#ifdef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
|
||||
#include <atomic>
|
||||
#endif
|
||||
#include <utility>
|
||||
|
||||
// WARNING: *NOT* A REPLACEMENT FOR std::atomic. READ CAREFULLY:
|
||||
// Provides basic support for atomic variables -- no memory ordering guarantees are provided.
|
||||
// The guarantee of atomicity is only made for types that already have atomic load and store
|
||||
// guarantees at the hardware level -- on most platforms this generally means aligned pointers and
|
||||
// integers (only).
|
||||
namespace Common {
|
||||
template <typename T>
|
||||
class weak_atomic {
|
||||
public:
|
||||
AE_NO_TSAN weak_atomic() : value() {}
|
||||
#ifdef AE_VCPP
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4100) // Get rid of (erroneous) 'unreferenced formal parameter' warning
|
||||
#endif
|
||||
template <typename U>
|
||||
AE_NO_TSAN weak_atomic(U&& x) : value(std::forward<U>(x)) {}
|
||||
#ifdef __cplusplus_cli
|
||||
// Work around bug with universal reference/nullptr combination that only appears when /clr is
|
||||
// on
|
||||
AE_NO_TSAN weak_atomic(nullptr_t) : value(nullptr) {}
|
||||
#endif
|
||||
AE_NO_TSAN weak_atomic(weak_atomic const& other) : value(other.load()) {}
|
||||
AE_NO_TSAN weak_atomic(weak_atomic&& other) : value(std::move(other.load())) {}
|
||||
#ifdef AE_VCPP
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
AE_FORCEINLINE operator T() const AE_NO_TSAN {
|
||||
return load();
|
||||
}
|
||||
|
||||
#ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
|
||||
template <typename U>
|
||||
AE_FORCEINLINE weak_atomic const& operator=(U&& x) AE_NO_TSAN {
|
||||
value = std::forward<U>(x);
|
||||
return *this;
|
||||
}
|
||||
AE_FORCEINLINE weak_atomic const& operator=(weak_atomic const& other) AE_NO_TSAN {
|
||||
value = other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AE_FORCEINLINE T load() const AE_NO_TSAN {
|
||||
return value;
|
||||
}
|
||||
|
||||
AE_FORCEINLINE T fetch_add_acquire(T increment) AE_NO_TSAN {
|
||||
#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
|
||||
if (sizeof(T) == 4)
|
||||
return _InterlockedExchangeAdd((long volatile*)&value, (long)increment);
|
||||
#if defined(_M_AMD64)
|
||||
else if (sizeof(T) == 8)
|
||||
return _InterlockedExchangeAdd64((long long volatile*)&value, (long long)increment);
|
||||
#endif
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
assert(false && "T must be either a 32 or 64 bit type");
|
||||
return value;
|
||||
}
|
||||
|
||||
AE_FORCEINLINE T fetch_add_release(T increment) AE_NO_TSAN {
|
||||
#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
|
||||
if (sizeof(T) == 4)
|
||||
return _InterlockedExchangeAdd((long volatile*)&value, (long)increment);
|
||||
#if defined(_M_AMD64)
|
||||
else if (sizeof(T) == 8)
|
||||
return _InterlockedExchangeAdd64((long long volatile*)&value, (long long)increment);
|
||||
#endif
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
assert(false && "T must be either a 32 or 64 bit type");
|
||||
return value;
|
||||
}
|
||||
#else
|
||||
template <typename U>
|
||||
AE_FORCEINLINE weak_atomic const& operator=(U&& x) AE_NO_TSAN {
|
||||
value.store(std::forward<U>(x), std::memory_order_relaxed);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AE_FORCEINLINE weak_atomic const& operator=(weak_atomic const& other) AE_NO_TSAN {
|
||||
value.store(other.value.load(std::memory_order_relaxed), std::memory_order_relaxed);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AE_FORCEINLINE T load() const AE_NO_TSAN {
|
||||
return value.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
AE_FORCEINLINE T fetch_add_acquire(T increment) AE_NO_TSAN {
|
||||
return value.fetch_add(increment, std::memory_order_acquire);
|
||||
}
|
||||
|
||||
AE_FORCEINLINE T fetch_add_release(T increment) AE_NO_TSAN {
|
||||
return value.fetch_add(increment, std::memory_order_release);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
|
||||
// No std::atomic support, but still need to circumvent compiler optimizations.
|
||||
// `volatile` will make memory access slow, but is guaranteed to be reliable.
|
||||
volatile T value;
|
||||
#else
|
||||
std::atomic<T> value;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
||||
// Portable single-producer, single-consumer semaphore below:
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Avoid including windows.h in a header; we only need a handful of
|
||||
// items, so we'll redeclare them here (this is relatively safe since
|
||||
// the API generally has to remain stable between Windows versions).
|
||||
// I know this is an ugly hack but it still beats polluting the global
|
||||
// namespace with thousands of generic names or adding a .cpp for nothing.
|
||||
extern "C" {
|
||||
struct _SECURITY_ATTRIBUTES;
|
||||
__declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes,
|
||||
long lInitialCount, long lMaximumCount,
|
||||
const wchar_t* lpName);
|
||||
__declspec(dllimport) int __stdcall CloseHandle(void* hObject);
|
||||
__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void* hHandle,
|
||||
unsigned long dwMilliseconds);
|
||||
__declspec(dllimport) int __stdcall ReleaseSemaphore(void* hSemaphore, long lReleaseCount,
|
||||
long* lpPreviousCount);
|
||||
}
|
||||
#elif defined(__MACH__)
|
||||
#include <mach/mach.h>
|
||||
#elif defined(__unix__)
|
||||
#include <semaphore.h>
|
||||
#elif defined(FREERTOS)
|
||||
#include <FreeRTOS.h>
|
||||
#include <semphr.h>
|
||||
#include <task.h>
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
// Code in the spsc_sema namespace below is an adaptation of Jeff Preshing's
|
||||
// portable + lightweight semaphore implementations, originally from
|
||||
// https://github.com/preshing/cpp11-on-multicore/blob/master/common/sema.h
|
||||
// LICENSE:
|
||||
// Copyright (c) 2015 Jeff Preshing
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgement in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
namespace spsc_sema {
|
||||
#if defined(_WIN32)
|
||||
class Semaphore {
|
||||
private:
|
||||
void* m_hSema;
|
||||
|
||||
Semaphore(const Semaphore& other);
|
||||
Semaphore& operator=(const Semaphore& other);
|
||||
|
||||
public:
|
||||
AE_NO_TSAN Semaphore(int initialCount = 0) : m_hSema() {
|
||||
assert(initialCount >= 0);
|
||||
const long maxLong = 0x7fffffff;
|
||||
m_hSema = CreateSemaphoreW(nullptr, initialCount, maxLong, nullptr);
|
||||
assert(m_hSema);
|
||||
}
|
||||
|
||||
AE_NO_TSAN ~Semaphore() {
|
||||
CloseHandle(m_hSema);
|
||||
}
|
||||
|
||||
bool wait() AE_NO_TSAN {
|
||||
const unsigned long infinite = 0xffffffff;
|
||||
return WaitForSingleObject(m_hSema, infinite) == 0;
|
||||
}
|
||||
|
||||
bool try_wait() AE_NO_TSAN {
|
||||
return WaitForSingleObject(m_hSema, 0) == 0;
|
||||
}
|
||||
|
||||
bool timed_wait(std::uint64_t usecs) AE_NO_TSAN {
|
||||
return WaitForSingleObject(m_hSema, (unsigned long)(usecs / 1000)) == 0;
|
||||
}
|
||||
|
||||
void signal(int count = 1) AE_NO_TSAN {
|
||||
while (!ReleaseSemaphore(m_hSema, count, nullptr))
|
||||
;
|
||||
}
|
||||
};
|
||||
#elif defined(__MACH__)
|
||||
//---------------------------------------------------------
|
||||
// Semaphore (Apple iOS and OSX)
|
||||
// Can't use POSIX semaphores due to
|
||||
// http://lists.apple.com/archives/darwin-kernel/2009/Apr/msg00010.html
|
||||
//---------------------------------------------------------
|
||||
class Semaphore {
|
||||
private:
|
||||
semaphore_t m_sema;
|
||||
|
||||
Semaphore(const Semaphore& other);
|
||||
Semaphore& operator=(const Semaphore& other);
|
||||
|
||||
public:
|
||||
AE_NO_TSAN Semaphore(int initialCount = 0) : m_sema() {
|
||||
assert(initialCount >= 0);
|
||||
kern_return_t rc =
|
||||
semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount);
|
||||
assert(rc == KERN_SUCCESS);
|
||||
AE_UNUSED(rc);
|
||||
}
|
||||
|
||||
AE_NO_TSAN ~Semaphore() {
|
||||
semaphore_destroy(mach_task_self(), m_sema);
|
||||
}
|
||||
|
||||
bool wait() AE_NO_TSAN {
|
||||
return semaphore_wait(m_sema) == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
bool try_wait() AE_NO_TSAN {
|
||||
return timed_wait(0);
|
||||
}
|
||||
|
||||
bool timed_wait(std::uint64_t timeout_usecs) AE_NO_TSAN {
|
||||
mach_timespec_t ts;
|
||||
ts.tv_sec = static_cast<unsigned int>(timeout_usecs / 1000000);
|
||||
ts.tv_nsec = static_cast<int>((timeout_usecs % 1000000) * 1000);
|
||||
|
||||
// added in OSX 10.10:
|
||||
// https://developer.apple.com/library/prerelease/mac/documentation/General/Reference/APIDiffsMacOSX10_10SeedDiff/modules/Darwin.html
|
||||
kern_return_t rc = semaphore_timedwait(m_sema, ts);
|
||||
return rc == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
void signal() AE_NO_TSAN {
|
||||
while (semaphore_signal(m_sema) != KERN_SUCCESS)
|
||||
;
|
||||
}
|
||||
|
||||
void signal(int count) AE_NO_TSAN {
|
||||
while (count-- > 0) {
|
||||
while (semaphore_signal(m_sema) != KERN_SUCCESS)
|
||||
;
|
||||
}
|
||||
}
|
||||
};
|
||||
#elif defined(__unix__)
|
||||
//---------------------------------------------------------
|
||||
// Semaphore (POSIX, Linux)
|
||||
//---------------------------------------------------------
|
||||
class Semaphore {
|
||||
private:
|
||||
sem_t m_sema;
|
||||
|
||||
Semaphore(const Semaphore& other);
|
||||
Semaphore& operator=(const Semaphore& other);
|
||||
|
||||
public:
|
||||
AE_NO_TSAN Semaphore(int initialCount = 0) : m_sema() {
|
||||
assert(initialCount >= 0);
|
||||
int rc = sem_init(&m_sema, 0, static_cast<unsigned int>(initialCount));
|
||||
assert(rc == 0);
|
||||
AE_UNUSED(rc);
|
||||
}
|
||||
|
||||
AE_NO_TSAN ~Semaphore() {
|
||||
sem_destroy(&m_sema);
|
||||
}
|
||||
|
||||
bool wait() AE_NO_TSAN {
|
||||
// http://stackoverflow.com/questions/2013181/gdb-causes-sem-wait-to-fail-with-eintr-error
|
||||
int rc;
|
||||
do {
|
||||
rc = sem_wait(&m_sema);
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
bool try_wait() AE_NO_TSAN {
|
||||
int rc;
|
||||
do {
|
||||
rc = sem_trywait(&m_sema);
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
bool timed_wait(std::uint64_t usecs) AE_NO_TSAN {
|
||||
struct timespec ts;
|
||||
const int usecs_in_1_sec = 1000000;
|
||||
const int nsecs_in_1_sec = 1000000000;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_sec += static_cast<time_t>(usecs / usecs_in_1_sec);
|
||||
ts.tv_nsec += static_cast<long>(usecs % usecs_in_1_sec) * 1000;
|
||||
// sem_timedwait bombs if you have more than 1e9 in tv_nsec
|
||||
// so we have to clean things up before passing it in
|
||||
if (ts.tv_nsec >= nsecs_in_1_sec) {
|
||||
ts.tv_nsec -= nsecs_in_1_sec;
|
||||
++ts.tv_sec;
|
||||
}
|
||||
|
||||
int rc;
|
||||
do {
|
||||
rc = sem_timedwait(&m_sema, &ts);
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
void signal() AE_NO_TSAN {
|
||||
while (sem_post(&m_sema) == -1)
|
||||
;
|
||||
}
|
||||
|
||||
void signal(int count) AE_NO_TSAN {
|
||||
while (count-- > 0) {
|
||||
while (sem_post(&m_sema) == -1)
|
||||
;
|
||||
}
|
||||
}
|
||||
};
|
||||
#elif defined(FREERTOS)
|
||||
//---------------------------------------------------------
|
||||
// Semaphore (FreeRTOS)
|
||||
//---------------------------------------------------------
|
||||
class Semaphore {
|
||||
private:
|
||||
SemaphoreHandle_t m_sema;
|
||||
|
||||
Semaphore(const Semaphore& other);
|
||||
Semaphore& operator=(const Semaphore& other);
|
||||
|
||||
public:
|
||||
AE_NO_TSAN Semaphore(int initialCount = 0) : m_sema() {
|
||||
assert(initialCount >= 0);
|
||||
m_sema = xSemaphoreCreateCounting(static_cast<UBaseType_t>(~0ull),
|
||||
static_cast<UBaseType_t>(initialCount));
|
||||
assert(m_sema);
|
||||
}
|
||||
|
||||
AE_NO_TSAN ~Semaphore() {
|
||||
vSemaphoreDelete(m_sema);
|
||||
}
|
||||
|
||||
bool wait() AE_NO_TSAN {
|
||||
return xSemaphoreTake(m_sema, portMAX_DELAY) == pdTRUE;
|
||||
}
|
||||
|
||||
bool try_wait() AE_NO_TSAN {
|
||||
// Note: In an ISR context, if this causes a task to unblock,
|
||||
// the caller won't know about it
|
||||
if (xPortIsInsideInterrupt())
|
||||
return xSemaphoreTakeFromISR(m_sema, NULL) == pdTRUE;
|
||||
return xSemaphoreTake(m_sema, 0) == pdTRUE;
|
||||
}
|
||||
|
||||
bool timed_wait(std::uint64_t usecs) AE_NO_TSAN {
|
||||
std::uint64_t msecs = usecs / 1000;
|
||||
TickType_t ticks = static_cast<TickType_t>(msecs / portTICK_PERIOD_MS);
|
||||
if (ticks == 0)
|
||||
return try_wait();
|
||||
return xSemaphoreTake(m_sema, ticks) == pdTRUE;
|
||||
}
|
||||
|
||||
void signal() AE_NO_TSAN {
|
||||
// Note: In an ISR context, if this causes a task to unblock,
|
||||
// the caller won't know about it
|
||||
BaseType_t rc;
|
||||
if (xPortIsInsideInterrupt())
|
||||
rc = xSemaphoreGiveFromISR(m_sema, NULL);
|
||||
else
|
||||
rc = xSemaphoreGive(m_sema);
|
||||
assert(rc == pdTRUE);
|
||||
AE_UNUSED(rc);
|
||||
}
|
||||
|
||||
void signal(int count) AE_NO_TSAN {
|
||||
while (count-- > 0)
|
||||
signal();
|
||||
}
|
||||
};
|
||||
#else
|
||||
#error Unsupported platform! (No semaphore wrapper available)
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------
|
||||
// LightweightSemaphore
|
||||
//---------------------------------------------------------
|
||||
class LightweightSemaphore {
|
||||
public:
|
||||
typedef std::make_signed<std::size_t>::type ssize_t;
|
||||
|
||||
private:
|
||||
weak_atomic<ssize_t> m_count;
|
||||
Semaphore m_sema;
|
||||
|
||||
bool waitWithPartialSpinning(std::int64_t timeout_usecs = -1) AE_NO_TSAN {
|
||||
ssize_t oldCount;
|
||||
// Is there a better way to set the initial spin count?
|
||||
// If we lower it to 1000, testBenaphore becomes 15x slower on my Core i7-5930K Windows PC,
|
||||
// as threads start hitting the kernel semaphore.
|
||||
int spin = 1024;
|
||||
while (--spin >= 0) {
|
||||
if (m_count.load() > 0) {
|
||||
m_count.fetch_add_acquire(-1);
|
||||
return true;
|
||||
}
|
||||
compiler_fence(memory_order_acquire); // Prevent the compiler from collapsing the loop.
|
||||
}
|
||||
oldCount = m_count.fetch_add_acquire(-1);
|
||||
if (oldCount > 0)
|
||||
return true;
|
||||
if (timeout_usecs < 0) {
|
||||
if (m_sema.wait())
|
||||
return true;
|
||||
}
|
||||
if (timeout_usecs > 0 && m_sema.timed_wait(static_cast<uint64_t>(timeout_usecs)))
|
||||
return true;
|
||||
// At this point, we've timed out waiting for the semaphore, but the
|
||||
// count is still decremented indicating we may still be waiting on
|
||||
// it. So we have to re-adjust the count, but only if the semaphore
|
||||
// wasn't signaled enough times for us too since then. If it was, we
|
||||
// need to release the semaphore too.
|
||||
while (true) {
|
||||
oldCount = m_count.fetch_add_release(1);
|
||||
if (oldCount < 0)
|
||||
return false; // successfully restored things to the way they were
|
||||
// Oh, the producer thread just signaled the semaphore after all. Try again:
|
||||
oldCount = m_count.fetch_add_acquire(-1);
|
||||
if (oldCount > 0 && m_sema.try_wait())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
AE_NO_TSAN LightweightSemaphore(ssize_t initialCount = 0) : m_count(initialCount), m_sema() {
|
||||
assert(initialCount >= 0);
|
||||
}
|
||||
|
||||
bool tryWait() AE_NO_TSAN {
|
||||
if (m_count.load() > 0) {
|
||||
m_count.fetch_add_acquire(-1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wait() AE_NO_TSAN {
|
||||
return tryWait() || waitWithPartialSpinning();
|
||||
}
|
||||
|
||||
bool wait(std::int64_t timeout_usecs) AE_NO_TSAN {
|
||||
return tryWait() || waitWithPartialSpinning(timeout_usecs);
|
||||
}
|
||||
|
||||
void signal(ssize_t count = 1) AE_NO_TSAN {
|
||||
assert(count >= 0);
|
||||
ssize_t oldCount = m_count.fetch_add_release(count);
|
||||
assert(oldCount >= -1);
|
||||
if (oldCount < 0) {
|
||||
m_sema.signal(1);
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t availableApprox() const AE_NO_TSAN {
|
||||
ssize_t count = m_count.load();
|
||||
return count > 0 ? static_cast<std::size_t>(count) : 0;
|
||||
}
|
||||
};
|
||||
} // namespace spsc_sema
|
||||
} // namespace Common
|
||||
|
||||
#if defined(AE_VCPP) && (_MSC_VER < 1700 || defined(__cplusplus_cli))
|
||||
#pragma warning(pop)
|
||||
#ifdef __cplusplus_cli
|
||||
#pragma managed(pop)
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -39,12 +42,8 @@
|
||||
#define Crash() exit(1)
|
||||
#endif
|
||||
|
||||
#define LTO_NOINLINE __attribute__((noinline))
|
||||
|
||||
#else // _MSC_VER
|
||||
|
||||
#define LTO_NOINLINE
|
||||
|
||||
// Locale Cross-Compatibility
|
||||
#define locale_t _locale_t
|
||||
|
||||
@@ -129,19 +128,4 @@ namespace Common {
|
||||
u64(g) << 48 | u64(h) << 56;
|
||||
}
|
||||
|
||||
// std::size() does not support zero-size C arrays. We're fixing that.
|
||||
template <class C>
|
||||
constexpr auto Size(const C& c) -> decltype(c.size()) {
|
||||
return std::size(c);
|
||||
}
|
||||
|
||||
template <class C>
|
||||
constexpr std::size_t Size(const C& c) {
|
||||
if constexpr (sizeof(C) == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return std::size(c);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "common/heap_tracker.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/assert.h"
|
||||
@@ -36,6 +37,8 @@ HeapTracker::~HeapTracker() = default;
|
||||
|
||||
void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
MemoryPermission perm, bool is_separate_heap) {
|
||||
bool rebuild_required = false;
|
||||
|
||||
// When mapping other memory, map pages immediately.
|
||||
if (!is_separate_heap) {
|
||||
m_buffer.Map(virtual_offset, host_offset, length, perm, false);
|
||||
@@ -57,11 +60,29 @@ void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
|
||||
// Insert into mappings.
|
||||
m_map_count++;
|
||||
m_mappings.insert(*map);
|
||||
const auto it = m_mappings.insert(*map);
|
||||
|
||||
// Update tick before possible rebuild.
|
||||
it->tick = m_tick++;
|
||||
|
||||
// Check if we need to rebuild.
|
||||
if (m_resident_map_count >= m_max_resident_map_count) {
|
||||
rebuild_required = true;
|
||||
}
|
||||
|
||||
// Map the area.
|
||||
m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false);
|
||||
|
||||
// This map is now resident.
|
||||
it->is_resident = true;
|
||||
m_resident_map_count++;
|
||||
m_resident_mappings.insert(*it);
|
||||
}
|
||||
|
||||
// Finally, map.
|
||||
this->DeferredMapSeparateHeap(virtual_offset);
|
||||
if (rebuild_required) {
|
||||
// A rebuild was required, so perform it now.
|
||||
this->RebuildSeparateHeapAddressSpace();
|
||||
}
|
||||
}
|
||||
|
||||
void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_heap) {
|
||||
@@ -148,6 +169,7 @@ void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission p
|
||||
|
||||
// Clamp to end.
|
||||
next = (std::min)(next, end);
|
||||
|
||||
// Reprotect, if we need to.
|
||||
if (should_protect) {
|
||||
m_buffer.Protect(cur, next - cur, perm);
|
||||
@@ -158,51 +180,6 @@ void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission p
|
||||
}
|
||||
}
|
||||
|
||||
bool HeapTracker::DeferredMapSeparateHeap(u8* fault_address) {
|
||||
if (m_buffer.IsInVirtualRange(fault_address)) {
|
||||
return this->DeferredMapSeparateHeap(fault_address - m_buffer.VirtualBasePointer());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) {
|
||||
bool rebuild_required = false;
|
||||
|
||||
{
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
// Check to ensure this was a non-resident separate heap mapping.
|
||||
const auto it = this->GetNearestHeapMapLocked(virtual_offset);
|
||||
if (it == m_mappings.end() || it->is_resident) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update tick before possible rebuild.
|
||||
it->tick = m_tick++;
|
||||
|
||||
// Check if we need to rebuild.
|
||||
if (m_resident_map_count > m_max_resident_map_count) {
|
||||
rebuild_required = true;
|
||||
}
|
||||
|
||||
// Map the area.
|
||||
m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false);
|
||||
|
||||
// This map is now resident.
|
||||
it->is_resident = true;
|
||||
m_resident_map_count++;
|
||||
m_resident_mappings.insert(*it);
|
||||
}
|
||||
|
||||
if (rebuild_required) {
|
||||
// A rebuild was required, so perform it now.
|
||||
this->RebuildSeparateHeapAddressSpace();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HeapTracker::RebuildSeparateHeapAddressSpace() {
|
||||
std::scoped_lock lk{m_rebuild_lock, m_lock};
|
||||
|
||||
@@ -213,8 +190,8 @@ void HeapTracker::RebuildSeparateHeapAddressSpace() {
|
||||
// Despite being worse in theory, this has proven to be better in practice than more
|
||||
// regularly dumping a smaller amount, because it significantly reduces average case
|
||||
// lock contention.
|
||||
std::size_t const desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2;
|
||||
std::size_t const evict_count = m_resident_map_count - desired_count;
|
||||
const size_t desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2;
|
||||
const size_t evict_count = m_resident_map_count - desired_count;
|
||||
auto it = m_resident_mappings.begin();
|
||||
|
||||
for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) {
|
||||
|
||||
@@ -622,6 +622,10 @@ struct Values {
|
||||
|
||||
// Linux
|
||||
SwitchableSetting<bool> enable_gamemode{linkage, true, "enable_gamemode", Category::Linux};
|
||||
#ifdef __unix__
|
||||
SwitchableSetting<bool> gui_force_x11{linkage, false, "gui_force_x11", Category::Linux};
|
||||
Setting<bool> gui_hide_backend_warning{linkage, false, "gui_hide_backend_warning", Category::Linux};
|
||||
#endif
|
||||
|
||||
// Controls
|
||||
InputSetting<std::array<PlayerInput, 10>> players;
|
||||
|
||||
@@ -1231,7 +1231,6 @@ endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
target_sources(core PRIVATE
|
||||
arm/dynarmic/arm_dynarmic.cpp
|
||||
arm/dynarmic/arm_dynarmic.h
|
||||
arm/dynarmic/arm_dynarmic_64.cpp
|
||||
arm/dynarmic/arm_dynarmic_64.h
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "common/signal_chain.h"
|
||||
|
||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
namespace {
|
||||
|
||||
thread_local Core::Memory::Memory* g_current_memory{};
|
||||
std::once_flag g_registered{};
|
||||
struct sigaction g_old_segv {};
|
||||
|
||||
void HandleSigSegv(int sig, siginfo_t* info, void* ctx) {
|
||||
if (g_current_memory && g_current_memory->InvalidateSeparateHeap(info->si_addr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return g_old_segv.sa_sigaction(sig, info, ctx);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ScopedJitExecution::ScopedJitExecution(Kernel::KProcess* process) {
|
||||
g_current_memory = std::addressof(process->GetMemory());
|
||||
}
|
||||
|
||||
ScopedJitExecution::~ScopedJitExecution() {
|
||||
g_current_memory = nullptr;
|
||||
}
|
||||
|
||||
void ScopedJitExecution::RegisterHandler() {
|
||||
std::call_once(g_registered, [] {
|
||||
struct sigaction sa {};
|
||||
sa.sa_sigaction = &HandleSigSegv;
|
||||
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
Common::SigAction(SIGSEGV, std::addressof(sa), std::addressof(g_old_segv));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -26,24 +29,4 @@ constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
|
||||
return static_cast<HaltReason>(hr);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
class ScopedJitExecution {
|
||||
public:
|
||||
explicit ScopedJitExecution(Kernel::KProcess* process);
|
||||
~ScopedJitExecution();
|
||||
static void RegisterHandler();
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class ScopedJitExecution {
|
||||
public:
|
||||
explicit ScopedJitExecution(Kernel::KProcess* process) {}
|
||||
~ScopedJitExecution() {}
|
||||
static void RegisterHandler() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -210,12 +210,9 @@ std::shared_ptr<Dynarmic::A32::Jit> ArmDynarmic32::MakeJit(Common::PageTable* pa
|
||||
config.wall_clock_cntpct = m_uses_wall_clock;
|
||||
config.enable_cycle_counting = !m_uses_wall_clock;
|
||||
|
||||
// Code cache size
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
// Code cache size - max in ARM is 128MiB, max in x86_64 is 2GiB
|
||||
// Solaris doesn't support kPageSize >= 512MiB
|
||||
config.code_cache_size = std::uint32_t(128_MiB);
|
||||
#else
|
||||
config.code_cache_size = std::uint32_t(512_MiB);
|
||||
#endif
|
||||
|
||||
// Allow memory fault handling to work
|
||||
if (m_system.DebuggerEnabled()) {
|
||||
@@ -344,15 +341,11 @@ bool ArmDynarmic32::IsInThumbMode() const {
|
||||
}
|
||||
|
||||
HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Run());
|
||||
}
|
||||
|
||||
HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Step());
|
||||
}
|
||||
@@ -394,7 +387,6 @@ ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProc
|
||||
m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} {
|
||||
auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl();
|
||||
m_jit = MakeJit(&page_table_impl);
|
||||
ScopedJitExecution::RegisterHandler();
|
||||
}
|
||||
|
||||
ArmDynarmic32::~ArmDynarmic32() = default;
|
||||
|
||||
@@ -269,12 +269,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa
|
||||
config.wall_clock_cntpct = m_uses_wall_clock;
|
||||
config.enable_cycle_counting = !m_uses_wall_clock;
|
||||
|
||||
// Code cache size
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
// Code cache size - max in ARM is 128MiB, max in x86_64 is 2GiB
|
||||
// Solaris doesn't support kPageSize >= 512MiB
|
||||
config.code_cache_size = std::uint32_t(128_MiB);
|
||||
#else
|
||||
config.code_cache_size = std::uint32_t(512_MiB);
|
||||
#endif
|
||||
|
||||
// Allow memory fault handling to work
|
||||
if (m_system.DebuggerEnabled()) {
|
||||
@@ -375,15 +372,11 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa
|
||||
}
|
||||
|
||||
HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Run());
|
||||
}
|
||||
|
||||
HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Step());
|
||||
}
|
||||
@@ -423,7 +416,6 @@ ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProc
|
||||
auto& page_table = process->GetPageTable().GetBasePageTable();
|
||||
auto& page_table_impl = page_table.GetImpl();
|
||||
m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth());
|
||||
ScopedJitExecution::RegisterHandler();
|
||||
}
|
||||
|
||||
ArmDynarmic64::~ArmDynarmic64() = default;
|
||||
|
||||
@@ -60,15 +60,15 @@ constexpr bool IsInvalidCharacterImpl(char c) {
|
||||
} // namespace impl
|
||||
|
||||
constexpr bool IsInvalidCharacter(char c) {
|
||||
return impl::IsInvalidCharacterImpl<InvalidCharacters, Common::Size(InvalidCharacters)>(c);
|
||||
return impl::IsInvalidCharacterImpl<InvalidCharacters, std::size(InvalidCharacters)>(c);
|
||||
}
|
||||
constexpr bool IsInvalidCharacterForHostName(char c) {
|
||||
return impl::IsInvalidCharacterImpl<InvalidCharactersForHostName,
|
||||
Common::Size(InvalidCharactersForHostName)>(c);
|
||||
std::size(InvalidCharactersForHostName)>(c);
|
||||
}
|
||||
constexpr bool IsInvalidCharacterForMountName(char c) {
|
||||
return impl::IsInvalidCharacterImpl<InvalidCharactersForMountName,
|
||||
Common::Size(InvalidCharactersForMountName)>(c);
|
||||
std::size(InvalidCharactersForMountName)>(c);
|
||||
}
|
||||
|
||||
} // namespace StringTraits
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -25,6 +28,9 @@ namespace Kernel {
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO: Remove this workaround when proper ASLR is implemented for all address spaces.
|
||||
constexpr u64 CodeStartOffset = 0x500000UL;
|
||||
|
||||
Result TerminateChildren(KernelCore& kernel, KProcess* process,
|
||||
const KThread* thread_to_not_terminate) {
|
||||
// Request that all children threads terminate.
|
||||
@@ -1195,11 +1201,11 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
|
||||
break;
|
||||
case FileSys::ProgramAddressSpaceType::Is32Bit:
|
||||
flag |= Svc::CreateProcessFlag::AddressSpace32Bit;
|
||||
code_address = 0x20'0000;
|
||||
code_address = 0x20'0000 + CodeStartOffset;
|
||||
break;
|
||||
case FileSys::ProgramAddressSpaceType::Is32BitNoMap:
|
||||
flag |= Svc::CreateProcessFlag::AddressSpace32BitWithoutAlias;
|
||||
code_address = 0x20'0000;
|
||||
code_address = 0x20'0000 + CodeStartOffset;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1266,13 +1272,8 @@ void KProcess::InitializeInterfaces() {
|
||||
|
||||
#ifdef HAS_NCE
|
||||
if (this->IsApplication() && Settings::IsNceEnabled()) {
|
||||
// Register the scoped JIT handler before creating any NCE instances
|
||||
// so that its signal handler will appear first in the signal chain.
|
||||
Core::ScopedJitExecution::RegisterHandler();
|
||||
|
||||
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++)
|
||||
m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (this->Is64Bit()) {
|
||||
|
||||
@@ -359,7 +359,7 @@ struct KernelCore::Impl {
|
||||
static inline thread_local u8 host_thread_id = UINT8_MAX;
|
||||
|
||||
/// Sets the host thread ID for the caller.
|
||||
LTO_NOINLINE u32 SetHostThreadId(std::size_t core_id) {
|
||||
u32 SetHostThreadId(std::size_t core_id) {
|
||||
// This should only be called during core init.
|
||||
ASSERT(host_thread_id == UINT8_MAX);
|
||||
|
||||
@@ -370,17 +370,16 @@ struct KernelCore::Impl {
|
||||
}
|
||||
|
||||
/// Gets the host thread ID for the caller
|
||||
LTO_NOINLINE u32 GetHostThreadId() const {
|
||||
u32 GetHostThreadId() const {
|
||||
return host_thread_id;
|
||||
}
|
||||
|
||||
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
|
||||
LTO_NOINLINE KThread* GetHostDummyThread(KThread* existing_thread) {
|
||||
const auto initialize{[](KThread* thread) LTO_NOINLINE {
|
||||
KThread* GetHostDummyThread(KThread* existing_thread) {
|
||||
const auto initialize{[](KThread* thread) {
|
||||
ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess());
|
||||
return thread;
|
||||
}};
|
||||
|
||||
thread_local KThread raw_thread{system.Kernel()};
|
||||
thread_local KThread* thread = existing_thread ? existing_thread : initialize(&raw_thread);
|
||||
return thread;
|
||||
@@ -410,11 +409,11 @@ struct KernelCore::Impl {
|
||||
|
||||
static inline thread_local bool is_phantom_mode_for_singlecore{false};
|
||||
|
||||
LTO_NOINLINE bool IsPhantomModeForSingleCore() const {
|
||||
bool IsPhantomModeForSingleCore() const {
|
||||
return is_phantom_mode_for_singlecore;
|
||||
}
|
||||
|
||||
LTO_NOINLINE void SetIsPhantomModeForSingleCore(bool value) {
|
||||
void SetIsPhantomModeForSingleCore(bool value) {
|
||||
ASSERT(!is_multicore);
|
||||
is_phantom_mode_for_singlecore = value;
|
||||
}
|
||||
@@ -425,14 +424,14 @@ struct KernelCore::Impl {
|
||||
|
||||
static inline thread_local KThread* current_thread{nullptr};
|
||||
|
||||
LTO_NOINLINE KThread* GetCurrentEmuThread() {
|
||||
KThread* GetCurrentEmuThread() {
|
||||
if (!current_thread) {
|
||||
current_thread = GetHostDummyThread(nullptr);
|
||||
}
|
||||
return current_thread;
|
||||
}
|
||||
|
||||
LTO_NOINLINE void SetCurrentEmuThread(KThread* thread) {
|
||||
void SetCurrentEmuThread(KThread* thread) {
|
||||
current_thread = thread;
|
||||
}
|
||||
|
||||
|
||||
@@ -1828,6 +1828,10 @@ static void SvcWrap_SetProcessMemoryPermission64From32(Core::System& system, std
|
||||
uint64_t size{};
|
||||
MemoryPermission perm{};
|
||||
|
||||
LOG_DEBUG(Kernel_SVC, "Raw args, [0]={:#x} [1]={:#x} [2]={:#x} [3]={:#x} [4]={:#x} [5]={:#x}",
|
||||
GetArg32(args, 0), GetArg32(args, 1), GetArg32(args, 2),
|
||||
GetArg32(args, 3), GetArg32(args, 4), GetArg32(args, 5));
|
||||
|
||||
process_handle = Convert<Handle>(GetArg32(args, 0));
|
||||
std::array<uint32_t, 2> address_gather{};
|
||||
address_gather[0] = GetArg32(args, 2);
|
||||
@@ -1915,6 +1919,10 @@ static void SvcWrap_MapProcessCodeMemory64From32(Core::System& system, std::span
|
||||
uint64_t src_address{};
|
||||
uint64_t size{};
|
||||
|
||||
LOG_DEBUG(Kernel_SVC, "Raw args, [0]={:#x} [1]={:#x} [2]={:#x} [3]={:#x} [4]={:#x} [5]={:#x} [6]={:#x}",
|
||||
GetArg32(args, 0), GetArg32(args, 1), GetArg32(args, 2),
|
||||
GetArg32(args, 3), GetArg32(args, 4), GetArg32(args, 5), GetArg32(args, 6));
|
||||
|
||||
process_handle = Convert<Handle>(GetArg32(args, 0));
|
||||
std::array<uint32_t, 2> dst_address_gather{};
|
||||
dst_address_gather[0] = GetArg32(args, 2);
|
||||
@@ -1942,6 +1950,10 @@ static void SvcWrap_UnmapProcessCodeMemory64From32(Core::System& system, std::sp
|
||||
uint64_t src_address{};
|
||||
uint64_t size{};
|
||||
|
||||
LOG_DEBUG(Kernel_SVC, "Raw args, [0]={:#x} [1]={:#x} [2]={:#x} [3]={:#x} [4]={:#x} [5]={:#x} [6]={:#x}",
|
||||
GetArg32(args, 0), GetArg32(args, 1), GetArg32(args, 2),
|
||||
GetArg32(args, 3), GetArg32(args, 4), GetArg32(args, 5), GetArg32(args, 6));
|
||||
|
||||
process_handle = Convert<Handle>(GetArg32(args, 0));
|
||||
std::array<uint32_t, 2> dst_address_gather{};
|
||||
dst_address_gather[0] = GetArg32(args, 2);
|
||||
@@ -1956,6 +1968,9 @@ static void SvcWrap_UnmapProcessCodeMemory64From32(Core::System& system, std::sp
|
||||
size_gather[1] = GetArg32(args, 6);
|
||||
size = Convert<uint64_t>(size_gather);
|
||||
|
||||
LOG_DEBUG(Kernel_SVC, "Reconstructed, handle={:#x} dst={:#x} src={:#x} size={:#x}",
|
||||
process_handle, dst_address, src_address, size);
|
||||
|
||||
ret = UnmapProcessCodeMemory64From32(system, process_handle, dst_address, src_address, size);
|
||||
|
||||
SetArg32(args, 0, Convert<uint32_t>(ret));
|
||||
|
||||
@@ -10,16 +10,19 @@
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/algorithm/string/find.hpp>
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#include "common/fs/file.h"
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/fs_types.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include <ranges>
|
||||
#include "common/settings.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include <ranges>
|
||||
|
||||
namespace Service::Account {
|
||||
|
||||
@@ -39,6 +42,7 @@ struct ProfileDataRaw {
|
||||
INSERT_PADDING_BYTES(0x10);
|
||||
std::array<UserRaw, MAX_USERS> users{};
|
||||
};
|
||||
|
||||
static_assert(sizeof(ProfileDataRaw) == 0x650, "ProfileDataRaw has incorrect size.");
|
||||
|
||||
// TODO(ogniK): Get actual error codes
|
||||
@@ -490,8 +494,22 @@ void ProfileManager::ResetUserSaveFile()
|
||||
|
||||
std::vector<std::string> ProfileManager::FindGoodProfiles()
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
std::vector<std::string> good_uuids;
|
||||
|
||||
const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir)
|
||||
/ "user/save/0000000000000000";
|
||||
|
||||
// some exceptions because certain games just LOVE TO CAUSE ISSUES
|
||||
static constexpr const std::array<const char* const, 2> EXCEPTION_UUIDS
|
||||
= {"5755CC2A545A87128500000000000000", "00000000000000000000000000000000"};
|
||||
|
||||
for (const char *const uuid : EXCEPTION_UUIDS) {
|
||||
if (fs::exists(path / uuid))
|
||||
good_uuids.emplace_back(uuid);
|
||||
}
|
||||
|
||||
for (const ProfileInfo& p : profiles) {
|
||||
std::string uuid_string = [p]() -> std::string {
|
||||
auto uuid = p.user_uuid;
|
||||
@@ -506,12 +524,9 @@ std::vector<std::string> ProfileManager::FindGoodProfiles()
|
||||
return fmt::format("{:016X}{:016X}", user_id[1], user_id[0]);
|
||||
}();
|
||||
|
||||
good_uuids.emplace_back(uuid_string);
|
||||
if (uuid_string != "0") good_uuids.emplace_back(uuid_string);
|
||||
}
|
||||
|
||||
// used for acnh, etc
|
||||
good_uuids.emplace_back("00000000000000000000000000000000");
|
||||
|
||||
return good_uuids;
|
||||
}
|
||||
|
||||
@@ -519,6 +534,8 @@ std::vector<std::string> ProfileManager::FindOrphanedProfiles()
|
||||
{
|
||||
std::vector<std::string> good_uuids = FindGoodProfiles();
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// TODO: fetch save_id programmatically
|
||||
const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir)
|
||||
/ "user/save/0000000000000000";
|
||||
@@ -530,32 +547,47 @@ std::vector<std::string> ProfileManager::FindOrphanedProfiles()
|
||||
[&good_uuids, &orphaned_profiles](const std::filesystem::directory_entry& entry) -> bool {
|
||||
const std::string uuid = entry.path().stem().string();
|
||||
|
||||
bool override = false;
|
||||
|
||||
// first off, we should always clear empty profiles
|
||||
// 99% of the time these are useless. If not, they are recreated anyways...
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
const auto is_empty = [&entry]() -> bool {
|
||||
const auto is_empty = [&entry, &override]() -> bool {
|
||||
try {
|
||||
for (const auto& file : fs::recursive_directory_iterator(entry.path())) {
|
||||
if (file.is_regular_file()) {
|
||||
return true;
|
||||
}
|
||||
// TODO: .yuzu_save_size is a weird file that gets created by certain games
|
||||
// I have no idea what its purpose is, but TEMPORARY SOLUTION: just mark the profile as valid if
|
||||
// this file exists (???) e.g. for SSBU
|
||||
// In short: if .yuzu_save_size is the ONLY file in a profile it's probably fine to keep
|
||||
if (file.path().filename().string() == FileSys::GetSaveDataSizeFileName())
|
||||
override = true;
|
||||
|
||||
// if there are any regular files (NOT directories) there, do NOT delete it :p
|
||||
if (file.is_regular_file())
|
||||
return false;
|
||||
}
|
||||
} catch (const fs::filesystem_error& e) {
|
||||
// if we get an error--no worries, just pretend it's not empty
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}();
|
||||
|
||||
if (!is_empty) {
|
||||
if (is_empty) {
|
||||
fs::remove_all(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
// edge-case: some filesystems forcefully change filenames to lowercase
|
||||
// so we can just ignore any differences
|
||||
// looking at you microsoft... ;)
|
||||
std::string upper_uuid = uuid;
|
||||
boost::to_upper(upper_uuid);
|
||||
|
||||
// if profiles.dat contains the UUID--all good
|
||||
// if not--it's an orphaned profile and should be resolved by the user
|
||||
if (std::find(good_uuids.begin(), good_uuids.end(), uuid) == good_uuids.end()) {
|
||||
if (!override
|
||||
&& std::find(good_uuids.begin(), good_uuids.end(), upper_uuid) == good_uuids.end()) {
|
||||
orphaned_profiles.emplace_back(uuid);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -69,7 +69,7 @@ enum class FatalType : u32 {
|
||||
static void GenerateErrorReport(Core::System& system, Result error_code, const FatalInfo& info) {
|
||||
const auto title_id = system.GetApplicationProcessProgramID();
|
||||
std::string crash_report = fmt::format(
|
||||
"Yuzu {}-{} crash report\n"
|
||||
"Eden {}-{} crash report\n"
|
||||
"Title ID: {:016x}\n"
|
||||
"Result: {:#X} ({:04}-{:04d})\n"
|
||||
"Set flags: 0x{:16X}\n"
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -70,67 +73,80 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
|
||||
|
||||
system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
|
||||
|
||||
// clang-format off
|
||||
kernel.RunOnHostCoreProcess("audio", [&] { Audio::LoopProcess(system); }).detach();
|
||||
kernel.RunOnHostCoreProcess("FS", [&] { FileSystem::LoopProcess(system); }).detach();
|
||||
kernel.RunOnHostCoreProcess("jit", [&] { JIT::LoopProcess(system); }).detach();
|
||||
kernel.RunOnHostCoreProcess("ldn", [&] { LDN::LoopProcess(system); }).detach();
|
||||
kernel.RunOnHostCoreProcess("Loader", [&] { LDR::LoopProcess(system); }).detach();
|
||||
kernel.RunOnHostCoreProcess("nvservices", [&] { Nvidia::LoopProcess(system); }).detach();
|
||||
kernel.RunOnHostCoreProcess("bsdsocket", [&] { Sockets::LoopProcess(system); }).detach();
|
||||
kernel.RunOnHostCoreProcess("vi", [&, token] { VI::LoopProcess(system, token); }).detach();
|
||||
// Just a quick C++ lesson
|
||||
// Capturing lambdas will silently create new variables for the objects referenced via <ident> = <expr>
|
||||
// and create a `auto&` sorts of for `&`; with all your usual reference shenanigans.
|
||||
// Do not be confused, `std::function<>` will allocate into the heap and will do so most of the time
|
||||
// The heap is where we'd expect our "stored" values to be placed at.
|
||||
//
|
||||
// Eventually we'd need a "heapless" solution so the overhead is nil - but again a good starting point
|
||||
// is removing all the cold clones ;)
|
||||
|
||||
kernel.RunOnGuestCoreProcess("sm", [&] { SM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("account", [&] { Account::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("am", [&] { AM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("aoc", [&] { AOC::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("apm", [&] { APM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("bcat", [&] { BCAT::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("bpc", [&] { BPC::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("btdrv", [&] { BtDrv::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("btm", [&] { BTM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("capsrv", [&] { Capture::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("erpt", [&] { ERPT::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("es", [&] { ES::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("eupld", [&] { EUPLD::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("fatal", [&] { Fatal::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("fgm", [&] { FGM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("friends", [&] { Friend::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("glue", [&] { Glue::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("grc", [&] { GRC::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("hid", [&] { HID::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("lbl", [&] { LBL::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("LogManager.Prod", [&] { LM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("mig", [&] { Migration::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("mii", [&] { Mii::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("mm", [&] { MM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("mnpp", [&] { MNPP::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("nvnflinger", [&] { Nvnflinger::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("NCM", [&] { NCM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("nfc", [&] { NFC::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("nfp", [&] { NFP::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("ngc", [&] { NGC::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("nifm", [&] { NIFM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("nim", [&] { NIM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("npns", [&] { NPNS::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("ns", [&] { NS::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("olsc", [&] { OLSC::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("omm", [&] { OMM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("pcie", [&] { PCIe::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("pctl", [&] { PCTL::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("pcv", [&] { PCV::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("prepo", [&] { PlayReport::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("ro", [&] { RO::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("usb", [&] { USB::LoopProcess(system); });
|
||||
// clang-format on
|
||||
// BEGONE cold clones of lambdas, for I have merged you all into a SINGLE lambda instead of
|
||||
// spamming lambdas like it's some kind of lambda calculus class
|
||||
for (auto const& e : std::vector<std::pair<std::string_view, void (*)(Core::System&)>>{
|
||||
{"audio", &Audio::LoopProcess},
|
||||
{"FS", &FileSystem::LoopProcess},
|
||||
{"jit", &JIT::LoopProcess},
|
||||
{"ldn", &LDN::LoopProcess},
|
||||
{"Loader", &LDR::LoopProcess},
|
||||
{"nvservices", &Nvidia::LoopProcess},
|
||||
{"bsdsocket", &Sockets::LoopProcess},
|
||||
})
|
||||
kernel.RunOnHostCoreProcess(std::string(e.first), [&system, f = e.second] { f(system); }).detach();
|
||||
kernel.RunOnHostCoreProcess("vi", [&, token] { VI::LoopProcess(system, token); }).detach();
|
||||
// Avoid cold clones of lambdas -- succintly
|
||||
for (auto const& e : std::vector<std::pair<std::string_view, void (*)(Core::System&)>>{
|
||||
{"sm", &SM::LoopProcess},
|
||||
{"account", &Account::LoopProcess},
|
||||
{"am", &AM::LoopProcess},
|
||||
{"aoc", &AOC::LoopProcess},
|
||||
{"apm", &APM::LoopProcess},
|
||||
{"bcat", &BCAT::LoopProcess},
|
||||
{"bpc", &BPC::LoopProcess},
|
||||
{"btdrv", &BtDrv::LoopProcess},
|
||||
{"btm", &BTM::LoopProcess},
|
||||
{"capsrv", &Capture::LoopProcess},
|
||||
{"erpt", &ERPT::LoopProcess},
|
||||
{"es", &ES::LoopProcess},
|
||||
{"eupld", &EUPLD::LoopProcess},
|
||||
{"fatal", &Fatal::LoopProcess},
|
||||
{"fgm", &FGM::LoopProcess},
|
||||
{"friends", &Friend::LoopProcess},
|
||||
{"settings", &Set::LoopProcess},
|
||||
{"psc", &PSC::LoopProcess},
|
||||
{"glue", &Glue::LoopProcess},
|
||||
{"grc", &GRC::LoopProcess},
|
||||
{"hid", &HID::LoopProcess},
|
||||
{"lbl", &LBL::LoopProcess},
|
||||
{"LogManager.Prod", &LM::LoopProcess},
|
||||
{"mig", &Migration::LoopProcess},
|
||||
{"mii", &Mii::LoopProcess},
|
||||
{"mm", &MM::LoopProcess},
|
||||
{"mnpp", &MNPP::LoopProcess},
|
||||
{"nvnflinger", &Nvnflinger::LoopProcess},
|
||||
{"NCM", &NCM::LoopProcess},
|
||||
{"nfc", &NFC::LoopProcess},
|
||||
{"nfp", &NFP::LoopProcess},
|
||||
{"ngc", &NGC::LoopProcess},
|
||||
{"nifm", &NIFM::LoopProcess},
|
||||
{"nim", &NIM::LoopProcess},
|
||||
{"npns", &NPNS::LoopProcess},
|
||||
{"ns", &NS::LoopProcess},
|
||||
{"olsc", &OLSC::LoopProcess},
|
||||
{"omm", &OMM::LoopProcess},
|
||||
{"pcie", &PCIe::LoopProcess},
|
||||
{"pctl", &PCTL::LoopProcess},
|
||||
{"pcv", &PCV::LoopProcess},
|
||||
{"prepo", &PlayReport::LoopProcess},
|
||||
{"ProcessManager", &PM::LoopProcess},
|
||||
{"ptm", &PTM::LoopProcess},
|
||||
{"ro", &RO::LoopProcess},
|
||||
{"spl", &SPL::LoopProcess},
|
||||
{"ssl", &SSL::LoopProcess},
|
||||
{"usb", &USB::LoopProcess}
|
||||
})
|
||||
kernel.RunOnGuestCoreProcess(std::string(e.first), [&system, f = e.second] { f(system); });
|
||||
}
|
||||
|
||||
Services::~Services() = default;
|
||||
|
||||
} // namespace Service
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -8,15 +11,13 @@
|
||||
|
||||
namespace Service {
|
||||
|
||||
/**
|
||||
* The purpose of this class is to own any objects that need to be shared across the other service
|
||||
* implementations. Will be torn down when the global system instance is shutdown.
|
||||
*/
|
||||
/// @brief The purpose of this class is to own any objects that need to be shared across the other service
|
||||
/// implementations. Will be torn down when the global system instance is shutdown.
|
||||
class Services final {
|
||||
public:
|
||||
explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,
|
||||
std::stop_token token);
|
||||
~Services();
|
||||
~Services() = default;
|
||||
};
|
||||
|
||||
} // namespace Service
|
||||
|
||||
@@ -1230,22 +1230,7 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
|
||||
if (rasterizer) {
|
||||
impl->InvalidateGPUMemory(ptr, size);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
if (!rasterizer && mapped) {
|
||||
impl->buffer->DeferredMapSeparateHeap(GetInteger(vaddr));
|
||||
}
|
||||
#endif
|
||||
|
||||
return mapped && ptr != nullptr;
|
||||
}
|
||||
|
||||
bool Memory::InvalidateSeparateHeap(void* fault_address) {
|
||||
#ifdef __linux__
|
||||
return impl->buffer->DeferredMapSeparateHeap(static_cast<u8*>(fault_address));
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Core::Memory
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -492,8 +495,6 @@ public:
|
||||
|
||||
bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size);
|
||||
|
||||
bool InvalidateSeparateHeap(void* fault_address);
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
|
||||
|
||||
@@ -137,8 +137,6 @@ endif()
|
||||
|
||||
if ("x86_64" IN_LIST ARCHITECTURE)
|
||||
find_package(xbyak 7 CONFIG)
|
||||
find_package(zycore REQUIRED)
|
||||
find_package(zydis 4 REQUIRED)
|
||||
endif()
|
||||
|
||||
if (DYNARMIC_USE_LLVM)
|
||||
|
||||
@@ -20,7 +20,6 @@ if (NOT @BUILD_SHARED_LIBS@)
|
||||
|
||||
if ("x86_64" IN_LIST ARCHITECTURE)
|
||||
find_dependency(xbyak 7)
|
||||
find_dependency(Zydis 4)
|
||||
endif()
|
||||
|
||||
if (@DYNARMIC_USE_LLVM@)
|
||||
|
||||
@@ -389,30 +389,3 @@ THE POSSIBILITY OF SUCH DAMAGE.
|
||||
損害、間接損害、偶発的な損害、特別損害、懲罰的損害、または結果損害について、
|
||||
一切責任を負わないものとします。
|
||||
```
|
||||
|
||||
### zydis
|
||||
|
||||
```
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2020 Florian Bernd
|
||||
Copyright (c) 2014-2020 Joel Höner
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
14
src/dynarmic/externals/CMakeLists.txt
vendored
@@ -32,17 +32,3 @@ AddJsonPackage(
|
||||
NAME mcl
|
||||
BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS}
|
||||
)
|
||||
|
||||
# TODO(crueter): maybe it's just Gentoo but zydis system package really sucks
|
||||
if ("x86_64" IN_LIST ARCHITECTURE)
|
||||
set(CMAKE_DISABLE_FIND_PACKAGE_Doxygen ON)
|
||||
AddJsonPackage(
|
||||
NAME zycore
|
||||
BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS}
|
||||
)
|
||||
|
||||
AddJsonPackage(
|
||||
NAME zydis
|
||||
BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS}
|
||||
)
|
||||
endif()
|
||||
|
||||
19
src/dynarmic/externals/cpmfile.json
vendored
@@ -17,24 +17,5 @@
|
||||
"patches": [
|
||||
"0001-assert-macro.patch"
|
||||
]
|
||||
},
|
||||
"zycore": {
|
||||
"package": "zycore",
|
||||
"repo": "zyantific/zycore-c",
|
||||
"sha": "75a36c45ae",
|
||||
"hash": "e1cf9bdd3163b6429eba94d0f9f82e343de33b77a838748f598c719913c9f91c502b818e37b716e174b55a3a26cdf39d665c4b50a548255973ac287c0e554fb6"
|
||||
},
|
||||
"zydis": {
|
||||
"package": "zydis",
|
||||
"version": "4",
|
||||
"repo": "zyantific/zydis",
|
||||
"sha": "c2d2bab025",
|
||||
"hash": "3808773593536f78d3ddaf4cf712101d3fb6d981c6cc55555ad686a9adbe3397a727f62f561e8d8755bdcd88a763777da30281cc2924fc160b0386c3f99f5bd9",
|
||||
"options": [
|
||||
"ZYDIS_BUILD_TOOLS OFF",
|
||||
"ZYDIS_BUILD_EXAMPLES OFF",
|
||||
"ZYDIS_BUILD_DOXYGEN OFF",
|
||||
"ZYAN_SYSTEM_ZYCORE ON"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,10 @@ add_library(dynarmic STATIC
|
||||
backend/block_range_information.cpp
|
||||
backend/block_range_information.h
|
||||
backend/exception_handler.h
|
||||
common/always_false.h
|
||||
common/assert.cpp
|
||||
common/assert.h
|
||||
common/type_util.h
|
||||
common/cast_util.h
|
||||
common/common_types.h
|
||||
common/crypto/aes.cpp
|
||||
common/crypto/aes.h
|
||||
@@ -57,14 +58,11 @@ add_library(dynarmic STATIC
|
||||
common/lut_from_list.h
|
||||
common/math_util.cpp
|
||||
common/math_util.h
|
||||
common/memory_pool.cpp
|
||||
common/memory_pool.h
|
||||
common/safe_ops.h
|
||||
common/spin_lock.h
|
||||
common/string_util.h
|
||||
common/u128.cpp
|
||||
common/u128.h
|
||||
common/variant_util.h
|
||||
frontend/A32/a32_types.cpp
|
||||
frontend/A32/a32_types.h
|
||||
frontend/A64/a64_types.cpp
|
||||
@@ -79,7 +77,6 @@ add_library(dynarmic STATIC
|
||||
ir/basic_block.cpp
|
||||
ir/basic_block.h
|
||||
ir/cond.h
|
||||
ir/ir_emitter.cpp
|
||||
ir/ir_emitter.h
|
||||
ir/location_descriptor.cpp
|
||||
ir/location_descriptor.h
|
||||
@@ -147,11 +144,7 @@ if ("x86_64" IN_LIST ARCHITECTURE)
|
||||
target_compile_definitions(dynarmic PRIVATE XBYAK_STRICT_CHECK_MEM_REG_SIZE=0)
|
||||
|
||||
target_compile_definitions(dynarmic PRIVATE XBYAK_OLD_DISP_CHECK=1)
|
||||
target_link_libraries(dynarmic
|
||||
PRIVATE
|
||||
xbyak::xbyak
|
||||
Zydis::Zydis
|
||||
)
|
||||
target_link_libraries(dynarmic PRIVATE xbyak::xbyak)
|
||||
|
||||
target_architecture_specific_sources(dynarmic "x86_64"
|
||||
backend/x64/abi.cpp
|
||||
@@ -195,8 +188,6 @@ if ("x86_64" IN_LIST ARCHITECTURE)
|
||||
backend/x64/verbose_debugging_output.h
|
||||
common/spin_lock_x64.cpp
|
||||
common/spin_lock_x64.h
|
||||
common/x64_disassemble.cpp
|
||||
common/x64_disassemble.h
|
||||
# A32
|
||||
backend/x64/a32_emit_x64.cpp
|
||||
backend/x64/a32_emit_x64.h
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "dynarmic/backend/arm64/devirtualize.h"
|
||||
#include "dynarmic/backend/arm64/emit_arm64.h"
|
||||
#include "dynarmic/backend/arm64/stack_layout.h"
|
||||
#include "dynarmic/common/type_util.h"
|
||||
#include "dynarmic/common/cast_util.h"
|
||||
#include "dynarmic/common/fp/fpcr.h"
|
||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
||||
#include "dynarmic/frontend/A32/translate/a32_translate.h"
|
||||
|
||||
@@ -125,10 +125,6 @@ struct Jit::Impl final {
|
||||
current_state.exclusive_state = false;
|
||||
}
|
||||
|
||||
void DumpDisassembly() const {
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
}
|
||||
|
||||
private:
|
||||
void PerformRequestedCacheInvalidation(HaltReason hr) {
|
||||
if (Has(hr, HaltReason::CacheInvalidation)) {
|
||||
@@ -235,8 +231,4 @@ void Jit::ClearExclusiveState() {
|
||||
impl->ClearExclusiveState();
|
||||
}
|
||||
|
||||
void Jit::DumpDisassembly() const {
|
||||
impl->DumpDisassembly();
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "dynarmic/backend/arm64/devirtualize.h"
|
||||
#include "dynarmic/backend/arm64/emit_arm64.h"
|
||||
#include "dynarmic/backend/arm64/stack_layout.h"
|
||||
#include "dynarmic/common/type_util.h"
|
||||
#include "dynarmic/common/cast_util.h"
|
||||
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
|
||||
#include "dynarmic/frontend/A64/translate/a64_translate.h"
|
||||
#include "dynarmic/interface/A64/config.h"
|
||||
|
||||
@@ -151,12 +151,8 @@ struct Jit::Impl final {
|
||||
return is_executing;
|
||||
}
|
||||
|
||||
void DumpDisassembly() const {
|
||||
current_address_space.DumpDisassembly();
|
||||
}
|
||||
|
||||
std::vector<std::string> Disassemble() const {
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
std::string Disassemble() const {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -315,11 +311,7 @@ bool Jit::IsExecuting() const {
|
||||
return impl->IsExecuting();
|
||||
}
|
||||
|
||||
void Jit::DumpDisassembly() const {
|
||||
impl->DumpDisassembly();
|
||||
}
|
||||
|
||||
std::vector<std::string> Jit::Disassemble() const {
|
||||
std::string Jit::Disassemble() const {
|
||||
return impl->Disassemble();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "dynarmic/common/assert.h"
|
||||
#include <oaknut/oaknut.hpp>
|
||||
|
||||
#include "dynarmic/common/always_false.h"
|
||||
|
||||
namespace Dynarmic::Backend::Arm64 {
|
||||
|
||||
@@ -36,8 +37,7 @@ constexpr auto Rscratch0() {
|
||||
} else if constexpr (bitsize == 64) {
|
||||
return Xscratch0;
|
||||
} else {
|
||||
// TODO: This codepath is regarded as "takeable" on gcc12
|
||||
return Xscratch0; //static_assert(false);
|
||||
static_assert(Common::always_false_v<mcl::mp::lift_value<bitsize>>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,8 +48,7 @@ constexpr auto Rscratch1() {
|
||||
} else if constexpr (bitsize == 64) {
|
||||
return Xscratch1;
|
||||
} else {
|
||||
// TODO: This codepath is regarded as "takeable" on gcc12
|
||||
return Xscratch1; //static_assert(false);
|
||||
static_assert(Common::always_false_v<mcl::mp::lift_value<bitsize>>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,11 +61,7 @@ constexpr RegisterList ToRegList(oaknut::Reg reg) {
|
||||
if (reg.is_vector()) {
|
||||
return RegisterList{1} << (reg.index() + 32);
|
||||
}
|
||||
|
||||
if (reg.index() == 31) {
|
||||
ASSERT_FALSE("ZR not allowed in reg list");
|
||||
}
|
||||
|
||||
ASSERT(reg.index() != 31 && "ZR not allowed in reg list");
|
||||
if (reg.index() == -1) {
|
||||
return RegisterList{1} << 31;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include <bit>
|
||||
#include <numeric>
|
||||
|
||||
#include "dynarmic/backend/arm64/a64_address_space.h"
|
||||
#include "dynarmic/backend/arm64/a64_jitstate.h"
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "dynarmic/backend/arm64/devirtualize.h"
|
||||
#include "dynarmic/backend/arm64/emit_arm64.h"
|
||||
#include "dynarmic/backend/arm64/stack_layout.h"
|
||||
#include "dynarmic/common/type_util.h"
|
||||
#include "dynarmic/common/cast_util.h"
|
||||
#include "dynarmic/common/fp/fpcr.h"
|
||||
#include "dynarmic/common/llvm_disassemble.h"
|
||||
#include "dynarmic/interface/exclusive_monitor.h"
|
||||
@@ -28,7 +28,7 @@ AddressSpace::AddressSpace(size_t code_cache_size)
|
||||
, mem(code_cache_size)
|
||||
, code(mem.ptr(), mem.ptr())
|
||||
, fastmem_manager(exception_handler) {
|
||||
ASSERT_MSG(code_cache_size <= 128 * 1024 * 1024, "code_cache_size > 128 MiB not currently supported");
|
||||
ASSERT(code_cache_size <= 128 * 1024 * 1024 && "code_cache_size > 128 MiB not currently supported");
|
||||
|
||||
exception_handler.Register(mem, code_cache_size);
|
||||
exception_handler.SetFastmemCallback([this](u64 host_pc) {
|
||||
@@ -100,12 +100,6 @@ void AddressSpace::ClearCache() {
|
||||
code.set_offset(prelude_info.end_of_prelude);
|
||||
}
|
||||
|
||||
void AddressSpace::DumpDisassembly() const {
|
||||
for (u32* ptr = mem.ptr(); ptr < code.xptr<u32*>(); ptr++) {
|
||||
std::printf("%s", Common::DisassembleAArch64(*ptr, std::bit_cast<u64>(ptr)).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
size_t AddressSpace::GetRemainingSize() {
|
||||
return code_cache_size - static_cast<size_t>(code.offset());
|
||||
}
|
||||
@@ -264,7 +258,7 @@ void AddressSpace::Link(EmittedBlockInfo& block_info) {
|
||||
c.BL(prelude_info.get_ticks_remaining);
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid relocation target");
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,7 +292,7 @@ void AddressSpace::LinkBlockLinks(const CodePtr entry_point, const CodePtr targe
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid BlockRelocationType");
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,9 +342,9 @@ FakeCall AddressSpace::FastmemCallback(u64 host_pc) {
|
||||
}
|
||||
|
||||
fail:
|
||||
fmt::print("dynarmic: Segfault happened within JITted code at host_pc = {:016x}\n", host_pc);
|
||||
fmt::print("Segfault wasn't at a fastmem patch location!\n");
|
||||
ASSERT_FALSE("segfault");
|
||||
fmt::print("dynarmic: Segfault happened within JITted code at host_pc = {:016x}\n"
|
||||
"Segfault wasn't at a fastmem patch location!\n", host_pc);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::Backend::Arm64
|
||||
|
||||
@@ -44,9 +44,6 @@ public:
|
||||
void InvalidateBasicBlocks(const ankerl::unordered_dense::set<IR::LocationDescriptor>& descriptors);
|
||||
|
||||
void ClearCache();
|
||||
|
||||
void DumpDisassembly() const;
|
||||
|
||||
protected:
|
||||
virtual EmitConfig GetEmitConfig() = 0;
|
||||
virtual void RegisterNewBasicBlock(const IR::Block& block, const EmittedBlockInfo& block_info) = 0;
|
||||
|
||||
@@ -9,12 +9,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <bit>
|
||||
#include <numeric>
|
||||
#include "dynarmic/common/common_types.h"
|
||||
#include <mcl/type_traits/function_info.hpp>
|
||||
|
||||
namespace Dynarmic::Backend::Arm64 {
|
||||
|
||||
namespace impl {
|
||||
template<typename T, typename P> inline T bit_cast_pointee(const P source_ptr) noexcept {
|
||||
std::aligned_storage_t<sizeof(T), alignof(T)> dest;
|
||||
std::memcpy(&dest, std::bit_cast<void*>(source_ptr), sizeof(T));
|
||||
return reinterpret_cast<T&>(dest);
|
||||
}
|
||||
};
|
||||
|
||||
struct DevirtualizedCall {
|
||||
u64 fn_ptr;
|
||||
u64 this_ptr;
|
||||
@@ -43,8 +50,8 @@ DevirtualizedCall DevirtualizeDefault(mcl::class_type<decltype(mfp)>* this_) {
|
||||
u64 fn_ptr = mfp_struct.ptr;
|
||||
u64 this_ptr = std::bit_cast<u64>(this_) + (mfp_struct.adj >> 1);
|
||||
if (mfp_struct.adj & 1) {
|
||||
u64 vtable = std::bit_cast<u64>(this_ptr);
|
||||
fn_ptr = std::bit_cast<u64>(vtable + fn_ptr);
|
||||
u64 vtable = impl::bit_cast_pointee<u64>(this_ptr);
|
||||
fn_ptr = impl::bit_cast_pointee<u64>(vtable + fn_ptr);
|
||||
}
|
||||
return DevirtualizedCall{fn_ptr, this_ptr};
|
||||
}
|
||||
|
||||
@@ -112,8 +112,7 @@ void EmitIR<IR::Opcode::GetNZCVFromOp>(oaknut::CodeGenerator& code, EmitContext&
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT_FALSE("Invalid type for GetNZCVFromOp");
|
||||
break;
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,8 +142,7 @@ void EmitIR<IR::Opcode::GetNZFromOp>(oaknut::CodeGenerator& code, EmitContext& c
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT_FALSE("Invalid type for GetNZFromOp");
|
||||
break;
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,8 +239,7 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E
|
||||
#undef A32OPC
|
||||
#undef A64OPC
|
||||
default:
|
||||
ASSERT_FALSE("Invalid opcode: {:x}", std::size_t(inst->GetOpcode()));
|
||||
break;
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
reg_alloc.UpdateAllUses();
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2022 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
@@ -34,7 +37,7 @@ oaknut::Label EmitA32Cond(oaknut::CodeGenerator& code, EmitContext&, IR::Cond co
|
||||
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
|
||||
|
||||
void EmitA32Terminal(oaknut::CodeGenerator&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) {
|
||||
ASSERT_FALSE("Interpret should never be emitted.");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2022 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
@@ -20,7 +23,8 @@ namespace Dynarmic::Backend::Arm64 {
|
||||
using namespace oaknut::util;
|
||||
|
||||
static void EmitCoprocessorException() {
|
||||
ASSERT_FALSE("Should raise coproc exception here");
|
||||
// TODO: Raise coproc except
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
static void CallCoprocCallback(oaknut::CodeGenerator& code, EmitContext& ctx, A32::Coprocessor::Callback callback, IR::Inst* inst = nullptr, std::optional<Argument::copyable_reference> arg0 = {}, std::optional<Argument::copyable_reference> arg1 = {}) {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
#include <bit>
|
||||
#include <numeric>
|
||||
#include <oaknut/oaknut.hpp>
|
||||
|
||||
#include "dynarmic/backend/arm64/a64_jitstate.h"
|
||||
@@ -37,7 +36,7 @@ oaknut::Label EmitA64Cond(oaknut::CodeGenerator& code, EmitContext&, IR::Cond co
|
||||
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
|
||||
|
||||
void EmitA64Terminal(oaknut::CodeGenerator&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) {
|
||||
ASSERT_FALSE("Interpret should never be emitted.");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2022 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
@@ -117,7 +120,7 @@ void EmitIR<IR::Opcode::SM4AccessSubstitutionBox>(oaknut::CodeGenerator& code, E
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2022 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
@@ -123,11 +126,10 @@ static void EmitToFixed(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst*
|
||||
code.FCVTAS(Rto, Vfrom);
|
||||
break;
|
||||
case FP::RoundingMode::ToOdd:
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid RoundingMode");
|
||||
break;
|
||||
UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
switch (rounding_mode) {
|
||||
@@ -147,11 +149,10 @@ static void EmitToFixed(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst*
|
||||
code.FCVTAU(Rto, Vfrom);
|
||||
break;
|
||||
case FP::RoundingMode::ToOdd:
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid RoundingMode");
|
||||
break;
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,7 +189,7 @@ void EmitIR<IR::Opcode::FPAbs16>(oaknut::CodeGenerator& code, EmitContext& ctx,
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -315,7 +316,7 @@ void EmitIR<IR::Opcode::FPMulAdd16>(oaknut::CodeGenerator& code, EmitContext& ct
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -333,7 +334,7 @@ void EmitIR<IR::Opcode::FPMulSub16>(oaknut::CodeGenerator& code, EmitContext& ct
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -361,7 +362,7 @@ void EmitIR<IR::Opcode::FPNeg16>(oaknut::CodeGenerator& code, EmitContext& ctx,
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -379,7 +380,7 @@ void EmitIR<IR::Opcode::FPRecipEstimate16>(oaknut::CodeGenerator& code, EmitCont
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -397,7 +398,7 @@ void EmitIR<IR::Opcode::FPRecipExponent16>(oaknut::CodeGenerator& code, EmitCont
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -415,7 +416,7 @@ void EmitIR<IR::Opcode::FPRecipStepFused16>(oaknut::CodeGenerator& code, EmitCon
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -433,7 +434,7 @@ void EmitIR<IR::Opcode::FPRoundInt16>(oaknut::CodeGenerator& code, EmitContext&
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -467,9 +468,8 @@ void EmitIR<IR::Opcode::FPRoundInt32>(oaknut::CodeGenerator& code, EmitContext&
|
||||
case FP::RoundingMode::ToNearest_TieAwayFromZero:
|
||||
code.FRINTA(Sresult, Soperand);
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid RoundingMode");
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,7 +505,7 @@ void EmitIR<IR::Opcode::FPRoundInt64>(oaknut::CodeGenerator& code, EmitContext&
|
||||
code.FRINTA(Dresult, Doperand);
|
||||
break;
|
||||
default:
|
||||
ASSERT_FALSE("Invalid RoundingMode");
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -515,7 +515,7 @@ void EmitIR<IR::Opcode::FPRSqrtEstimate16>(oaknut::CodeGenerator& code, EmitCont
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -533,7 +533,7 @@ void EmitIR<IR::Opcode::FPRSqrtStepFused16>(oaknut::CodeGenerator& code, EmitCon
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -647,7 +647,7 @@ void EmitIR<IR::Opcode::FPHalfToFixedS16>(oaknut::CodeGenerator& code, EmitConte
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -655,7 +655,7 @@ void EmitIR<IR::Opcode::FPHalfToFixedS32>(oaknut::CodeGenerator& code, EmitConte
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -663,7 +663,7 @@ void EmitIR<IR::Opcode::FPHalfToFixedS64>(oaknut::CodeGenerator& code, EmitConte
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -671,7 +671,7 @@ void EmitIR<IR::Opcode::FPHalfToFixedU16>(oaknut::CodeGenerator& code, EmitConte
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -679,7 +679,7 @@ void EmitIR<IR::Opcode::FPHalfToFixedU32>(oaknut::CodeGenerator& code, EmitConte
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -687,7 +687,7 @@ void EmitIR<IR::Opcode::FPHalfToFixedU64>(oaknut::CodeGenerator& code, EmitConte
|
||||
(void)code;
|
||||
(void)ctx;
|
||||
(void)inst;
|
||||
ASSERT_FALSE("Unimplemented");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
|
||||