early-access version 3927
This commit is contained in:
parent
91ade31ddd
commit
7fe7262395
29 changed files with 330 additions and 106 deletions
|
@ -53,7 +53,7 @@ option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android"
|
||||||
|
|
||||||
CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF)
|
CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF)
|
||||||
|
|
||||||
CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF)
|
CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
|
||||||
|
|
||||||
option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}")
|
option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}")
|
||||||
|
|
||||||
|
@ -179,9 +179,6 @@ if (YUZU_USE_BUNDLED_VCPKG)
|
||||||
if (YUZU_TESTS)
|
if (YUZU_TESTS)
|
||||||
list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests")
|
list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests")
|
||||||
endif()
|
endif()
|
||||||
if (YUZU_CRASH_DUMPS)
|
|
||||||
list(APPEND VCPKG_MANIFEST_FEATURES "dbghelp")
|
|
||||||
endif()
|
|
||||||
if (ENABLE_WEB_SERVICE)
|
if (ENABLE_WEB_SERVICE)
|
||||||
list(APPEND VCPKG_MANIFEST_FEATURES "web-service")
|
list(APPEND VCPKG_MANIFEST_FEATURES "web-service")
|
||||||
endif()
|
endif()
|
||||||
|
@ -587,6 +584,18 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG)
|
||||||
find_package(FFmpeg 4.3 REQUIRED QUIET COMPONENTS ${FFmpeg_COMPONENTS})
|
find_package(FFmpeg 4.3 REQUIRED QUIET COMPONENTS ${FFmpeg_COMPONENTS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (WIN32 AND YUZU_CRASH_DUMPS)
|
||||||
|
set(BREAKPAD_VER "breakpad-c89f9dd")
|
||||||
|
download_bundled_external("breakpad/" ${BREAKPAD_VER} BREAKPAD_PREFIX)
|
||||||
|
|
||||||
|
set(BREAKPAD_CLIENT_INCLUDE_DIR "${BREAKPAD_PREFIX}/include")
|
||||||
|
set(BREAKPAD_CLIENT_LIBRARY "${BREAKPAD_PREFIX}/lib/libbreakpad_client.lib")
|
||||||
|
|
||||||
|
add_library(libbreakpad_client INTERFACE IMPORTED)
|
||||||
|
target_link_libraries(libbreakpad_client INTERFACE "${BREAKPAD_CLIENT_LIBRARY}")
|
||||||
|
target_include_directories(libbreakpad_client INTERFACE "${BREAKPAD_CLIENT_INCLUDE_DIR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Prefer the -pthread flag on Linux.
|
# Prefer the -pthread flag on Linux.
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
@ -606,13 +615,6 @@ elseif (WIN32)
|
||||||
# PSAPI is the Process Status API
|
# PSAPI is the Process Status API
|
||||||
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version)
|
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (YUZU_CRASH_DUMPS)
|
|
||||||
find_library(DBGHELP_LIBRARY dbghelp)
|
|
||||||
if ("${DBGHELP_LIBRARY}" STREQUAL "DBGHELP_LIBRARY-NOTFOUND")
|
|
||||||
message(FATAL_ERROR "YUZU_CRASH_DUMPS enabled but dbghelp library not found")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$")
|
elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$")
|
||||||
set(PLATFORM_LIBRARIES rt)
|
set(PLATFORM_LIBRARIES rt)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 3926.
|
This is the source code for early-access 3927.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
102
externals/CMakeLists.txt
vendored
102
externals/CMakeLists.txt
vendored
|
@ -185,3 +185,105 @@ if (ANDROID)
|
||||||
add_subdirectory(libadrenotools)
|
add_subdirectory(libadrenotools)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Breakpad
|
||||||
|
# https://github.com/microsoft/vcpkg/blob/master/ports/breakpad/CMakeLists.txt
|
||||||
|
if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client)
|
||||||
|
set(BREAKPAD_WIN32_DEFINES
|
||||||
|
NOMINMAX
|
||||||
|
UNICODE
|
||||||
|
WIN32_LEAN_AND_MEAN
|
||||||
|
_CRT_SECURE_NO_WARNINGS
|
||||||
|
_CRT_SECURE_NO_DEPRECATE
|
||||||
|
_CRT_NONSTDC_NO_DEPRECATE
|
||||||
|
)
|
||||||
|
|
||||||
|
# libbreakpad
|
||||||
|
add_library(libbreakpad STATIC)
|
||||||
|
file(GLOB_RECURSE LIBBREAKPAD_SOURCES breakpad/src/processor/*.cc)
|
||||||
|
file(GLOB_RECURSE LIBDISASM_SOURCES breakpad/src/third_party/libdisasm/*.c)
|
||||||
|
list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "_unittest|_selftest|synth_minidump|/tests|/testdata|/solaris|microdump_stackwalk|minidump_dump|minidump_stackwalk")
|
||||||
|
if (WIN32)
|
||||||
|
list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "/linux|/mac|/android")
|
||||||
|
target_compile_definitions(libbreakpad PRIVATE ${BREAKPAD_WIN32_DEFINES})
|
||||||
|
target_include_directories(libbreakpad PRIVATE "${CMAKE_GENERATOR_INSTANCE}/DIA SDK/include")
|
||||||
|
elseif (APPLE)
|
||||||
|
list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "/linux|/windows|/android")
|
||||||
|
else()
|
||||||
|
list(FILTER LIBBREAKPAD_SOURCES EXCLUDE REGEX "/mac|/windows|/android")
|
||||||
|
endif()
|
||||||
|
target_sources(libbreakpad PRIVATE ${LIBBREAKPAD_SOURCES} ${LIBDISASM_SOURCES})
|
||||||
|
target_include_directories(libbreakpad
|
||||||
|
PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/breakpad/src
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/breakpad/src/third_party/libdisasm
|
||||||
|
)
|
||||||
|
|
||||||
|
# libbreakpad_client
|
||||||
|
add_library(libbreakpad_client STATIC)
|
||||||
|
file(GLOB LIBBREAKPAD_COMMON_SOURCES breakpad/src/common/*.cc breakpad/src/common/*.c breakpad/src/client/*.cc)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
file(GLOB_RECURSE LIBBREAKPAD_CLIENT_SOURCES breakpad/src/client/windows/*.cc breakpad/src/common/windows/*.cc)
|
||||||
|
list(FILTER LIBBREAKPAD_COMMON_SOURCES EXCLUDE REGEX "language.cc|path_helper.cc|stabs_to_module.cc|stabs_reader.cc|minidump_file_writer.cc")
|
||||||
|
target_include_directories(libbreakpad_client PRIVATE "${CMAKE_GENERATOR_INSTANCE}/DIA SDK/include")
|
||||||
|
target_compile_definitions(libbreakpad_client PRIVATE ${BREAKPAD_WIN32_DEFINES})
|
||||||
|
elseif (APPLE)
|
||||||
|
target_compile_definitions(libbreakpad_client PRIVATE HAVE_MACH_O_NLIST_H)
|
||||||
|
file(GLOB_RECURSE LIBBREAKPAD_CLIENT_SOURCES breakpad/src/client/mac/*.cc breakpad/src/common/mac/*.cc)
|
||||||
|
list(APPEND LIBBREAKPAD_CLIENT_SOURCES breakpad/src/common/mac/MachIPC.mm)
|
||||||
|
else()
|
||||||
|
target_compile_definitions(libbreakpad_client PUBLIC -DHAVE_A_OUT_H)
|
||||||
|
file(GLOB_RECURSE LIBBREAKPAD_CLIENT_SOURCES breakpad/src/client/linux/*.cc breakpad/src/common/linux/*.cc)
|
||||||
|
endif()
|
||||||
|
list(APPEND LIBBREAKPAD_CLIENT_SOURCES ${LIBBREAKPAD_COMMON_SOURCES})
|
||||||
|
list(FILTER LIBBREAKPAD_CLIENT_SOURCES EXCLUDE REGEX "/sender|/tests|/unittests|/testcases|_unittest|_test")
|
||||||
|
target_sources(libbreakpad_client PRIVATE ${LIBBREAKPAD_CLIENT_SOURCES})
|
||||||
|
target_include_directories(libbreakpad_client PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/breakpad/src)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
target_link_libraries(libbreakpad_client PRIVATE wininet.lib)
|
||||||
|
elseif (APPLE)
|
||||||
|
find_library(CoreFoundation_FRAMEWORK CoreFoundation)
|
||||||
|
target_link_libraries(libbreakpad_client PRIVATE ${CoreFoundation_FRAMEWORK})
|
||||||
|
else()
|
||||||
|
find_library(PTHREAD_LIBRARIES pthread)
|
||||||
|
target_compile_definitions(libbreakpad_client PRIVATE HAVE_GETCONTEXT=1)
|
||||||
|
if (PTHREAD_LIBRARIES)
|
||||||
|
target_link_libraries(libbreakpad_client PRIVATE ${PTHREAD_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Host tools for symbol processing
|
||||||
|
if (LINUX)
|
||||||
|
find_package(ZLIB REQUIRED)
|
||||||
|
|
||||||
|
add_executable(minidump_stackwalk breakpad/src/processor/minidump_stackwalk.cc)
|
||||||
|
target_link_libraries(minidump_stackwalk PRIVATE libbreakpad libbreakpad_client)
|
||||||
|
|
||||||
|
add_executable(dump_syms
|
||||||
|
breakpad/src/common/dwarf_cfi_to_module.cc
|
||||||
|
breakpad/src/common/dwarf_cu_to_module.cc
|
||||||
|
breakpad/src/common/dwarf_line_to_module.cc
|
||||||
|
breakpad/src/common/dwarf_range_list_handler.cc
|
||||||
|
breakpad/src/common/language.cc
|
||||||
|
breakpad/src/common/module.cc
|
||||||
|
breakpad/src/common/path_helper.cc
|
||||||
|
breakpad/src/common/stabs_reader.cc
|
||||||
|
breakpad/src/common/stabs_to_module.cc
|
||||||
|
breakpad/src/common/dwarf/bytereader.cc
|
||||||
|
breakpad/src/common/dwarf/dwarf2diehandler.cc
|
||||||
|
breakpad/src/common/dwarf/dwarf2reader.cc
|
||||||
|
breakpad/src/common/dwarf/elf_reader.cc
|
||||||
|
breakpad/src/common/linux/crc32.cc
|
||||||
|
breakpad/src/common/linux/dump_symbols.cc
|
||||||
|
breakpad/src/common/linux/elf_symbols_to_module.cc
|
||||||
|
breakpad/src/common/linux/elfutils.cc
|
||||||
|
breakpad/src/common/linux/file_id.cc
|
||||||
|
breakpad/src/common/linux/linux_libc_support.cc
|
||||||
|
breakpad/src/common/linux/memory_mapped_file.cc
|
||||||
|
breakpad/src/common/linux/safe_readlink.cc
|
||||||
|
breakpad/src/tools/linux/dump_syms/dump_syms.cc)
|
||||||
|
target_link_libraries(dump_syms PRIVATE libbreakpad_client ZLIB::ZLIB)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
|
@ -39,8 +39,12 @@
|
||||||
#define Crash() exit(1)
|
#define Crash() exit(1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define LTO_NOINLINE __attribute__((noinline))
|
||||||
|
|
||||||
#else // _MSC_VER
|
#else // _MSC_VER
|
||||||
|
|
||||||
|
#define LTO_NOINLINE
|
||||||
|
|
||||||
// Locale Cross-Compatibility
|
// Locale Cross-Compatibility
|
||||||
#define locale_t _locale_t
|
#define locale_t _locale_t
|
||||||
|
|
||||||
|
|
|
@ -211,6 +211,11 @@ struct Elf64_Rela {
|
||||||
Elf64_Sxword r_addend; /* Addend */
|
Elf64_Sxword r_addend; /* Addend */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* RELR relocation table entry */
|
||||||
|
|
||||||
|
using Elf32_Relr = Elf32_Word;
|
||||||
|
using Elf64_Relr = Elf64_Xword;
|
||||||
|
|
||||||
/* How to extract and insert information held in the r_info field. */
|
/* How to extract and insert information held in the r_info field. */
|
||||||
|
|
||||||
static inline u32 Elf32RelSymIndex(Elf32_Word r_info) {
|
static inline u32 Elf32RelSymIndex(Elf32_Word r_info) {
|
||||||
|
@ -328,6 +333,9 @@ constexpr u32 ElfDtFiniArray = 26; /* Array with addresses of fini fct */
|
||||||
constexpr u32 ElfDtInitArraySz = 27; /* Size in bytes of DT_INIT_ARRAY */
|
constexpr u32 ElfDtInitArraySz = 27; /* Size in bytes of DT_INIT_ARRAY */
|
||||||
constexpr u32 ElfDtFiniArraySz = 28; /* Size in bytes of DT_FINI_ARRAY */
|
constexpr u32 ElfDtFiniArraySz = 28; /* Size in bytes of DT_FINI_ARRAY */
|
||||||
constexpr u32 ElfDtSymtabShndx = 34; /* Address of SYMTAB_SHNDX section */
|
constexpr u32 ElfDtSymtabShndx = 34; /* Address of SYMTAB_SHNDX section */
|
||||||
|
constexpr u32 ElfDtRelrsz = 35; /* Size of RELR relative relocations */
|
||||||
|
constexpr u32 ElfDtRelr = 36; /* Address of RELR relative relocations */
|
||||||
|
constexpr u32 ElfDtRelrent = 37; /* Size of one RELR relative relocation */
|
||||||
|
|
||||||
} // namespace ELF
|
} // namespace ELF
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#define AMIIBO_DIR "amiibo"
|
#define AMIIBO_DIR "amiibo"
|
||||||
#define CACHE_DIR "cache"
|
#define CACHE_DIR "cache"
|
||||||
#define CONFIG_DIR "config"
|
#define CONFIG_DIR "config"
|
||||||
|
#define CRASH_DUMPS_DIR "crash_dumps"
|
||||||
#define DUMP_DIR "dump"
|
#define DUMP_DIR "dump"
|
||||||
#define KEYS_DIR "keys"
|
#define KEYS_DIR "keys"
|
||||||
#define LOAD_DIR "load"
|
#define LOAD_DIR "load"
|
||||||
|
|
|
@ -119,6 +119,7 @@ public:
|
||||||
GenerateYuzuPath(YuzuPath::AmiiboDir, yuzu_path / AMIIBO_DIR);
|
GenerateYuzuPath(YuzuPath::AmiiboDir, yuzu_path / AMIIBO_DIR);
|
||||||
GenerateYuzuPath(YuzuPath::CacheDir, yuzu_path_cache);
|
GenerateYuzuPath(YuzuPath::CacheDir, yuzu_path_cache);
|
||||||
GenerateYuzuPath(YuzuPath::ConfigDir, yuzu_path_config);
|
GenerateYuzuPath(YuzuPath::ConfigDir, yuzu_path_config);
|
||||||
|
GenerateYuzuPath(YuzuPath::CrashDumpsDir, yuzu_path / CRASH_DUMPS_DIR);
|
||||||
GenerateYuzuPath(YuzuPath::DumpDir, yuzu_path / DUMP_DIR);
|
GenerateYuzuPath(YuzuPath::DumpDir, yuzu_path / DUMP_DIR);
|
||||||
GenerateYuzuPath(YuzuPath::KeysDir, yuzu_path / KEYS_DIR);
|
GenerateYuzuPath(YuzuPath::KeysDir, yuzu_path / KEYS_DIR);
|
||||||
GenerateYuzuPath(YuzuPath::LoadDir, yuzu_path / LOAD_DIR);
|
GenerateYuzuPath(YuzuPath::LoadDir, yuzu_path / LOAD_DIR);
|
||||||
|
|
|
@ -15,6 +15,7 @@ enum class YuzuPath {
|
||||||
AmiiboDir, // Where Amiibo backups are stored.
|
AmiiboDir, // Where Amiibo backups are stored.
|
||||||
CacheDir, // Where cached filesystem data is stored.
|
CacheDir, // Where cached filesystem data is stored.
|
||||||
ConfigDir, // Where config files are stored.
|
ConfigDir, // Where config files are stored.
|
||||||
|
CrashDumpsDir, // Where crash dumps are stored.
|
||||||
DumpDir, // Where dumped data is stored.
|
DumpDir, // Where dumped data is stored.
|
||||||
KeysDir, // Where key files are stored.
|
KeysDir, // Where key files are stored.
|
||||||
LoadDir, // Where cheat/mod files are stored.
|
LoadDir, // Where cheat/mod files are stored.
|
||||||
|
|
|
@ -502,7 +502,6 @@ struct Values {
|
||||||
linkage, false, "use_auto_stub", Category::Debugging, Specialization::Default, false};
|
linkage, false, "use_auto_stub", Category::Debugging, Specialization::Default, false};
|
||||||
Setting<bool> enable_all_controllers{linkage, false, "enable_all_controllers",
|
Setting<bool> enable_all_controllers{linkage, false, "enable_all_controllers",
|
||||||
Category::Debugging};
|
Category::Debugging};
|
||||||
Setting<bool> create_crash_dumps{linkage, false, "create_crash_dumps", Category::Debugging};
|
|
||||||
Setting<bool> perform_vulkan_check{linkage, true, "perform_vulkan_check", Category::Debugging};
|
Setting<bool> perform_vulkan_check{linkage, true, "perform_vulkan_check", Category::Debugging};
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
|
|
|
@ -373,7 +373,7 @@ struct KernelCore::Impl {
|
||||||
static inline thread_local u8 host_thread_id = UINT8_MAX;
|
static inline thread_local u8 host_thread_id = UINT8_MAX;
|
||||||
|
|
||||||
/// Sets the host thread ID for the caller.
|
/// Sets the host thread ID for the caller.
|
||||||
u32 SetHostThreadId(std::size_t core_id) {
|
LTO_NOINLINE u32 SetHostThreadId(std::size_t core_id) {
|
||||||
// This should only be called during core init.
|
// This should only be called during core init.
|
||||||
ASSERT(host_thread_id == UINT8_MAX);
|
ASSERT(host_thread_id == UINT8_MAX);
|
||||||
|
|
||||||
|
@ -384,13 +384,13 @@ struct KernelCore::Impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the host thread ID for the caller
|
/// Gets the host thread ID for the caller
|
||||||
u32 GetHostThreadId() const {
|
LTO_NOINLINE u32 GetHostThreadId() const {
|
||||||
return host_thread_id;
|
return host_thread_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
|
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
|
||||||
KThread* GetHostDummyThread(KThread* existing_thread) {
|
LTO_NOINLINE KThread* GetHostDummyThread(KThread* existing_thread) {
|
||||||
const auto initialize{[](KThread* thread) {
|
const auto initialize{[](KThread* thread) LTO_NOINLINE {
|
||||||
ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess());
|
ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess());
|
||||||
return thread;
|
return thread;
|
||||||
}};
|
}};
|
||||||
|
@ -424,11 +424,11 @@ struct KernelCore::Impl {
|
||||||
|
|
||||||
static inline thread_local bool is_phantom_mode_for_singlecore{false};
|
static inline thread_local bool is_phantom_mode_for_singlecore{false};
|
||||||
|
|
||||||
bool IsPhantomModeForSingleCore() const {
|
LTO_NOINLINE bool IsPhantomModeForSingleCore() const {
|
||||||
return is_phantom_mode_for_singlecore;
|
return is_phantom_mode_for_singlecore;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetIsPhantomModeForSingleCore(bool value) {
|
LTO_NOINLINE void SetIsPhantomModeForSingleCore(bool value) {
|
||||||
ASSERT(!is_multicore);
|
ASSERT(!is_multicore);
|
||||||
is_phantom_mode_for_singlecore = value;
|
is_phantom_mode_for_singlecore = value;
|
||||||
}
|
}
|
||||||
|
@ -439,14 +439,14 @@ struct KernelCore::Impl {
|
||||||
|
|
||||||
static inline thread_local KThread* current_thread{nullptr};
|
static inline thread_local KThread* current_thread{nullptr};
|
||||||
|
|
||||||
KThread* GetCurrentEmuThread() {
|
LTO_NOINLINE KThread* GetCurrentEmuThread() {
|
||||||
if (!current_thread) {
|
if (!current_thread) {
|
||||||
current_thread = GetHostDummyThread(nullptr);
|
current_thread = GetHostDummyThread(nullptr);
|
||||||
}
|
}
|
||||||
return current_thread;
|
return current_thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetCurrentEmuThread(KThread* thread) {
|
LTO_NOINLINE void SetCurrentEmuThread(KThread* thread) {
|
||||||
current_thread = thread;
|
current_thread = thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, Albu
|
||||||
|
|
||||||
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
|
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
|
||||||
ContentType contex_type, s64 start_posix_time,
|
ContentType contex_type, s64 start_posix_time,
|
||||||
s64 end_posix_time, u64 aruid) {
|
s64 end_posix_time, u64 aruid) const {
|
||||||
if (!is_mounted) {
|
if (!is_mounted) {
|
||||||
return ResultIsNotMounted;
|
return ResultIsNotMounted;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou
|
||||||
|
|
||||||
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
|
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
|
||||||
ContentType contex_type, AlbumFileDateTime start_date,
|
ContentType contex_type, AlbumFileDateTime start_date,
|
||||||
AlbumFileDateTime end_date, u64 aruid) {
|
AlbumFileDateTime end_date, u64 aruid) const {
|
||||||
if (!is_mounted) {
|
if (!is_mounted) {
|
||||||
return ResultIsNotMounted;
|
return ResultIsNotMounted;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,10 +46,10 @@ public:
|
||||||
u8 flags) const;
|
u8 flags) const;
|
||||||
Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
|
Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
|
||||||
ContentType contex_type, s64 start_posix_time, s64 end_posix_time,
|
ContentType contex_type, s64 start_posix_time, s64 end_posix_time,
|
||||||
u64 aruid);
|
u64 aruid) const;
|
||||||
Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
|
Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
|
||||||
ContentType contex_type, AlbumFileDateTime start_date,
|
ContentType contex_type, AlbumFileDateTime start_date,
|
||||||
AlbumFileDateTime end_date, u64 aruid);
|
AlbumFileDateTime end_date, u64 aruid) const;
|
||||||
Result GetAutoSavingStorage(bool& out_is_autosaving) const;
|
Result GetAutoSavingStorage(bool& out_is_autosaving) const;
|
||||||
Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
|
Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
|
||||||
std::vector<u8>& out_image, const AlbumFileId& file_id,
|
std::vector<u8>& out_image, const AlbumFileId& file_id,
|
||||||
|
|
|
@ -156,6 +156,8 @@ public:
|
||||||
|
|
||||||
bool LoadNRO(std::span<const u8> data) {
|
bool LoadNRO(std::span<const u8> data) {
|
||||||
local_memory.clear();
|
local_memory.clear();
|
||||||
|
|
||||||
|
relocbase = local_memory.size();
|
||||||
local_memory.insert(local_memory.end(), data.begin(), data.end());
|
local_memory.insert(local_memory.end(), data.begin(), data.end());
|
||||||
|
|
||||||
if (FixupRelocations()) {
|
if (FixupRelocations()) {
|
||||||
|
@ -181,8 +183,8 @@ public:
|
||||||
// https://refspecs.linuxbase.org/elf/gabi4+/ch5.dynamic.html
|
// https://refspecs.linuxbase.org/elf/gabi4+/ch5.dynamic.html
|
||||||
// https://refspecs.linuxbase.org/elf/gabi4+/ch4.reloc.html
|
// https://refspecs.linuxbase.org/elf/gabi4+/ch4.reloc.html
|
||||||
VAddr dynamic_offset{mod_offset + callbacks->MemoryRead32(mod_offset + 4)};
|
VAddr dynamic_offset{mod_offset + callbacks->MemoryRead32(mod_offset + 4)};
|
||||||
VAddr rela_dyn = 0;
|
VAddr rela_dyn = 0, relr_dyn = 0;
|
||||||
size_t num_rela = 0;
|
size_t num_rela = 0, num_relr = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
const auto dyn{callbacks->ReadMemory<Elf64_Dyn>(dynamic_offset)};
|
const auto dyn{callbacks->ReadMemory<Elf64_Dyn>(dynamic_offset)};
|
||||||
dynamic_offset += sizeof(Elf64_Dyn);
|
dynamic_offset += sizeof(Elf64_Dyn);
|
||||||
|
@ -196,6 +198,12 @@ public:
|
||||||
if (dyn.d_tag == ElfDtRelasz) {
|
if (dyn.d_tag == ElfDtRelasz) {
|
||||||
num_rela = dyn.d_un.d_val / sizeof(Elf64_Rela);
|
num_rela = dyn.d_un.d_val / sizeof(Elf64_Rela);
|
||||||
}
|
}
|
||||||
|
if (dyn.d_tag == ElfDtRelr) {
|
||||||
|
relr_dyn = dyn.d_un.d_ptr;
|
||||||
|
}
|
||||||
|
if (dyn.d_tag == ElfDtRelrsz) {
|
||||||
|
num_relr = dyn.d_un.d_val / sizeof(Elf64_Relr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < num_rela; i++) {
|
for (size_t i = 0; i < num_rela; i++) {
|
||||||
|
@ -207,6 +215,29 @@ public:
|
||||||
callbacks->MemoryWrite64(rela.r_offset, contents + rela.r_addend);
|
callbacks->MemoryWrite64(rela.r_offset, contents + rela.r_addend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VAddr relr_where = 0;
|
||||||
|
for (size_t i = 0; i < num_relr; i++) {
|
||||||
|
const auto relr{callbacks->ReadMemory<Elf64_Relr>(relr_dyn + i * sizeof(Elf64_Relr))};
|
||||||
|
const auto incr{[&](VAddr where) {
|
||||||
|
callbacks->MemoryWrite64(where, callbacks->MemoryRead64(where) + relocbase);
|
||||||
|
}};
|
||||||
|
|
||||||
|
if ((relr & 1) == 0) {
|
||||||
|
// where pointer
|
||||||
|
relr_where = relocbase + relr;
|
||||||
|
incr(relr_where);
|
||||||
|
relr_where += sizeof(Elf64_Addr);
|
||||||
|
} else {
|
||||||
|
// bitmap
|
||||||
|
for (int bit = 1; bit < 64; bit++) {
|
||||||
|
if ((relr & (1ULL << bit)) != 0) {
|
||||||
|
incr(relr_where + i * sizeof(Elf64_Addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
relr_where += 63 * sizeof(Elf64_Addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,6 +344,7 @@ public:
|
||||||
Core::Memory::Memory& memory;
|
Core::Memory::Memory& memory;
|
||||||
VAddr top_of_stack;
|
VAddr top_of_stack;
|
||||||
VAddr heap_pointer;
|
VAddr heap_pointer;
|
||||||
|
VAddr relocbase;
|
||||||
};
|
};
|
||||||
|
|
||||||
void DynarmicCallbacks64::CallSVC(u32 swi) {
|
void DynarmicCallbacks64::CallSVC(u32 swi) {
|
||||||
|
|
|
@ -62,7 +62,11 @@ using BufferId = SlotId;
|
||||||
using VideoCore::Surface::PixelFormat;
|
using VideoCore::Surface::PixelFormat;
|
||||||
using namespace Common::Literals;
|
using namespace Common::Literals;
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
constexpr u32 NUM_VERTEX_BUFFERS = 16;
|
||||||
|
#else
|
||||||
constexpr u32 NUM_VERTEX_BUFFERS = 32;
|
constexpr u32 NUM_VERTEX_BUFFERS = 32;
|
||||||
|
#endif
|
||||||
constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4;
|
constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4;
|
||||||
constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18;
|
constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18;
|
||||||
constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8;
|
constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8;
|
||||||
|
|
|
@ -3,16 +3,16 @@
|
||||||
|
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
|
precision mediump int;
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
layout(binding = 0) uniform sampler2D depth_tex;
|
layout(binding = 0) uniform sampler2D depth_tex;
|
||||||
layout(binding = 1) uniform isampler2D stencil_tex;
|
layout(binding = 1) uniform usampler2D stencil_tex;
|
||||||
|
|
||||||
layout(location = 0) out vec4 color;
|
layout(location = 0) out vec4 color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
ivec2 coord = ivec2(gl_FragCoord.xy);
|
ivec2 coord = ivec2(gl_FragCoord.xy);
|
||||||
uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
|
|
||||||
uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
|
|
||||||
|
|
||||||
highp uint depth_val =
|
highp uint depth_val =
|
||||||
uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0));
|
uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0));
|
||||||
lowp uint stencil_val = textureLod(stencil_tex, coord, 0).r;
|
lowp uint stencil_val = textureLod(stencil_tex, coord, 0).r;
|
||||||
|
|
|
@ -3,16 +3,16 @@
|
||||||
|
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
|
precision mediump int;
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
layout(binding = 0) uniform sampler2D depth_tex;
|
layout(binding = 0) uniform sampler2D depth_tex;
|
||||||
layout(binding = 1) uniform isampler2D stencil_tex;
|
layout(binding = 1) uniform usampler2D stencil_tex;
|
||||||
|
|
||||||
layout(location = 0) out vec4 color;
|
layout(location = 0) out vec4 color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
ivec2 coord = ivec2(gl_FragCoord.xy);
|
ivec2 coord = ivec2(gl_FragCoord.xy);
|
||||||
uint depth = uint(textureLod(depth_tex, coord, 0).r * (exp2(24.0) - 1.0f));
|
|
||||||
uint stencil = uint(textureLod(stencil_tex, coord, 0).r);
|
|
||||||
|
|
||||||
highp uint depth_val =
|
highp uint depth_val =
|
||||||
uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0));
|
uint(textureLod(depth_tex, coord, 0).r * (exp2(32.0) - 1.0));
|
||||||
lowp uint stencil_val = textureLod(stencil_tex, coord, 0).r;
|
lowp uint stencil_val = textureLod(stencil_tex, coord, 0).r;
|
||||||
|
|
|
@ -1436,6 +1436,7 @@ void QueryCacheRuntime::Barriers(bool is_prebarrier) {
|
||||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||||
};
|
};
|
||||||
|
impl->scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
if (is_prebarrier) {
|
if (is_prebarrier) {
|
||||||
impl->scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
impl->scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||||
|
|
|
@ -975,6 +975,19 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
|
||||||
if (!state_tracker.TouchScissors()) {
|
if (!state_tracker.TouchScissors()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!regs.viewport_scale_offset_enabled) {
|
||||||
|
const auto x = static_cast<float>(regs.surface_clip.x);
|
||||||
|
const auto y = static_cast<float>(regs.surface_clip.y);
|
||||||
|
const auto width = static_cast<float>(regs.surface_clip.width);
|
||||||
|
const auto height = static_cast<float>(regs.surface_clip.height);
|
||||||
|
VkRect2D scissor;
|
||||||
|
scissor.offset.x = static_cast<u32>(x);
|
||||||
|
scissor.offset.y = static_cast<u32>(y);
|
||||||
|
scissor.extent.width = static_cast<u32>(width != 0.0f ? width : 1.0f);
|
||||||
|
scissor.extent.height = static_cast<u32>(height != 0.0f ? height : 1.0f);
|
||||||
|
scheduler.Record([scissor](vk::CommandBuffer cmdbuf) { cmdbuf.SetScissor(0, scissor); });
|
||||||
|
return;
|
||||||
|
}
|
||||||
u32 up_scale = 1;
|
u32 up_scale = 1;
|
||||||
u32 down_shift = 0;
|
u32 down_shift = 0;
|
||||||
if (texture_cache.IsRescaling()) {
|
if (texture_cache.IsRescaling()) {
|
||||||
|
|
|
@ -19,7 +19,7 @@ VkAttachmentDescription AttachmentDescription(const Device& device, PixelFormat
|
||||||
VkSampleCountFlagBits samples) {
|
VkSampleCountFlagBits samples) {
|
||||||
using MaxwellToVK::SurfaceFormat;
|
using MaxwellToVK::SurfaceFormat;
|
||||||
return {
|
return {
|
||||||
.flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT,
|
.flags = {},
|
||||||
.format = SurfaceFormat(device, FormatType::Optimal, true, format).format,
|
.format = SurfaceFormat(device, FormatType::Optimal, true, format).format,
|
||||||
.samples = samples,
|
.samples = samples,
|
||||||
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
|
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
|
|
|
@ -10,19 +10,23 @@
|
||||||
#include "video_core/texture_cache/image_info.h"
|
#include "video_core/texture_cache/image_info.h"
|
||||||
#include "video_core/texture_cache/image_view_base.h"
|
#include "video_core/texture_cache/image_view_base.h"
|
||||||
#include "video_core/texture_cache/render_targets.h"
|
#include "video_core/texture_cache/render_targets.h"
|
||||||
|
#include "video_core/texture_cache/samples_helper.h"
|
||||||
|
|
||||||
namespace VideoCommon {
|
namespace VideoCommon {
|
||||||
|
|
||||||
std::string Name(const ImageBase& image) {
|
std::string Name(const ImageBase& image) {
|
||||||
const GPUVAddr gpu_addr = image.gpu_addr;
|
const GPUVAddr gpu_addr = image.gpu_addr;
|
||||||
const ImageInfo& info = image.info;
|
const ImageInfo& info = image.info;
|
||||||
const u32 width = info.size.width;
|
u32 width = info.size.width;
|
||||||
const u32 height = info.size.height;
|
u32 height = info.size.height;
|
||||||
const u32 depth = info.size.depth;
|
const u32 depth = info.size.depth;
|
||||||
const u32 num_layers = image.info.resources.layers;
|
const u32 num_layers = image.info.resources.layers;
|
||||||
const u32 num_levels = image.info.resources.levels;
|
const u32 num_levels = image.info.resources.levels;
|
||||||
std::string resource;
|
std::string resource;
|
||||||
if (image.info.num_samples > 1) {
|
if (image.info.num_samples > 1) {
|
||||||
|
const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(image.info.num_samples);
|
||||||
|
width >>= samples_x;
|
||||||
|
height >>= samples_y;
|
||||||
resource += fmt::format(":{}xMSAA", image.info.num_samples);
|
resource += fmt::format(":{}xMSAA", image.info.num_samples);
|
||||||
}
|
}
|
||||||
if (num_layers > 1) {
|
if (num_layers > 1) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace VideoCommon {
|
||||||
return {2, 2};
|
return {2, 2};
|
||||||
}
|
}
|
||||||
ASSERT_MSG(false, "Invalid number of samples={}", num_samples);
|
ASSERT_MSG(false, "Invalid number of samples={}", num_samples);
|
||||||
return {1, 1};
|
return {0, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline int NumSamples(Tegra::Texture::MsaaMode msaa_mode) {
|
[[nodiscard]] inline int NumSamples(Tegra::Texture::MsaaMode msaa_mode) {
|
||||||
|
|
|
@ -68,7 +68,6 @@ struct LevelInfo {
|
||||||
Extent2D tile_size;
|
Extent2D tile_size;
|
||||||
u32 bpp_log2;
|
u32 bpp_log2;
|
||||||
u32 tile_width_spacing;
|
u32 tile_width_spacing;
|
||||||
u32 num_levels;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] constexpr u32 AdjustTileSize(u32 shift, u32 unit_factor, u32 dimension) {
|
[[nodiscard]] constexpr u32 AdjustTileSize(u32 shift, u32 unit_factor, u32 dimension) {
|
||||||
|
@ -119,11 +118,11 @@ template <u32 GOB_EXTENT>
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr Extent3D AdjustMipBlockSize(Extent3D num_tiles, Extent3D block_size,
|
[[nodiscard]] constexpr Extent3D AdjustMipBlockSize(Extent3D num_tiles, Extent3D block_size,
|
||||||
u32 level, u32 num_levels) {
|
u32 level) {
|
||||||
return {
|
return {
|
||||||
.width = AdjustMipBlockSize<GOB_SIZE_X>(num_tiles.width, block_size.width, level),
|
.width = AdjustMipBlockSize<GOB_SIZE_X>(num_tiles.width, block_size.width, level),
|
||||||
.height = AdjustMipBlockSize<GOB_SIZE_Y>(num_tiles.height, block_size.height, level),
|
.height = AdjustMipBlockSize<GOB_SIZE_Y>(num_tiles.height, block_size.height, level),
|
||||||
.depth = level == 0 && num_levels == 1
|
.depth = level == 0
|
||||||
? block_size.depth
|
? block_size.depth
|
||||||
: AdjustMipBlockSize<GOB_SIZE_Z>(num_tiles.depth, block_size.depth, level),
|
: AdjustMipBlockSize<GOB_SIZE_Z>(num_tiles.depth, block_size.depth, level),
|
||||||
};
|
};
|
||||||
|
@ -167,6 +166,13 @@ template <u32 GOB_EXTENT>
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr Extent3D TileShift(const LevelInfo& info, u32 level) {
|
[[nodiscard]] constexpr Extent3D TileShift(const LevelInfo& info, u32 level) {
|
||||||
|
if (level == 0) {
|
||||||
|
return Extent3D{
|
||||||
|
.width = info.block.width,
|
||||||
|
.height = info.block.height,
|
||||||
|
.depth = info.block.depth,
|
||||||
|
};
|
||||||
|
}
|
||||||
const Extent3D blocks = NumLevelBlocks(info, level);
|
const Extent3D blocks = NumLevelBlocks(info, level);
|
||||||
return Extent3D{
|
return Extent3D{
|
||||||
.width = AdjustTileSize(info.block.width, GOB_SIZE_X, blocks.width),
|
.width = AdjustTileSize(info.block.width, GOB_SIZE_X, blocks.width),
|
||||||
|
@ -251,7 +257,7 @@ template <u32 GOB_EXTENT>
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr LevelInfo MakeLevelInfo(PixelFormat format, Extent3D size, Extent3D block,
|
[[nodiscard]] constexpr LevelInfo MakeLevelInfo(PixelFormat format, Extent3D size, Extent3D block,
|
||||||
u32 tile_width_spacing, u32 num_levels) {
|
u32 tile_width_spacing) {
|
||||||
const u32 bytes_per_block = BytesPerBlock(format);
|
const u32 bytes_per_block = BytesPerBlock(format);
|
||||||
return {
|
return {
|
||||||
.size =
|
.size =
|
||||||
|
@ -264,18 +270,16 @@ template <u32 GOB_EXTENT>
|
||||||
.tile_size = DefaultBlockSize(format),
|
.tile_size = DefaultBlockSize(format),
|
||||||
.bpp_log2 = BytesPerBlockLog2(bytes_per_block),
|
.bpp_log2 = BytesPerBlockLog2(bytes_per_block),
|
||||||
.tile_width_spacing = tile_width_spacing,
|
.tile_width_spacing = tile_width_spacing,
|
||||||
.num_levels = num_levels,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr LevelInfo MakeLevelInfo(const ImageInfo& info) {
|
[[nodiscard]] constexpr LevelInfo MakeLevelInfo(const ImageInfo& info) {
|
||||||
return MakeLevelInfo(info.format, info.size, info.block, info.tile_width_spacing,
|
return MakeLevelInfo(info.format, info.size, info.block, info.tile_width_spacing);
|
||||||
info.resources.levels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr u32 CalculateLevelOffset(PixelFormat format, Extent3D size, Extent3D block,
|
[[nodiscard]] constexpr u32 CalculateLevelOffset(PixelFormat format, Extent3D size, Extent3D block,
|
||||||
u32 tile_width_spacing, u32 level) {
|
u32 tile_width_spacing, u32 level) {
|
||||||
const LevelInfo info = MakeLevelInfo(format, size, block, tile_width_spacing, level);
|
const LevelInfo info = MakeLevelInfo(format, size, block, tile_width_spacing);
|
||||||
u32 offset = 0;
|
u32 offset = 0;
|
||||||
for (u32 current_level = 0; current_level < level; ++current_level) {
|
for (u32 current_level = 0; current_level < level; ++current_level) {
|
||||||
offset += CalculateLevelSize(info, current_level);
|
offset += CalculateLevelSize(info, current_level);
|
||||||
|
@ -462,7 +466,7 @@ template <u32 GOB_EXTENT>
|
||||||
};
|
};
|
||||||
const u32 bpp_log2 = BytesPerBlockLog2(info.format);
|
const u32 bpp_log2 = BytesPerBlockLog2(info.format);
|
||||||
const u32 alignment = StrideAlignment(num_tiles, info.block, bpp_log2, info.tile_width_spacing);
|
const u32 alignment = StrideAlignment(num_tiles, info.block, bpp_log2, info.tile_width_spacing);
|
||||||
const Extent3D mip_block = AdjustMipBlockSize(num_tiles, info.block, 0, info.resources.levels);
|
const Extent3D mip_block = AdjustMipBlockSize(num_tiles, info.block, 0);
|
||||||
return Extent3D{
|
return Extent3D{
|
||||||
.width = Common::AlignUpLog2(num_tiles.width, alignment),
|
.width = Common::AlignUpLog2(num_tiles.width, alignment),
|
||||||
.height = Common::AlignUpLog2(num_tiles.height, GOB_SIZE_Y_SHIFT + mip_block.height),
|
.height = Common::AlignUpLog2(num_tiles.height, GOB_SIZE_Y_SHIFT + mip_block.height),
|
||||||
|
@ -529,8 +533,7 @@ void SwizzleBlockLinearImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr
|
||||||
UNIMPLEMENTED_IF(copy.image_extent != level_size);
|
UNIMPLEMENTED_IF(copy.image_extent != level_size);
|
||||||
|
|
||||||
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
|
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
|
||||||
const Extent3D block =
|
const Extent3D block = AdjustMipBlockSize(num_tiles, level_info.block, level);
|
||||||
AdjustMipBlockSize(num_tiles, level_info.block, level, level_info.num_levels);
|
|
||||||
|
|
||||||
size_t host_offset = copy.buffer_offset;
|
size_t host_offset = copy.buffer_offset;
|
||||||
|
|
||||||
|
@ -695,7 +698,7 @@ u32 CalculateLevelStrideAlignment(const ImageInfo& info, u32 level) {
|
||||||
const Extent2D tile_size = DefaultBlockSize(info.format);
|
const Extent2D tile_size = DefaultBlockSize(info.format);
|
||||||
const Extent3D level_size = AdjustMipSize(info.size, level);
|
const Extent3D level_size = AdjustMipSize(info.size, level);
|
||||||
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
|
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
|
||||||
const Extent3D block = AdjustMipBlockSize(num_tiles, info.block, level, info.resources.levels);
|
const Extent3D block = AdjustMipBlockSize(num_tiles, info.block, level);
|
||||||
const u32 bpp_log2 = BytesPerBlockLog2(info.format);
|
const u32 bpp_log2 = BytesPerBlockLog2(info.format);
|
||||||
return StrideAlignment(num_tiles, block, bpp_log2, info.tile_width_spacing);
|
return StrideAlignment(num_tiles, block, bpp_log2, info.tile_width_spacing);
|
||||||
}
|
}
|
||||||
|
@ -884,8 +887,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
|
||||||
.image_extent = level_size,
|
.image_extent = level_size,
|
||||||
};
|
};
|
||||||
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
|
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
|
||||||
const Extent3D block =
|
const Extent3D block = AdjustMipBlockSize(num_tiles, level_info.block, level);
|
||||||
AdjustMipBlockSize(num_tiles, level_info.block, level, level_info.num_levels);
|
|
||||||
const u32 stride_alignment = StrideAlignment(num_tiles, info.block, gob, bpp_log2);
|
const u32 stride_alignment = StrideAlignment(num_tiles, info.block, gob, bpp_log2);
|
||||||
size_t guest_layer_offset = 0;
|
size_t guest_layer_offset = 0;
|
||||||
|
|
||||||
|
@ -1039,7 +1041,7 @@ Extent3D MipBlockSize(const ImageInfo& info, u32 level) {
|
||||||
const Extent2D tile_size = DefaultBlockSize(info.format);
|
const Extent2D tile_size = DefaultBlockSize(info.format);
|
||||||
const Extent3D level_size = AdjustMipSize(info.size, level);
|
const Extent3D level_size = AdjustMipSize(info.size, level);
|
||||||
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
|
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
|
||||||
return AdjustMipBlockSize(num_tiles, level_info.block, level, level_info.num_levels);
|
return AdjustMipBlockSize(num_tiles, level_info.block, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::container::small_vector<SwizzleParameters, 16> FullUploadSwizzles(const ImageInfo& info) {
|
boost::container::small_vector<SwizzleParameters, 16> FullUploadSwizzles(const ImageInfo& info) {
|
||||||
|
@ -1061,8 +1063,7 @@ boost::container::small_vector<SwizzleParameters, 16> FullUploadSwizzles(const I
|
||||||
for (s32 level = 0; level < num_levels; ++level) {
|
for (s32 level = 0; level < num_levels; ++level) {
|
||||||
const Extent3D level_size = AdjustMipSize(size, level);
|
const Extent3D level_size = AdjustMipSize(size, level);
|
||||||
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
|
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
|
||||||
const Extent3D block =
|
const Extent3D block = AdjustMipBlockSize(num_tiles, level_info.block, level);
|
||||||
AdjustMipBlockSize(num_tiles, level_info.block, level, level_info.num_levels);
|
|
||||||
params[level] = SwizzleParameters{
|
params[level] = SwizzleParameters{
|
||||||
.num_tiles = num_tiles,
|
.num_tiles = num_tiles,
|
||||||
.block = block,
|
.block = block,
|
||||||
|
@ -1291,11 +1292,11 @@ u32 MapSizeBytes(const ImageBase& image) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(CalculateLevelSize(LevelInfo{{1920, 1080, 1}, {0, 2, 0}, {1, 1}, 2, 0, 1}, 0) ==
|
static_assert(CalculateLevelSize(LevelInfo{{1920, 1080, 1}, {0, 2, 0}, {1, 1}, 2, 0}, 0) ==
|
||||||
0x7f8000);
|
0x7f8000);
|
||||||
static_assert(CalculateLevelSize(LevelInfo{{32, 32, 1}, {0, 0, 4}, {1, 1}, 4, 0, 1}, 0) == 0x4000);
|
static_assert(CalculateLevelSize(LevelInfo{{32, 32, 1}, {0, 0, 4}, {1, 1}, 4, 0}, 0) == 0x40000);
|
||||||
|
|
||||||
static_assert(CalculateLevelSize(LevelInfo{{128, 8, 1}, {0, 4, 0}, {1, 1}, 4, 0, 1}, 0) == 0x4000);
|
static_assert(CalculateLevelSize(LevelInfo{{128, 8, 1}, {0, 4, 0}, {1, 1}, 4, 0}, 0) == 0x40000);
|
||||||
|
|
||||||
static_assert(CalculateLevelOffset(PixelFormat::R8_SINT, {1920, 1080, 1}, {0, 2, 0}, 0, 7) ==
|
static_assert(CalculateLevelOffset(PixelFormat::R8_SINT, {1920, 1080, 1}, {0, 2, 0}, 0, 7) ==
|
||||||
0x2afc00);
|
0x2afc00);
|
||||||
|
|
|
@ -227,14 +227,14 @@ add_executable(yuzu
|
||||||
yuzu.rc
|
yuzu.rc
|
||||||
)
|
)
|
||||||
|
|
||||||
if (WIN32 AND YUZU_CRASH_DUMPS)
|
if (YUZU_CRASH_DUMPS)
|
||||||
target_sources(yuzu PRIVATE
|
target_sources(yuzu PRIVATE
|
||||||
mini_dump.cpp
|
breakpad.cpp
|
||||||
mini_dump.h
|
breakpad.h
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(yuzu PRIVATE ${DBGHELP_LIBRARY})
|
target_link_libraries(yuzu PRIVATE libbreakpad_client)
|
||||||
target_compile_definitions(yuzu PRIVATE -DYUZU_DBGHELP)
|
target_compile_definitions(yuzu PRIVATE YUZU_CRASH_DUMPS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
|
|
77
src/yuzu/breakpad.cpp
Executable file
77
src/yuzu/breakpad.cpp
Executable file
|
@ -0,0 +1,77 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <client/windows/handler/exception_handler.h>
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#include <client/linux/handler/exception_handler.h>
|
||||||
|
#else
|
||||||
|
#error Minidump creation not supported on this platform
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "common/fs/fs_paths.h"
|
||||||
|
#include "common/fs/path_util.h"
|
||||||
|
#include "yuzu/breakpad.h"
|
||||||
|
|
||||||
|
namespace Breakpad {
|
||||||
|
|
||||||
|
static void PruneDumpDirectory(const std::filesystem::path& dump_path) {
|
||||||
|
// Code in this function should be exception-safe.
|
||||||
|
struct Entry {
|
||||||
|
std::filesystem::path path;
|
||||||
|
std::filesystem::file_time_type last_write_time;
|
||||||
|
};
|
||||||
|
std::vector<Entry> existing_dumps;
|
||||||
|
|
||||||
|
// Get existing entries.
|
||||||
|
std::error_code ec;
|
||||||
|
std::filesystem::directory_iterator dir(dump_path, ec);
|
||||||
|
for (auto& entry : dir) {
|
||||||
|
if (entry.is_regular_file()) {
|
||||||
|
existing_dumps.push_back(Entry{
|
||||||
|
.path = entry.path(),
|
||||||
|
.last_write_time = entry.last_write_time(ec),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort descending by creation date.
|
||||||
|
std::ranges::stable_sort(existing_dumps, [](const auto& a, const auto& b) {
|
||||||
|
return a.last_write_time > b.last_write_time;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delete older dumps.
|
||||||
|
for (size_t i = 5; i < existing_dumps.size(); i++) {
|
||||||
|
std::filesystem::remove(existing_dumps[i].path, ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
[[noreturn]] bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context,
|
||||||
|
bool succeeded) {
|
||||||
|
// Prevent time- and space-consuming core dumps from being generated, as we have
|
||||||
|
// already generated a minidump and a core file will not be useful anyway.
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void InstallCrashHandler() {
|
||||||
|
// Write crash dumps to profile directory.
|
||||||
|
const auto dump_path = GetYuzuPath(Common::FS::YuzuPath::CrashDumpsDir);
|
||||||
|
PruneDumpDirectory(dump_path);
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
// TODO: If we switch to MinGW builds for Windows, this needs to be wrapped in a C API.
|
||||||
|
static google_breakpad::ExceptionHandler eh{dump_path, nullptr, nullptr, nullptr,
|
||||||
|
google_breakpad::ExceptionHandler::HANDLER_ALL};
|
||||||
|
#elif defined(__linux__)
|
||||||
|
static google_breakpad::MinidumpDescriptor descriptor{dump_path};
|
||||||
|
static google_breakpad::ExceptionHandler eh{descriptor, nullptr, DumpCallback,
|
||||||
|
nullptr, true, -1};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Breakpad
|
10
src/yuzu/breakpad.h
Executable file
10
src/yuzu/breakpad.h
Executable file
|
@ -0,0 +1,10 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Breakpad {
|
||||||
|
|
||||||
|
void InstallCrashHandler();
|
||||||
|
|
||||||
|
}
|
|
@ -27,16 +27,6 @@ ConfigureDebug::ConfigureDebug(const Core::System& system_, QWidget* parent)
|
||||||
|
|
||||||
connect(ui->toggle_gdbstub, &QCheckBox::toggled,
|
connect(ui->toggle_gdbstub, &QCheckBox::toggled,
|
||||||
[&]() { ui->gdbport_spinbox->setEnabled(ui->toggle_gdbstub->isChecked()); });
|
[&]() { ui->gdbport_spinbox->setEnabled(ui->toggle_gdbstub->isChecked()); });
|
||||||
|
|
||||||
connect(ui->create_crash_dumps, &QCheckBox::stateChanged, [&](int) {
|
|
||||||
if (crash_dump_warning_shown) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QMessageBox::warning(this, tr("Restart Required"),
|
|
||||||
tr("yuzu is required to restart in order to apply this setting."),
|
|
||||||
QMessageBox::Ok, QMessageBox::Ok);
|
|
||||||
crash_dump_warning_shown = true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigureDebug::~ConfigureDebug() = default;
|
ConfigureDebug::~ConfigureDebug() = default;
|
||||||
|
@ -91,13 +81,6 @@ void ConfigureDebug::SetConfiguration() {
|
||||||
ui->disable_web_applet->setEnabled(false);
|
ui->disable_web_applet->setEnabled(false);
|
||||||
ui->disable_web_applet->setText(tr("Web applet not compiled"));
|
ui->disable_web_applet->setText(tr("Web applet not compiled"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef YUZU_DBGHELP
|
|
||||||
ui->create_crash_dumps->setChecked(Settings::values.create_crash_dumps.GetValue());
|
|
||||||
#else
|
|
||||||
ui->create_crash_dumps->setEnabled(false);
|
|
||||||
ui->create_crash_dumps->setText(tr("MiniDump creation not compiled"));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureDebug::ApplyConfiguration() {
|
void ConfigureDebug::ApplyConfiguration() {
|
||||||
|
@ -109,7 +92,6 @@ void ConfigureDebug::ApplyConfiguration() {
|
||||||
Settings::values.enable_fs_access_log = ui->fs_access_log->isChecked();
|
Settings::values.enable_fs_access_log = ui->fs_access_log->isChecked();
|
||||||
Settings::values.reporting_services = ui->reporting_services->isChecked();
|
Settings::values.reporting_services = ui->reporting_services->isChecked();
|
||||||
Settings::values.dump_audio_commands = ui->dump_audio_commands->isChecked();
|
Settings::values.dump_audio_commands = ui->dump_audio_commands->isChecked();
|
||||||
Settings::values.create_crash_dumps = ui->create_crash_dumps->isChecked();
|
|
||||||
Settings::values.quest_flag = ui->quest_flag->isChecked();
|
Settings::values.quest_flag = ui->quest_flag->isChecked();
|
||||||
Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked();
|
Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked();
|
||||||
Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
|
Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
|
||||||
|
|
|
@ -481,13 +481,6 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
|
||||||
<widget class="QCheckBox" name="create_crash_dumps">
|
|
||||||
<property name="text">
|
|
||||||
<string>Create Minidump After Crash</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QCheckBox" name="dump_audio_commands">
|
<widget class="QCheckBox" name="dump_audio_commands">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
|
|
|
@ -157,8 +157,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
||||||
#include "yuzu/util/clickable_label.h"
|
#include "yuzu/util/clickable_label.h"
|
||||||
#include "yuzu/vk_device_info.h"
|
#include "yuzu/vk_device_info.h"
|
||||||
|
|
||||||
#ifdef YUZU_DBGHELP
|
#ifdef YUZU_CRASH_DUMPS
|
||||||
#include "yuzu/mini_dump.h"
|
#include "yuzu/breakpad.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace Common::Literals;
|
using namespace Common::Literals;
|
||||||
|
@ -5146,22 +5146,15 @@ int main(int argc, char* argv[]) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef YUZU_DBGHELP
|
|
||||||
PROCESS_INFORMATION pi;
|
|
||||||
if (!is_child && Settings::values.create_crash_dumps.GetValue() &&
|
|
||||||
MiniDump::SpawnDebuggee(argv[0], pi)) {
|
|
||||||
// Delete the config object so that it doesn't save when the program exits
|
|
||||||
config.reset(nullptr);
|
|
||||||
MiniDump::DebugDebuggee(pi);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (StartupChecks(argv[0], &has_broken_vulkan,
|
if (StartupChecks(argv[0], &has_broken_vulkan,
|
||||||
Settings::values.perform_vulkan_check.GetValue())) {
|
Settings::values.perform_vulkan_check.GetValue())) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef YUZU_CRASH_DUMPS
|
||||||
|
Breakpad::InstallCrashHandler();
|
||||||
|
#endif
|
||||||
|
|
||||||
Common::DetachedTasks detached_tasks;
|
Common::DetachedTasks detached_tasks;
|
||||||
MicroProfileOnThreadCreate("Frontend");
|
MicroProfileOnThreadCreate("Frontend");
|
||||||
SCOPE_EXIT({ MicroProfileShutdown(); });
|
SCOPE_EXIT({ MicroProfileShutdown(); });
|
||||||
|
|
|
@ -33,10 +33,6 @@
|
||||||
"description": "Compile tests",
|
"description": "Compile tests",
|
||||||
"dependencies": [ "catch2" ]
|
"dependencies": [ "catch2" ]
|
||||||
},
|
},
|
||||||
"dbghelp": {
|
|
||||||
"description": "Compile Windows crash dump (Minidump) support",
|
|
||||||
"dependencies": [ "dbghelp" ]
|
|
||||||
},
|
|
||||||
"web-service": {
|
"web-service": {
|
||||||
"description": "Enable web services (telemetry, etc.)",
|
"description": "Enable web services (telemetry, etc.)",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
|
|
Loading…
Reference in a new issue