Compare commits
154 Commits
mcu-stub
...
blit-scree
Author | SHA1 | Date | |
---|---|---|---|
797d0e45ce | |||
37ce0540ed | |||
e978931574 | |||
facddbfc8c | |||
68a3217d1e | |||
ddfae0025c | |||
75b6c5b4c5 | |||
32c6e76ab9 | |||
479c7ed162 | |||
009dfa5265 | |||
b225239e1f | |||
f887621921 | |||
407ae3972a | |||
0f0ca03551 | |||
9ae84fb6e8 | |||
215255d415 | |||
f5f88101e1 | |||
e511e51491 | |||
242047744e | |||
349ac6ac05 | |||
16571a96a2 | |||
a0e9836386 | |||
fb10d05f97 | |||
182bebf272 | |||
7626804a90 | |||
20496e8ca4 | |||
b4184a3c2b | |||
2251d96d4d | |||
c028a8c7c5 | |||
359f97be22 | |||
748f8a0658 | |||
a7611bb2d3 | |||
6f35a3bf37 | |||
58573dd7b3 | |||
11728d6772 | |||
a99be221b2 | |||
f656610a41 | |||
cfa1a7b91c | |||
52b1fc4889 | |||
01e2b6cdaa | |||
f75380fc93 | |||
18af49a0ca | |||
c7e64f6c7b | |||
0a40a513a6 | |||
a4dc6a55b7 | |||
7dce5be263 | |||
3f7d97da4c | |||
a11b4dd051 | |||
c78847b2b6 | |||
8faa7a6e02 | |||
acf4b4e5fb | |||
3a0ca63d91 | |||
1e96775203 | |||
6d27e8be8d | |||
c357a8b9b6 | |||
7ad982f123 | |||
dd3d24bfec | |||
489bbb98b2 | |||
5c9543e39d | |||
49085d400c | |||
8be9ea4f4a | |||
a71c288252 | |||
159809eb32 | |||
2a4f0ce8de | |||
4c8f1c83c8 | |||
98f6d697d8 | |||
4636735783 | |||
8a2770bf83 | |||
f1e09c1ea1 | |||
2423e645f1 | |||
0eaae31f9f | |||
4f9b545296 | |||
628d70e112 | |||
9991b9b12b | |||
e4bcf73c5a | |||
b693d205e4 | |||
91621ec202 | |||
948f72d320 | |||
8c5b417486 | |||
51685ee2db | |||
079e4aa205 | |||
48edfb891b | |||
915406354c | |||
6f3fc32a93 | |||
ebfa98d31d | |||
3095ee91a8 | |||
fadeecfe6d | |||
2a1598036e | |||
58f01112c5 | |||
7e7b3dc18c | |||
d4a3f60575 | |||
f8cbf783cb | |||
dc0cddb7de | |||
9cef9d4c58 | |||
dada05801f | |||
9bc71a3307 | |||
98274273b1 | |||
269db2bfb8 | |||
d27c1c8606 | |||
891b4bff18 | |||
eeccdc02fc | |||
29ee94c3f5 | |||
8936641841 | |||
e1f6b88e7b | |||
64d809f06a | |||
ebd23026a0 | |||
6e1bfe9949 | |||
854092ce4f | |||
90d24caaf8 | |||
65400936c7 | |||
3f9e5a2b42 | |||
34ba320c3d | |||
ec9f1902f5 | |||
c72a365d78 | |||
8f211613a3 | |||
30885b72be | |||
beb078a71b | |||
a65f9ea5a8 | |||
f9c11eab96 | |||
794f6e4a67 | |||
c85731f3ae | |||
e1542cea84 | |||
887ef51f04 | |||
d809687aeb | |||
96ec85a72e | |||
0ed4d493ad | |||
78be1e7c17 | |||
2963682722 | |||
98eea4dcca | |||
98a4a18201 | |||
3619bd33b1 | |||
fa870be263 | |||
3a6d19f51f | |||
73d6a9d585 | |||
5d48107dd6 | |||
a306931e1c | |||
b3803c5002 | |||
c412c116d8 | |||
6ce4493e14 | |||
d6e545932a | |||
542bae4581 | |||
307154a06f | |||
725afe33ef | |||
bb58056ebe | |||
f69a33574c | |||
1a48cf7e7d | |||
2833d94a3b | |||
9b0aa5135e | |||
9787efc7ee | |||
623293d272 | |||
5ab5fdcc22 | |||
1b1988a37a | |||
f584d143ff | |||
56c679595f |
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
@ -95,6 +95,13 @@ jobs:
|
||||
env:
|
||||
MACOSX_DEPLOYMENT_TARGET: "10.13"
|
||||
ENABLE_COMPATIBILITY_REPORTING: "ON"
|
||||
- name: Pack
|
||||
run: ./.ci/macos/upload.sh
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macos
|
||||
path: artifacts/
|
||||
windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
|
12
.gitmodules
vendored
12
.gitmodules
vendored
@ -58,3 +58,15 @@
|
||||
[submodule "sdl2"]
|
||||
path = externals/sdl2/SDL
|
||||
url = https://github.com/libsdl-org/SDL
|
||||
[submodule "vulkan-headers"]
|
||||
path = externals/vulkan-headers
|
||||
url = https://github.com/KhronosGroup/Vulkan-Headers
|
||||
[submodule "glslang"]
|
||||
path = externals/glslang
|
||||
url = https://github.com/KhronosGroup/glslang
|
||||
[submodule "glm"]
|
||||
path = externals/glm
|
||||
url = https://github.com/g-truc/glm
|
||||
[submodule "sirit"]
|
||||
path = externals/sirit
|
||||
url = https://github.com/GPUCode/sirit
|
||||
|
@ -1,15 +1,15 @@
|
||||
# CMake 3.12 required for 20 to be a valid value for CXX_STANDARD
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.15)
|
||||
# Don't override the warning flags in MSVC:
|
||||
cmake_policy(SET CMP0092 NEW)
|
||||
# Enforce new LTO setting
|
||||
cmake_policy(SET CMP0069 NEW)
|
||||
endif()
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
# Don't override the warning flags in MSVC:
|
||||
cmake_policy(SET CMP0092 NEW)
|
||||
# Enforce new LTO setting
|
||||
cmake_policy(SET CMP0069 NEW)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
|
||||
include(DownloadExternals)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakeDependentOption)
|
||||
|
||||
project(citra LANGUAGES C CXX ASM)
|
||||
|
2
dist/qt_themes/colorful/style.qrc
vendored
2
dist/qt_themes/colorful/style.qrc
vendored
@ -13,6 +13,6 @@
|
||||
<file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="colorful">
|
||||
<file>style.qss</file>
|
||||
<file alias="style.qss">../default/style.qss</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
4
dist/qt_themes/colorful/style.qss
vendored
4
dist/qt_themes/colorful/style.qss
vendored
@ -1,4 +0,0 @@
|
||||
/*
|
||||
This file is intentionally left blank.
|
||||
We do not want to apply any stylesheet for colorful, only icons.
|
||||
*/
|
17
dist/qt_themes/default/default.qrc
vendored
17
dist/qt_themes/default/default.qrc
vendored
@ -1,33 +1,22 @@
|
||||
<RCC>
|
||||
<qresource prefix="icons/default">
|
||||
<file alias="index.theme">icons/index.theme</file>
|
||||
|
||||
<file alias="16x16/checked.png">icons/16x16/checked.png</file>
|
||||
|
||||
<file alias="16x16/failed.png">icons/16x16/failed.png</file>
|
||||
|
||||
<file alias="16x16/connected.png">icons/16x16/connected.png</file>
|
||||
|
||||
<file alias="16x16/disconnected.png">icons/16x16/disconnected.png</file>
|
||||
|
||||
<file alias="16x16/connected_notification.png">icons/16x16/connected_notification.png</file>
|
||||
|
||||
<file alias="16x16/lock.png">icons/16x16/lock.png</file>
|
||||
|
||||
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
|
||||
|
||||
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
|
||||
|
||||
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
||||
|
||||
<file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
|
||||
|
||||
<file alias="48x48/plus.png">icons/48x48/plus.png</file>
|
||||
|
||||
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
||||
|
||||
<file alias="256x256/citra.png">icons/256x256/citra.png</file>
|
||||
|
||||
<file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="default">
|
||||
<file>style.qss</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
13
dist/qt_themes/default/style.qss
vendored
Normal file
13
dist/qt_themes/default/style.qss
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
QPushButton#GraphicsAPIStatusBarButton {
|
||||
color: #656565;
|
||||
border: 1px solid transparent;
|
||||
background-color: transparent;
|
||||
padding: 0px 3px 0px 3px;
|
||||
text-align: center;
|
||||
min-width: 60px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
QPushButton#GraphicsAPIStatusBarButton:hover {
|
||||
border: 1px solid #76797C;
|
||||
}
|
21
dist/qt_themes/qdarkstyle/style.qss
vendored
21
dist/qt_themes/qdarkstyle/style.qss
vendored
@ -522,13 +522,12 @@ QToolButton#qt_toolbar_ext_button {
|
||||
|
||||
QPushButton {
|
||||
color: #eff0f1;
|
||||
border-width: 1px;
|
||||
border-color: #54575B;
|
||||
border-style: solid;
|
||||
padding: 6px 4px;
|
||||
border: 1px solid #54575B;
|
||||
border-radius: 2px;
|
||||
padding: 5px 0px 5px 0px;
|
||||
outline: none;
|
||||
min-width: 100px;
|
||||
min-height: 13px;
|
||||
background-color: #232629;
|
||||
}
|
||||
|
||||
@ -1237,3 +1236,17 @@ QPlainTextEdit:disabled {
|
||||
TouchScreenPreview {
|
||||
qproperty-dotHighlightColor: #3daee9;
|
||||
}
|
||||
|
||||
QPushButton#GraphicsAPIStatusBarButton {
|
||||
color: #656565;
|
||||
border: 1px solid transparent;
|
||||
background-color: transparent;
|
||||
padding: 0px 3px 0px 3px;
|
||||
text-align: center;
|
||||
min-width: 60px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
QPushButton#GraphicsAPIStatusBarButton:hover {
|
||||
border: 1px solid #76797C;
|
||||
}
|
22
externals/CMakeLists.txt
vendored
22
externals/CMakeLists.txt
vendored
@ -60,6 +60,19 @@ endif()
|
||||
# Glad
|
||||
add_subdirectory(glad)
|
||||
|
||||
# glslang
|
||||
set(SKIP_GLSLANG_INSTALL ON)
|
||||
set(ENABLE_GLSLANG_BINARIES OFF)
|
||||
set(ENABLE_SPVREMAPPER OFF)
|
||||
set(ENABLE_CTEST OFF)
|
||||
add_subdirectory(glslang)
|
||||
|
||||
# Sirit
|
||||
add_subdirectory(sirit)
|
||||
|
||||
# glm
|
||||
add_subdirectory(glm)
|
||||
|
||||
# inih
|
||||
add_subdirectory(inih)
|
||||
|
||||
@ -154,3 +167,12 @@ if(ANDROID)
|
||||
add_subdirectory(libyuv)
|
||||
target_include_directories(yuv INTERFACE ./libyuv/include)
|
||||
endif()
|
||||
|
||||
# VMA
|
||||
add_library(vma INTERFACE)
|
||||
target_include_directories(vma INTERFACE ./vma)
|
||||
|
||||
# vulkan-headers
|
||||
add_library(vulkan-headers INTERFACE)
|
||||
target_include_directories(vulkan-headers INTERFACE ./vulkan-headers/include)
|
||||
|
||||
|
1862
externals/glad/include/glad/glad.h
vendored
1862
externals/glad/include/glad/glad.h
vendored
File diff suppressed because it is too large
Load Diff
1037
externals/glad/src/glad.c
vendored
1037
externals/glad/src/glad.c
vendored
File diff suppressed because it is too large
Load Diff
1
externals/glm
vendored
Submodule
1
externals/glm
vendored
Submodule
Submodule externals/glm added at cc98465e35
1
externals/glslang
vendored
Submodule
1
externals/glslang
vendored
Submodule
Submodule externals/glslang added at c0cf8ad876
6
externals/microprofile/microprofile.h
vendored
6
externals/microprofile/microprofile.h
vendored
@ -847,7 +847,7 @@ inline MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfi
|
||||
MicroProfileLogEntry Entry = (nBegin<<62) | ((0x3fff&nToken)<<48) | (MP_LOG_TICK_MASK&nTick);
|
||||
int t = MicroProfileLogType(Entry);
|
||||
uint64_t nTimerIndex = MicroProfileLogTimerIndex(Entry);
|
||||
MP_ASSERT(t == nBegin);
|
||||
MP_ASSERT(static_cast<uint64_t>(t) == nBegin);
|
||||
MP_ASSERT(nTimerIndex == (nToken&0x3fff));
|
||||
return Entry;
|
||||
|
||||
@ -1579,10 +1579,10 @@ void MicroProfileFlip()
|
||||
|
||||
pFramePut->nFrameStartCpu = MP_TICK();
|
||||
pFramePut->nFrameStartGpu = (uint32_t)MicroProfileGpuInsertTimeStamp();
|
||||
if(pFrameNext->nFrameStartGpu != (uint64_t)-1)
|
||||
if(static_cast<uint64_t>(pFrameNext->nFrameStartGpu) != (uint64_t)-1)
|
||||
pFrameNext->nFrameStartGpu = MicroProfileGpuGetTimeStamp((uint32_t)pFrameNext->nFrameStartGpu);
|
||||
|
||||
if(pFrameCurrent->nFrameStartGpu == (uint64_t)-1)
|
||||
if(static_cast<uint64_t>(pFrameCurrent->nFrameStartGpu) == (uint64_t)-1)
|
||||
pFrameCurrent->nFrameStartGpu = pFrameNext->nFrameStartGpu + 1;
|
||||
|
||||
uint64_t nFrameStartCpu = pFrameCurrent->nFrameStartCpu;
|
||||
|
12
externals/microprofile/microprofileui.h
vendored
12
externals/microprofile/microprofileui.h
vendored
@ -354,7 +354,7 @@ void MicroProfileInitUI()
|
||||
if(!bInitialized)
|
||||
{
|
||||
bInitialized = true;
|
||||
memset(&g_MicroProfileUI, 0, sizeof(g_MicroProfileUI));
|
||||
g_MicroProfileUI = {};
|
||||
UI.nActiveMenu = UINT32_MAX;
|
||||
UI.fDetailedOffsetTarget = UI.fDetailedOffset = 0.f;
|
||||
UI.fDetailedRangeTarget = UI.fDetailedRange = 50.f;
|
||||
@ -845,8 +845,8 @@ void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int nBaseY,
|
||||
MicroProfile& S = *MicroProfileGet();
|
||||
MP_DEBUG_DUMP_RANGE();
|
||||
int nY = nBaseY - UI.nOffsetY;
|
||||
int64_t nNumBoxes = 0;
|
||||
int64_t nNumLines = 0;
|
||||
[[maybe_unused]] int64_t nNumBoxes = 0;
|
||||
[[maybe_unused]] int64_t nNumLines = 0;
|
||||
|
||||
uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY;
|
||||
MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent];
|
||||
@ -1988,7 +1988,7 @@ const char* MicroProfileUIMenuGroups(int nIndex, bool* bSelected)
|
||||
else
|
||||
{
|
||||
nIndex = nIndex-1;
|
||||
if(nIndex < UI.GroupMenuCount)
|
||||
if(static_cast<uint32_t>(nIndex) < UI.GroupMenuCount)
|
||||
{
|
||||
MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex];
|
||||
static char buffer[MICROPROFILE_NAME_MAX_LEN+32];
|
||||
@ -2135,7 +2135,7 @@ const char* MicroProfileUIMenuCustom(int nIndex, bool* bSelected)
|
||||
case 1: return "--";
|
||||
default:
|
||||
nIndex -= 2;
|
||||
if(nIndex < UI.nCustomCount)
|
||||
if(static_cast<uint32_t>(nIndex) < UI.nCustomCount)
|
||||
{
|
||||
return UI.Custom[nIndex].pName;
|
||||
}
|
||||
@ -2185,7 +2185,7 @@ void MicroProfileUIClickGroups(int nIndex)
|
||||
else
|
||||
{
|
||||
nIndex -= 1;
|
||||
if(nIndex < UI.GroupMenuCount)
|
||||
if(static_cast<uint32_t>(nIndex) < UI.GroupMenuCount)
|
||||
{
|
||||
MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex];
|
||||
if(Item.nIsCategory)
|
||||
|
2
externals/sdl2/CMakeLists.txt
vendored
2
externals/sdl2/CMakeLists.txt
vendored
@ -39,9 +39,9 @@ set(SDL_JOYSTICK ON CACHE BOOL "")
|
||||
set(SDL_HAPTIC OFF CACHE BOOL "")
|
||||
set(SDL_HIDAPI ON CACHE BOOL "")
|
||||
set(SDL_POWER OFF CACHE BOOL "")
|
||||
set(SDL_THREADS ON CACHE BOOL "")
|
||||
set(SDL_TIMERS ON CACHE BOOL "")
|
||||
set(SDL_FILE ON CACHE BOOL "")
|
||||
set(SDL_THREADS ON CACHE BOOL "")
|
||||
set(SDL_LOADSO ON CACHE BOOL "")
|
||||
set(SDL_CPUINFO OFF CACHE BOOL "")
|
||||
set(SDL_FILESYSTEM OFF CACHE BOOL "")
|
||||
|
1
externals/sirit
vendored
Submodule
1
externals/sirit
vendored
Submodule
Submodule externals/sirit added at 297d820eeb
19670
externals/vma/vk_mem_alloc.h
vendored
Normal file
19670
externals/vma/vk_mem_alloc.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
externals/vulkan-headers
vendored
Submodule
1
externals/vulkan-headers
vendored
Submodule
Submodule externals/vulkan-headers added at 98f440ce68
@ -103,6 +103,7 @@ else()
|
||||
|
||||
if (MINGW)
|
||||
add_definitions(-DMINGW_HAS_SECURE_API)
|
||||
add_compile_options("-Wa,-mbig-obj")
|
||||
if (COMPILE_WITH_DWARF)
|
||||
add_compile_options("-gdwarf")
|
||||
endif()
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "core/frontend/applets/default_applets.h"
|
||||
#include "core/frontend/camera/factory.h"
|
||||
#include "core/frontend/mic.h"
|
||||
#include "core/frontend/scope_acquire_context.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/nfc/nfc.h"
|
||||
#include "core/savestate.h"
|
||||
|
@ -7,7 +7,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.2.0'
|
||||
classpath 'com.android.tools.build:gradle:7.3.1'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
@ -7,17 +7,7 @@
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
// This needs to be included before getopt.h because the latter #defines symbols used by it
|
||||
#include "common/microprofile.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
// windows.h needs to be included before shellapi.h
|
||||
#include <windows.h>
|
||||
|
||||
#include <shellapi.h>
|
||||
#endif
|
||||
|
||||
#include "citra/config.h"
|
||||
#include "citra/emu_window/emu_window_sdl2.h"
|
||||
#include "citra/lodepng_image_interface.h"
|
||||
@ -25,21 +15,17 @@
|
||||
#include "common/detached_tasks.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/backend.h"
|
||||
#include "common/logging/filter.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/scm_rev.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/dumping/backend.h"
|
||||
#include "core/file_sys/cia_container.h"
|
||||
#include "core/frontend/applets/default_applets.h"
|
||||
#include "core/frontend/framebuffer_layout.h"
|
||||
#include "core/frontend/scope_acquire_context.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/cfg/cfg.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/movie.h"
|
||||
#include "core/settings.h"
|
||||
#include "network/network.h"
|
||||
@ -52,6 +38,11 @@
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// windows.h needs to be included before shellapi.h
|
||||
#include <windows.h>
|
||||
|
||||
#include <shellapi.h>
|
||||
|
||||
extern "C" {
|
||||
// tells Nvidia drivers to use the dedicated GPU by default on laptops with switchable graphics
|
||||
__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
|
||||
@ -104,35 +95,35 @@ static void OnNetworkError(const Network::RoomMember::Error& error) {
|
||||
break;
|
||||
case Network::RoomMember::Error::CouldNotConnect:
|
||||
LOG_ERROR(Network, "Error: Could not connect");
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
break;
|
||||
case Network::RoomMember::Error::NameCollision:
|
||||
LOG_ERROR(
|
||||
Network,
|
||||
"You tried to use the same nickname as another user that is connected to the Room");
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
break;
|
||||
case Network::RoomMember::Error::MacCollision:
|
||||
LOG_ERROR(Network, "You tried to use the same MAC-Address as another user that is "
|
||||
"connected to the Room");
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
break;
|
||||
case Network::RoomMember::Error::ConsoleIdCollision:
|
||||
LOG_ERROR(Network, "Your Console ID conflicted with someone else in the Room");
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
break;
|
||||
case Network::RoomMember::Error::WrongPassword:
|
||||
LOG_ERROR(Network, "Room replied with: Wrong password");
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
break;
|
||||
case Network::RoomMember::Error::WrongVersion:
|
||||
LOG_ERROR(Network,
|
||||
"You are using a different version than the room you are trying to connect to");
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
break;
|
||||
case Network::RoomMember::Error::RoomIsFull:
|
||||
LOG_ERROR(Network, "The room is full");
|
||||
exit(1);
|
||||
std::exit(1);
|
||||
break;
|
||||
case Network::RoomMember::Error::HostKicked:
|
||||
LOG_ERROR(Network, "You have been kicked by the host");
|
||||
@ -140,6 +131,8 @@ static void OnNetworkError(const Network::RoomMember::Error& error) {
|
||||
case Network::RoomMember::Error::HostBanned:
|
||||
LOG_ERROR(Network, "You have been banned by the host");
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR(Network, "Unknown network error {}", error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -359,7 +352,7 @@ int main(int argc, char** argv) {
|
||||
Core::System::GetInstance().RegisterImageInterface(std::make_shared<LodePNGImageInterface>());
|
||||
|
||||
std::unique_ptr<EmuWindow_SDL2> emu_window{std::make_unique<EmuWindow_SDL2>(fullscreen)};
|
||||
Frontend::ScopeAcquireContext scope(*emu_window);
|
||||
const auto scope = emu_window->Acquire();
|
||||
Core::System& system = Core::System::GetInstance();
|
||||
|
||||
const Core::System::ResultStatus load_result{system.Load(*emu_window, filepath)};
|
||||
|
@ -109,7 +109,8 @@ void Config::ReadValues() {
|
||||
sdl2_config->GetInteger("Core", "cpu_clock_percentage", 100);
|
||||
|
||||
// Renderer
|
||||
Settings::values.use_gles = sdl2_config->GetBoolean("Renderer", "use_gles", false);
|
||||
Settings::values.graphics_api =
|
||||
static_cast<Settings::GraphicsAPI>(sdl2_config->GetInteger("Renderer", "graphics_api", 0));
|
||||
Settings::values.use_hw_renderer = sdl2_config->GetBoolean("Renderer", "use_hw_renderer", true);
|
||||
Settings::values.use_hw_shader = sdl2_config->GetBoolean("Renderer", "use_hw_shader", true);
|
||||
#ifdef __APPLE__
|
||||
|
@ -147,7 +147,8 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
|
||||
|
||||
SDL_SetMainReady();
|
||||
|
||||
if (Settings::values.use_gles) {
|
||||
const bool is_opengles = Settings::values.graphics_api == Settings::GraphicsAPI::OpenGLES;
|
||||
if (is_opengles) {
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
@ -201,7 +202,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
auto gl_load_func = Settings::values.use_gles ? gladLoadGLES2Loader : gladLoadGLLoader;
|
||||
auto gl_load_func = is_opengles ? gladLoadGLES2Loader : gladLoadGLLoader;
|
||||
|
||||
if (!gl_load_func(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) {
|
||||
LOG_CRITICAL(Frontend, "Failed to initialize GL functions: {}", SDL_GetError());
|
||||
|
@ -260,9 +260,13 @@ endif()
|
||||
create_target_directory_groups(citra-qt)
|
||||
|
||||
target_link_libraries(citra-qt PRIVATE audio_core common core input_common network video_core)
|
||||
target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::Widgets Qt5::Multimedia)
|
||||
target_link_libraries(citra-qt PRIVATE Boost::boost glad vma vulkan-headers nihstro-headers Qt5::Widgets Qt5::Multimedia)
|
||||
target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
||||
|
||||
if (NOT WIN32)
|
||||
target_include_directories(citra-qt PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
target_compile_definitions(citra-qt PRIVATE
|
||||
# Use QStringBuilder for string concatenation to reduce
|
||||
# the overall number of temporary strings created.
|
||||
|
@ -54,12 +54,12 @@ QtKeyboardDialog::QtKeyboardDialog(QWidget* parent, QtKeyboard* keyboard_)
|
||||
case ButtonConfig::None:
|
||||
break;
|
||||
}
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, [=] { Submit(); });
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, [=] {
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, [this] { Submit(); });
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, [this] {
|
||||
button = QtKeyboard::cancel_id;
|
||||
accept();
|
||||
});
|
||||
connect(buttons, &QDialogButtonBox::helpRequested, this, [=] {
|
||||
connect(buttons, &QDialogButtonBox::helpRequested, this, [this] {
|
||||
button = QtKeyboard::forgot_id;
|
||||
accept();
|
||||
});
|
||||
|
@ -6,10 +6,10 @@
|
||||
#include <QDragEnterEvent>
|
||||
#include <QHBoxLayout>
|
||||
#include <QKeyEvent>
|
||||
#include <QMessageBox>
|
||||
#include <QOffscreenSurface>
|
||||
#include <QOpenGLContext>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLFunctions_4_3_Core>
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <fmt/format.h>
|
||||
#include "citra_qt/bootmanager.h"
|
||||
#include "citra_qt/main.h"
|
||||
@ -17,56 +17,60 @@
|
||||
#include "common/scm_rev.h"
|
||||
#include "core/3ds.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/scope_acquire_context.h"
|
||||
#include "core/perf_stats.h"
|
||||
#include "core/settings.h"
|
||||
#include "input_common/keyboard.h"
|
||||
#include "input_common/main.h"
|
||||
#include "input_common/motion_emu.h"
|
||||
#include "network/network.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
#if !defined(WIN32)
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#endif
|
||||
|
||||
EmuThread::EmuThread(Frontend::GraphicsContext& core_context) : core_context(core_context) {}
|
||||
|
||||
EmuThread::~EmuThread() = default;
|
||||
|
||||
static GMainWindow* GetMainWindow() {
|
||||
for (QWidget* w : qApp->topLevelWidgets()) {
|
||||
const auto widgets = qApp->topLevelWidgets();
|
||||
for (QWidget* w : widgets) {
|
||||
if (GMainWindow* main = qobject_cast<GMainWindow*>(w)) {
|
||||
return main;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void EmuThread::run() {
|
||||
MicroProfileOnThreadCreate("EmuThread");
|
||||
Frontend::ScopeAcquireContext scope(core_context);
|
||||
const auto scope = core_context.Acquire();
|
||||
|
||||
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
|
||||
|
||||
Core::System::GetInstance().Renderer().Rasterizer()->LoadDiskResources(
|
||||
Core::System& system = Core::System::GetInstance();
|
||||
system.Renderer().Rasterizer()->LoadDiskResources(
|
||||
stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
|
||||
emit LoadProgress(stage, value, total);
|
||||
});
|
||||
|
||||
emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
|
||||
emit HideLoadingScreen();
|
||||
|
||||
core_context.MakeCurrent();
|
||||
|
||||
if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) {
|
||||
if (system.frame_limiter.IsFrameAdvancing()) {
|
||||
// Usually the loading screen is hidden after the first frame is drawn. In this case
|
||||
// we hide it immediately as we need to wait for user input to start the emulation.
|
||||
emit HideLoadingScreen();
|
||||
Core::System::GetInstance().frame_limiter.WaitOnce();
|
||||
system.frame_limiter.WaitOnce();
|
||||
}
|
||||
|
||||
// Holds whether the cpu was running during the last iteration,
|
||||
// so that the DebugModeLeft signal can be emitted before the
|
||||
// next execution step.
|
||||
bool was_active = false;
|
||||
Core::System& system = Core::System::GetInstance();
|
||||
while (!stop_run) {
|
||||
if (running) {
|
||||
if (!was_active)
|
||||
@ -111,87 +115,236 @@ void EmuThread::run() {
|
||||
#endif
|
||||
}
|
||||
|
||||
OpenGLWindow::OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context)
|
||||
: QWindow(parent), context(std::make_unique<QOpenGLContext>(shared_context->parent())),
|
||||
event_handler(event_handler) {
|
||||
class OpenGLSharedContext : public Frontend::GraphicsContext {
|
||||
public:
|
||||
/// Create the original context that should be shared from
|
||||
explicit OpenGLSharedContext(QSurface* surface) : surface(surface) {
|
||||
QSurfaceFormat format;
|
||||
|
||||
// disable vsync for any shared contexts
|
||||
auto format = shared_context->format();
|
||||
format.setSwapInterval(Settings::values.use_vsync_new ? 1 : 0);
|
||||
this->setFormat(format);
|
||||
format.setVersion(4, 4);
|
||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||
|
||||
context->setShareContext(shared_context);
|
||||
context->setScreen(this->screen());
|
||||
context->setFormat(format);
|
||||
context->create();
|
||||
if (Settings::values.renderer_debug) {
|
||||
format.setOption(QSurfaceFormat::FormatOption::DebugContext);
|
||||
}
|
||||
|
||||
setSurfaceType(QWindow::OpenGLSurface);
|
||||
// TODO: expose a setting for buffer value (ie default/single/double/triple)
|
||||
format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior);
|
||||
format.setSwapInterval(0);
|
||||
|
||||
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
|
||||
// WA_DontShowOnScreen, WA_DeleteOnClose
|
||||
}
|
||||
|
||||
OpenGLWindow::~OpenGLWindow() {
|
||||
context->doneCurrent();
|
||||
}
|
||||
|
||||
void OpenGLWindow::Present() {
|
||||
if (!isExposed())
|
||||
return;
|
||||
|
||||
context->makeCurrent(this);
|
||||
if (VideoCore::g_renderer) {
|
||||
VideoCore::g_renderer->TryPresent(100);
|
||||
context = std::make_unique<QOpenGLContext>();
|
||||
context->setFormat(format);
|
||||
if (!context->create()) {
|
||||
LOG_ERROR(Frontend, "Unable to create main openGL context");
|
||||
}
|
||||
}
|
||||
context->swapBuffers(this);
|
||||
auto f = context->versionFunctions<QOpenGLFunctions_4_3_Core>();
|
||||
f->glFinish();
|
||||
QWindow::requestUpdate();
|
||||
}
|
||||
|
||||
bool OpenGLWindow::event(QEvent* event) {
|
||||
switch (event->type()) {
|
||||
case QEvent::UpdateRequest:
|
||||
/// Create the shared contexts for rendering and presentation
|
||||
explicit OpenGLSharedContext(QOpenGLContext* share_context, QSurface* main_surface = nullptr) {
|
||||
|
||||
// disable vsync for any shared contexts
|
||||
auto format = share_context->format();
|
||||
format.setSwapInterval(main_surface ? Settings::values.use_vsync_new : 0);
|
||||
|
||||
context = std::make_unique<QOpenGLContext>();
|
||||
context->setShareContext(share_context);
|
||||
context->setFormat(format);
|
||||
if (!context->create()) {
|
||||
LOG_ERROR(Frontend, "Unable to create shared openGL context");
|
||||
}
|
||||
|
||||
if (!main_surface) {
|
||||
offscreen_surface = std::make_unique<QOffscreenSurface>(nullptr);
|
||||
offscreen_surface->setFormat(format);
|
||||
offscreen_surface->create();
|
||||
surface = offscreen_surface.get();
|
||||
} else {
|
||||
surface = main_surface;
|
||||
}
|
||||
}
|
||||
|
||||
~OpenGLSharedContext() {
|
||||
context->doneCurrent();
|
||||
}
|
||||
|
||||
void SwapBuffers() override {
|
||||
context->swapBuffers(surface);
|
||||
}
|
||||
|
||||
void MakeCurrent() override {
|
||||
// We can't track the current state of the underlying context in this wrapper class because
|
||||
// Qt may make the underlying context not current for one reason or another. In particular,
|
||||
// the WebBrowser uses GL, so it seems to conflict if we aren't careful.
|
||||
// Instead of always just making the context current (which does not have any caching to
|
||||
// check if the underlying context is already current) we can check for the current context
|
||||
// in the thread local data by calling `currentContext()` and checking if its ours.
|
||||
if (QOpenGLContext::currentContext() != context.get()) {
|
||||
context->makeCurrent(surface);
|
||||
}
|
||||
}
|
||||
|
||||
void DoneCurrent() override {
|
||||
context->doneCurrent();
|
||||
}
|
||||
|
||||
QOpenGLContext* GetShareContext() const {
|
||||
return context.get();
|
||||
}
|
||||
|
||||
private:
|
||||
// Avoid using Qt parent system here since we might move the QObjects to new threads
|
||||
// As a note, this means we should avoid using slots/signals with the objects too
|
||||
std::unique_ptr<QOpenGLContext> context;
|
||||
std::unique_ptr<QOffscreenSurface> offscreen_surface{};
|
||||
QSurface* surface;
|
||||
};
|
||||
|
||||
class DummyContext : public Frontend::GraphicsContext {};
|
||||
|
||||
class RenderWidget : public QWidget {
|
||||
public:
|
||||
RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) {
|
||||
setAttribute(Qt::WA_NativeWindow);
|
||||
setAttribute(Qt::WA_PaintOnScreen);
|
||||
}
|
||||
|
||||
virtual ~RenderWidget() = default;
|
||||
|
||||
virtual void Present() {}
|
||||
|
||||
void paintEvent(QPaintEvent* event) override {
|
||||
Present();
|
||||
return true;
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseButtonDblClick:
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::KeyPress:
|
||||
case QEvent::KeyRelease:
|
||||
case QEvent::FocusIn:
|
||||
case QEvent::FocusOut:
|
||||
case QEvent::FocusAboutToChange:
|
||||
case QEvent::Enter:
|
||||
case QEvent::Leave:
|
||||
case QEvent::Wheel:
|
||||
case QEvent::TabletMove:
|
||||
case QEvent::TabletPress:
|
||||
case QEvent::TabletRelease:
|
||||
case QEvent::TabletEnterProximity:
|
||||
case QEvent::TabletLeaveProximity:
|
||||
case QEvent::TouchBegin:
|
||||
case QEvent::TouchUpdate:
|
||||
case QEvent::TouchEnd:
|
||||
case QEvent::InputMethodQuery:
|
||||
case QEvent::TouchCancel:
|
||||
return QCoreApplication::sendEvent(event_handler, event);
|
||||
case QEvent::Drop:
|
||||
GetMainWindow()->DropAction(static_cast<QDropEvent*>(event));
|
||||
return true;
|
||||
case QEvent::DragEnter:
|
||||
case QEvent::DragMove:
|
||||
GetMainWindow()->AcceptDropEvent(static_cast<QDropEvent*>(event));
|
||||
return true;
|
||||
default:
|
||||
return QWindow::event(event);
|
||||
update();
|
||||
}
|
||||
|
||||
void resizeEvent(QResizeEvent* ev) override {
|
||||
render_window->resize(ev->size());
|
||||
render_window->OnFramebufferSizeChanged();
|
||||
}
|
||||
|
||||
void keyPressEvent(QKeyEvent* event) override {
|
||||
InputCommon::GetKeyboard()->PressKey(event->key());
|
||||
}
|
||||
|
||||
void keyReleaseEvent(QKeyEvent* event) override {
|
||||
InputCommon::GetKeyboard()->ReleaseKey(event->key());
|
||||
}
|
||||
|
||||
void mousePressEvent(QMouseEvent* event) override {
|
||||
if (event->source() == Qt::MouseEventSynthesizedBySystem)
|
||||
return; // touch input is handled in TouchBeginEvent
|
||||
|
||||
const auto pos{event->pos()};
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
const auto [x, y] = render_window->ScaleTouch(pos);
|
||||
render_window->TouchPressed(x, y);
|
||||
} else if (event->button() == Qt::RightButton) {
|
||||
InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y());
|
||||
}
|
||||
}
|
||||
|
||||
void mouseMoveEvent(QMouseEvent* event) override {
|
||||
if (event->source() == Qt::MouseEventSynthesizedBySystem)
|
||||
return; // touch input is handled in TouchUpdateEvent
|
||||
|
||||
const auto pos{event->pos()};
|
||||
const auto [x, y] = render_window->ScaleTouch(pos);
|
||||
render_window->TouchMoved(x, y);
|
||||
InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y());
|
||||
}
|
||||
|
||||
void mouseReleaseEvent(QMouseEvent* event) override {
|
||||
if (event->source() == Qt::MouseEventSynthesizedBySystem)
|
||||
return; // touch input is handled in TouchEndEvent
|
||||
|
||||
if (event->button() == Qt::LeftButton)
|
||||
render_window->TouchReleased();
|
||||
else if (event->button() == Qt::RightButton)
|
||||
InputCommon::GetMotionEmu()->EndTilt();
|
||||
}
|
||||
|
||||
std::pair<unsigned, unsigned> GetSize() const {
|
||||
return std::make_pair(width(), height());
|
||||
}
|
||||
|
||||
QPaintEngine* paintEngine() const override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
GRenderWindow* render_window;
|
||||
};
|
||||
|
||||
class OpenGLRenderWidget : public RenderWidget {
|
||||
public:
|
||||
explicit OpenGLRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
|
||||
windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
|
||||
}
|
||||
|
||||
void SetContext(std::unique_ptr<OpenGLSharedContext>&& context_) {
|
||||
context = std::move(context_);
|
||||
}
|
||||
|
||||
void Present() override {
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
if (!Core::System::GetInstance().IsPoweredOn()) {
|
||||
return;
|
||||
}
|
||||
context->MakeCurrent();
|
||||
const auto f = context->GetShareContext()->extraFunctions();
|
||||
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
VideoCore::g_renderer->TryPresent(100);
|
||||
context->SwapBuffers();
|
||||
f->glFinish();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<OpenGLSharedContext> context{};
|
||||
};
|
||||
|
||||
class VulkanRenderWidget : public RenderWidget {
|
||||
public:
|
||||
explicit VulkanRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
|
||||
windowHandle()->setSurfaceType(QWindow::VulkanSurface);
|
||||
}
|
||||
};
|
||||
|
||||
static Frontend::WindowSystemType GetWindowSystemType() {
|
||||
// Determine WSI type based on Qt platform.
|
||||
QString platform_name = QGuiApplication::platformName();
|
||||
if (platform_name == QStringLiteral("windows"))
|
||||
return Frontend::WindowSystemType::Windows;
|
||||
else if (platform_name == QStringLiteral("xcb"))
|
||||
return Frontend::WindowSystemType::X11;
|
||||
else if (platform_name == QStringLiteral("wayland"))
|
||||
return Frontend::WindowSystemType::Wayland;
|
||||
else if (platform_name == QStringLiteral("cocoa"))
|
||||
return Frontend::WindowSystemType::MacOS;
|
||||
|
||||
LOG_CRITICAL(Frontend, "Unknown Qt platform!");
|
||||
return Frontend::WindowSystemType::Windows;
|
||||
}
|
||||
|
||||
void OpenGLWindow::exposeEvent(QExposeEvent* event) {
|
||||
QWindow::requestUpdate();
|
||||
QWindow::exposeEvent(event);
|
||||
static Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) {
|
||||
Frontend::EmuWindow::WindowSystemInfo wsi;
|
||||
wsi.type = GetWindowSystemType();
|
||||
|
||||
// Our Win32 Qt external doesn't have the private API.
|
||||
#if defined(WIN32) || defined(__APPLE__)
|
||||
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
|
||||
#else
|
||||
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
|
||||
wsi.display_connection = pni->nativeResourceForWindow("display", window);
|
||||
if (wsi.type == Frontend::WindowSystemType::Wayland)
|
||||
wsi.render_surface = window ? pni->nativeResourceForWindow("surface", window) : nullptr;
|
||||
else
|
||||
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
|
||||
#endif
|
||||
wsi.render_surface_scale = window ? static_cast<float>(window->devicePixelRatio()) : 1.0f;
|
||||
|
||||
return wsi;
|
||||
}
|
||||
|
||||
GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread)
|
||||
@ -218,11 +371,11 @@ GRenderWindow::~GRenderWindow() {
|
||||
}
|
||||
|
||||
void GRenderWindow::MakeCurrent() {
|
||||
core_context->MakeCurrent();
|
||||
main_context->MakeCurrent();
|
||||
}
|
||||
|
||||
void GRenderWindow::DoneCurrent() {
|
||||
core_context->DoneCurrent();
|
||||
main_context->DoneCurrent();
|
||||
}
|
||||
|
||||
void GRenderWindow::PollEvents() {
|
||||
@ -387,33 +540,70 @@ void GRenderWindow::resizeEvent(QResizeEvent* event) {
|
||||
OnFramebufferSizeChanged();
|
||||
}
|
||||
|
||||
void GRenderWindow::InitRenderTarget() {
|
||||
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
|
||||
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api;
|
||||
if (graphics_api == Settings::GraphicsAPI::OpenGL ||
|
||||
graphics_api == Settings::GraphicsAPI::OpenGLES) {
|
||||
auto c = static_cast<OpenGLSharedContext*>(main_context.get());
|
||||
// Bind the shared contexts to the main surface in case the backend wants to take over
|
||||
// presentation
|
||||
return std::make_unique<OpenGLSharedContext>(c->GetShareContext(),
|
||||
child_widget->windowHandle());
|
||||
}
|
||||
|
||||
return std::make_unique<DummyContext>();
|
||||
}
|
||||
|
||||
bool GRenderWindow::InitRenderTarget() {
|
||||
ReleaseRenderTarget();
|
||||
|
||||
{
|
||||
// Create a dummy render widget so that Qt
|
||||
// places the render window at the correct position.
|
||||
const RenderWidget dummy_widget{this};
|
||||
}
|
||||
|
||||
first_frame = false;
|
||||
|
||||
GMainWindow* parent = GetMainWindow();
|
||||
QWindow* parent_win_handle = parent ? parent->windowHandle() : nullptr;
|
||||
child_window = new OpenGLWindow(parent_win_handle, this, QOpenGLContext::globalShareContext());
|
||||
child_window->create();
|
||||
child_widget = createWindowContainer(child_window, this);
|
||||
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api;
|
||||
switch (graphics_api) {
|
||||
case Settings::GraphicsAPI::OpenGL:
|
||||
case Settings::GraphicsAPI::OpenGLES:
|
||||
if (!InitializeOpenGL()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Settings::GraphicsAPI::Vulkan:
|
||||
if (!InitializeVulkan()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Update the Window System information with the new render target
|
||||
window_info = GetWindowSystemInfo(child_widget->windowHandle());
|
||||
|
||||
child_widget->resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
|
||||
|
||||
layout()->addWidget(child_widget);
|
||||
// Reset minimum required size to avoid resizing issues on the main window after restarting.
|
||||
setMinimumSize(1, 1);
|
||||
|
||||
core_context = CreateSharedContext();
|
||||
resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
|
||||
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
||||
OnFramebufferSizeChanged();
|
||||
BackupGeometry();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GRenderWindow::ReleaseRenderTarget() {
|
||||
if (child_widget) {
|
||||
layout()->removeWidget(child_widget);
|
||||
delete child_widget;
|
||||
child_widget->deleteLater();
|
||||
child_widget = nullptr;
|
||||
}
|
||||
main_context.reset();
|
||||
}
|
||||
|
||||
void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) {
|
||||
@ -423,7 +613,7 @@ void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_p
|
||||
screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32);
|
||||
VideoCore::RequestScreenshot(
|
||||
screenshot_image.bits(),
|
||||
[=] {
|
||||
[this, &screenshot_path] {
|
||||
const std::string std_screenshot_path = screenshot_path.toStdString();
|
||||
if (screenshot_image.mirrored(false, true).save(screenshot_path)) {
|
||||
LOG_INFO(Frontend, "Screenshot saved to \"{}\"", std_screenshot_path);
|
||||
@ -438,6 +628,29 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal
|
||||
setMinimumSize(minimal_size.first, minimal_size.second);
|
||||
}
|
||||
|
||||
bool GRenderWindow::InitializeOpenGL() {
|
||||
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
|
||||
// WA_DontShowOnScreen, WA_DeleteOnClose
|
||||
auto child = new OpenGLRenderWidget(this);
|
||||
child_widget = child;
|
||||
child_widget->windowHandle()->create();
|
||||
auto context = std::make_shared<OpenGLSharedContext>(child->windowHandle());
|
||||
main_context = context;
|
||||
child->SetContext(
|
||||
std::make_unique<OpenGLSharedContext>(context->GetShareContext(), child->windowHandle()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GRenderWindow::InitializeVulkan() {
|
||||
auto child = new VulkanRenderWidget(this);
|
||||
child_widget = child;
|
||||
child_widget->windowHandle()->create();
|
||||
main_context = std::make_unique<DummyContext>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) {
|
||||
this->emu_thread = emu_thread;
|
||||
}
|
||||
@ -449,31 +662,3 @@ void GRenderWindow::OnEmulationStopping() {
|
||||
void GRenderWindow::showEvent(QShowEvent* event) {
|
||||
QWidget::showEvent(event);
|
||||
}
|
||||
|
||||
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
|
||||
return std::make_unique<GLContext>(QOpenGLContext::globalShareContext());
|
||||
}
|
||||
|
||||
GLContext::GLContext(QOpenGLContext* shared_context)
|
||||
: context(std::make_unique<QOpenGLContext>(shared_context->parent())),
|
||||
surface(std::make_unique<QOffscreenSurface>(nullptr)) {
|
||||
|
||||
// disable vsync for any shared contexts
|
||||
auto format = shared_context->format();
|
||||
format.setSwapInterval(0);
|
||||
|
||||
context->setShareContext(shared_context);
|
||||
context->setFormat(format);
|
||||
context->create();
|
||||
surface->setParent(shared_context->parent());
|
||||
surface->setFormat(format);
|
||||
surface->create();
|
||||
}
|
||||
|
||||
void GLContext::MakeCurrent() {
|
||||
context->makeCurrent(surface.get());
|
||||
}
|
||||
|
||||
void GLContext::DoneCurrent() {
|
||||
context->doneCurrent();
|
||||
}
|
||||
|
@ -27,19 +27,6 @@ namespace VideoCore {
|
||||
enum class LoadCallbackStage;
|
||||
}
|
||||
|
||||
class GLContext : public Frontend::GraphicsContext {
|
||||
public:
|
||||
explicit GLContext(QOpenGLContext* shared_context);
|
||||
|
||||
void MakeCurrent() override;
|
||||
|
||||
void DoneCurrent() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<QOpenGLContext> context;
|
||||
std::unique_ptr<QOffscreenSurface> surface;
|
||||
};
|
||||
|
||||
class EmuThread final : public QThread {
|
||||
Q_OBJECT
|
||||
|
||||
@ -126,24 +113,6 @@ signals:
|
||||
void HideLoadingScreen();
|
||||
};
|
||||
|
||||
class OpenGLWindow : public QWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context);
|
||||
|
||||
~OpenGLWindow();
|
||||
|
||||
void Present();
|
||||
|
||||
protected:
|
||||
bool event(QEvent* event) override;
|
||||
void exposeEvent(QExposeEvent* event) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<QOpenGLContext> context;
|
||||
QWidget* event_handler;
|
||||
};
|
||||
|
||||
class GRenderWindow : public QWidget, public Frontend::EmuWindow {
|
||||
Q_OBJECT
|
||||
|
||||
@ -179,13 +148,15 @@ public:
|
||||
|
||||
void focusOutEvent(QFocusEvent* event) override;
|
||||
|
||||
void InitRenderTarget();
|
||||
bool InitRenderTarget();
|
||||
|
||||
/// Destroy the previous run's child_widget which should also destroy the child_window
|
||||
void ReleaseRenderTarget();
|
||||
|
||||
void CaptureScreenshot(u32 res_scale, const QString& screenshot_path);
|
||||
|
||||
std::pair<u32, u32> ScaleTouch(const QPointF pos) const;
|
||||
|
||||
public slots:
|
||||
|
||||
void OnEmulationStarting(EmuThread* emu_thread);
|
||||
@ -205,29 +176,29 @@ signals:
|
||||
void MouseActivity();
|
||||
|
||||
private:
|
||||
std::pair<u32, u32> ScaleTouch(QPointF pos) const;
|
||||
void TouchBeginEvent(const QTouchEvent* event);
|
||||
void TouchUpdateEvent(const QTouchEvent* event);
|
||||
void TouchEndEvent();
|
||||
|
||||
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
||||
|
||||
std::unique_ptr<GraphicsContext> core_context;
|
||||
|
||||
QByteArray geometry;
|
||||
|
||||
/// Native window handle that backs this presentation widget
|
||||
QWindow* child_window = nullptr;
|
||||
|
||||
/// In order to embed the window into GRenderWindow, you need to use createWindowContainer to
|
||||
/// put the child_window into a widget then add it to the layout. This child_widget can be
|
||||
/// parented to GRenderWindow and use Qt's lifetime system
|
||||
QWidget* child_widget = nullptr;
|
||||
bool InitializeOpenGL();
|
||||
bool InitializeVulkan();
|
||||
|
||||
EmuThread* emu_thread;
|
||||
|
||||
// Main context that will be shared with all other contexts that are requested.
|
||||
// If this is used in a shared context setting, then this should not be used directly, but
|
||||
// should instead be shared from
|
||||
std::shared_ptr<Frontend::GraphicsContext> main_context;
|
||||
|
||||
/// Temporary storage of the screenshot taken
|
||||
QImage screenshot_image;
|
||||
|
||||
QByteArray geometry;
|
||||
|
||||
QWidget* child_widget = nullptr;
|
||||
|
||||
bool first_frame = false;
|
||||
|
||||
protected:
|
||||
|
@ -37,7 +37,7 @@ CheatDialog::CheatDialog(QWidget* parent)
|
||||
connect(ui->textNotes, &QPlainTextEdit::textChanged, this, &CheatDialog::OnTextEdited);
|
||||
connect(ui->textCode, &QPlainTextEdit::textChanged, this, &CheatDialog::OnTextEdited);
|
||||
|
||||
connect(ui->buttonSave, &QPushButton::clicked,
|
||||
connect(ui->buttonSave, &QPushButton::clicked, this,
|
||||
[this] { SaveCheat(ui->tableCheats->currentRow()); });
|
||||
connect(ui->buttonDelete, &QPushButton::clicked, this, &CheatDialog::OnDeleteCheat);
|
||||
|
||||
@ -91,7 +91,7 @@ bool CheatDialog::SaveCheat(int row) {
|
||||
}
|
||||
|
||||
// Check if the cheat lines are valid
|
||||
auto code_lines = ui->textCode->toPlainText().split(QLatin1Char{'\n'}, QString::SkipEmptyParts);
|
||||
auto code_lines = ui->textCode->toPlainText().split(QLatin1Char{'\n'}, Qt::SkipEmptyParts);
|
||||
for (int i = 0; i < code_lines.size(); ++i) {
|
||||
Cheats::GatewayCheat::CheatLine cheat_line(code_lines[i].toStdString());
|
||||
if (cheat_line.valid)
|
||||
@ -190,8 +190,9 @@ void CheatDialog::OnDeleteCheat() {
|
||||
if (newly_created) {
|
||||
newly_created = false;
|
||||
} else {
|
||||
Core::System::GetInstance().CheatEngine().RemoveCheat(ui->tableCheats->currentRow());
|
||||
Core::System::GetInstance().CheatEngine().SaveCheatFile();
|
||||
auto& cheat_engine = Core::System::GetInstance().CheatEngine();
|
||||
cheat_engine.RemoveCheat(ui->tableCheats->currentRow());
|
||||
cheat_engine.SaveCheatFile();
|
||||
}
|
||||
|
||||
LoadCheats();
|
||||
|
@ -327,6 +327,9 @@ void Config::ReadDebuggingValues() {
|
||||
qt_config->value(QStringLiteral("record_frame_times"), false).toBool();
|
||||
Settings::values.use_gdbstub = ReadSetting(QStringLiteral("use_gdbstub"), false).toBool();
|
||||
Settings::values.gdbstub_port = ReadSetting(QStringLiteral("gdbstub_port"), 24689).toInt();
|
||||
Settings::values.renderer_debug = ReadSetting(QStringLiteral("renderer_debug"), false).toBool();
|
||||
Settings::values.dump_command_buffers =
|
||||
ReadSetting(QStringLiteral("dump_command_buffers"), false).toBool();
|
||||
|
||||
qt_config->beginGroup(QStringLiteral("LLE"));
|
||||
for (const auto& service_module : Service::service_module_map) {
|
||||
@ -478,6 +481,12 @@ void Config::ReadPathValues() {
|
||||
void Config::ReadRendererValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Renderer"));
|
||||
|
||||
Settings::values.graphics_api = static_cast<Settings::GraphicsAPI>(
|
||||
ReadSetting(QStringLiteral("graphics_api"), static_cast<u32>(Settings::GraphicsAPI::OpenGL))
|
||||
.toUInt());
|
||||
Settings::values.physical_device = ReadSetting(QStringLiteral("physical_device"), 0).toUInt();
|
||||
Settings::values.async_command_recording = ReadSetting(QStringLiteral("async_command_recording"), true).toBool();
|
||||
Settings::values.spirv_shader_gen = ReadSetting(QStringLiteral("spirv_shader_gen"), false).toBool();
|
||||
Settings::values.use_hw_renderer =
|
||||
ReadSetting(QStringLiteral("use_hw_renderer"), true).toBool();
|
||||
Settings::values.use_hw_shader = ReadSetting(QStringLiteral("use_hw_shader"), true).toBool();
|
||||
@ -517,7 +526,7 @@ void Config::ReadRendererValues() {
|
||||
void Config::ReadShortcutValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Shortcuts"));
|
||||
|
||||
for (auto [name, group, shortcut] : default_hotkeys) {
|
||||
for (const auto& [name, group, shortcut] : default_hotkeys) {
|
||||
auto [keyseq, context] = shortcut;
|
||||
qt_config->beginGroup(group);
|
||||
qt_config->beginGroup(name);
|
||||
@ -552,7 +561,7 @@ void Config::ReadSystemValues() {
|
||||
// https://developers.google.com/media/vp9/live-encoding
|
||||
const QString DEFAULT_VIDEO_ENCODER_OPTIONS =
|
||||
QStringLiteral("quality:realtime,speed:6,tile-columns:4,frame-parallel:1,threads:8,row-mt:1");
|
||||
const QString DEFAULT_AUDIO_ENCODER_OPTIONS = QString{};
|
||||
const QString DEFAULT_AUDIO_ENCODER_OPTIONS = QStringLiteral("");
|
||||
|
||||
void Config::ReadVideoDumpingValues() {
|
||||
qt_config->beginGroup(QStringLiteral("VideoDumping"));
|
||||
@ -883,6 +892,9 @@ void Config::SaveDebuggingValues() {
|
||||
qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times);
|
||||
WriteSetting(QStringLiteral("use_gdbstub"), Settings::values.use_gdbstub, false);
|
||||
WriteSetting(QStringLiteral("gdbstub_port"), Settings::values.gdbstub_port, 24689);
|
||||
WriteSetting(QStringLiteral("renderer_debug"), Settings::values.renderer_debug, false);
|
||||
WriteSetting(QStringLiteral("dump_command_buffers"), Settings::values.dump_command_buffers,
|
||||
false);
|
||||
|
||||
qt_config->beginGroup(QStringLiteral("LLE"));
|
||||
for (const auto& service_module : Settings::values.lle_modules) {
|
||||
@ -991,6 +1003,11 @@ void Config::SavePathValues() {
|
||||
void Config::SaveRendererValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Renderer"));
|
||||
|
||||
WriteSetting(QStringLiteral("graphics_api"), static_cast<u32>(Settings::values.graphics_api),
|
||||
static_cast<u32>(Settings::GraphicsAPI::OpenGL));
|
||||
WriteSetting(QStringLiteral("physical_device"), Settings::values.physical_device, 0);
|
||||
WriteSetting(QStringLiteral("async_command_recording"), Settings::values.async_command_recording, true);
|
||||
WriteSetting(QStringLiteral("spirv_shader_gen"), Settings::values.spirv_shader_gen, false);
|
||||
WriteSetting(QStringLiteral("use_hw_renderer"), Settings::values.use_hw_renderer, true);
|
||||
WriteSetting(QStringLiteral("use_hw_shader"), Settings::values.use_hw_shader, true);
|
||||
#ifdef __APPLE__
|
||||
@ -1012,9 +1029,9 @@ void Config::SaveRendererValues() {
|
||||
200);
|
||||
|
||||
// Cast to double because Qt's written float values are not human-readable
|
||||
WriteSetting(QStringLiteral("bg_red"), (double)Settings::values.bg_red, 0.0);
|
||||
WriteSetting(QStringLiteral("bg_green"), (double)Settings::values.bg_green, 0.0);
|
||||
WriteSetting(QStringLiteral("bg_blue"), (double)Settings::values.bg_blue, 0.0);
|
||||
WriteSetting(QStringLiteral("bg_red"), static_cast<double>(Settings::values.bg_red), 0.0);
|
||||
WriteSetting(QStringLiteral("bg_green"), static_cast<double>(Settings::values.bg_green), 0.0);
|
||||
WriteSetting(QStringLiteral("bg_blue"), static_cast<double>(Settings::values.bg_blue), 0.0);
|
||||
|
||||
WriteSetting(QStringLiteral("texture_filter_name"),
|
||||
QString::fromStdString(Settings::values.texture_filter_name),
|
||||
|
@ -9,8 +9,6 @@
|
||||
#include <QMessageBox>
|
||||
#include <QWidget>
|
||||
#include "citra_qt/configuration/configure_camera.h"
|
||||
#include "citra_qt/uisettings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/camera/factory.h"
|
||||
#include "core/frontend/camera/interface.h"
|
||||
#include "core/hle/service/cam/cam.h"
|
||||
@ -91,7 +89,7 @@ void ConfigureCamera::ConnectEvents() {
|
||||
SetConfiguration();
|
||||
});
|
||||
connect(ui->toolButton, &QToolButton::clicked, this, &ConfigureCamera::OnToolButtonClicked);
|
||||
connect(ui->preview_button, &QPushButton::clicked, this, [=] { StartPreviewing(); });
|
||||
connect(ui->preview_button, &QPushButton::clicked, this, [this] { StartPreviewing(); });
|
||||
connect(ui->prompt_before_load, &QCheckBox::stateChanged, this, [this](int state) {
|
||||
ui->camera_file->setDisabled(state == Qt::Checked);
|
||||
ui->toolButton->setDisabled(state == Qt::Checked);
|
||||
@ -99,12 +97,11 @@ void ConfigureCamera::ConnectEvents() {
|
||||
ui->camera_file->setText(QString{});
|
||||
}
|
||||
});
|
||||
connect(ui->camera_file, &QLineEdit::textChanged, this, [=] { StopPreviewing(); });
|
||||
connect(ui->system_camera,
|
||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
||||
[=] { StopPreviewing(); });
|
||||
connect(ui->camera_flip, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
||||
this, [=] { StopPreviewing(); });
|
||||
connect(ui->camera_file, &QLineEdit::textChanged, this, [this] { StopPreviewing(); });
|
||||
connect(ui->system_camera, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
[this] { StopPreviewing(); });
|
||||
connect(ui->camera_flip, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
[this] { StopPreviewing(); });
|
||||
}
|
||||
|
||||
void ConfigureCamera::UpdateCameraMode() {
|
||||
|
@ -4,16 +4,17 @@
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QMessageBox>
|
||||
#include "citra_qt/configuration/configure_debug.h"
|
||||
#include "citra_qt/debugger/console.h"
|
||||
#include "citra_qt/uisettings.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/backend.h"
|
||||
#include "common/logging/filter.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/settings.h"
|
||||
#include "qcheckbox.h"
|
||||
#include "ui_configure_debug.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
|
||||
ConfigureDebug::ConfigureDebug(QWidget* parent)
|
||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureDebug>()) {
|
||||
@ -24,7 +25,41 @@ ConfigureDebug::ConfigureDebug(QWidget* parent)
|
||||
QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir));
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
||||
});
|
||||
ui->toggle_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
||||
|
||||
connect(ui->toggle_renderer_debug, &QCheckBox::clicked, this, [this](bool checked) {
|
||||
if (checked && Settings::values.graphics_api == Settings::GraphicsAPI::Vulkan) {
|
||||
try {
|
||||
Vulkan::Instance debug_inst{true};
|
||||
} catch (vk::LayerNotPresentError& err) {
|
||||
ui->toggle_renderer_debug->toggle();
|
||||
QMessageBox::warning(
|
||||
this, tr("Validation layer not available"),
|
||||
tr("Unable to enable debug renderer because the layer "
|
||||
"<strong>VK_LAYER_KHRONOS_validation</strong> is missing. "
|
||||
"Please install the Vulkan SDK or the appropriate package of your distribution"));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->toggle_dump_command_buffers, &QCheckBox::clicked, this, [this](bool checked) {
|
||||
if (checked && Settings::values.graphics_api == Settings::GraphicsAPI::Vulkan) {
|
||||
try {
|
||||
Vulkan::Instance debug_inst{false, true};
|
||||
} catch (vk::LayerNotPresentError& err) {
|
||||
ui->toggle_dump_command_buffers->toggle();
|
||||
QMessageBox::warning(
|
||||
this, tr("Command buffer dumping not available"),
|
||||
tr("Unable to enable command buffer dumping because the layer "
|
||||
"<strong>VK_LAYER_LUNARG_api_dump</strong> is missing. "
|
||||
"Please install the Vulkan SDK or the appropriate package of your distribution"));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const bool is_powered_on = Core::System::GetInstance().IsPoweredOn();
|
||||
ui->toggle_cpu_jit->setEnabled(!is_powered_on);
|
||||
ui->toggle_renderer_debug->setEnabled(!is_powered_on);
|
||||
ui->toggle_dump_command_buffers->setEnabled(!is_powered_on);
|
||||
}
|
||||
|
||||
ConfigureDebug::~ConfigureDebug() = default;
|
||||
@ -37,6 +72,8 @@ void ConfigureDebug::SetConfiguration() {
|
||||
ui->toggle_console->setChecked(UISettings::values.show_console);
|
||||
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter));
|
||||
ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit);
|
||||
ui->toggle_renderer_debug->setChecked(Settings::values.renderer_debug);
|
||||
ui->toggle_dump_command_buffers->setChecked(Settings::values.dump_command_buffers);
|
||||
}
|
||||
|
||||
void ConfigureDebug::ApplyConfiguration() {
|
||||
@ -49,6 +86,8 @@ void ConfigureDebug::ApplyConfiguration() {
|
||||
filter.ParseFilterString(Settings::values.log_filter);
|
||||
Log::SetGlobalFilter(filter);
|
||||
Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked();
|
||||
Settings::values.renderer_debug = ui->toggle_renderer_debug->isChecked();
|
||||
Settings::values.dump_command_buffers = ui->toggle_dump_command_buffers->isChecked();
|
||||
}
|
||||
|
||||
void ConfigureDebug::RetranslateUI() {
|
||||
|
@ -22,5 +22,6 @@ public:
|
||||
void RetranslateUI();
|
||||
void SetConfiguration();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::ConfigureDebug> ui;
|
||||
};
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>443</width>
|
||||
<height>300</height>
|
||||
<width>454</width>
|
||||
<height>356</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -114,11 +114,31 @@
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle_cpu_jit">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Enables the use of the ARM JIT compiler for emulating the 3DS CPUs. Don't disable unless for debugging purposes</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable CPU JIT</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle_renderer_debug">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Enables debug reporting in the currently selected graphics API. Causes measurable performance loss, don't enable unless for debugging purposes</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable debug renderer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle_dump_command_buffers">
|
||||
<property name="text">
|
||||
<string>Dump command buffers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -10,15 +10,28 @@
|
||||
#include "core/core.h"
|
||||
#include "core/settings.h"
|
||||
#include "ui_configure_graphics.h"
|
||||
#include "video_core/renderer_opengl/post_processing_opengl.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
|
||||
ConfigureGraphics::ConfigureGraphics(QWidget* parent)
|
||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureGraphics>()) {
|
||||
ui->setupUi(this);
|
||||
DiscoverPhysicalDevices();
|
||||
SetConfiguration();
|
||||
|
||||
ui->hw_renderer_group->setEnabled(ui->toggle_hw_renderer->isChecked());
|
||||
ui->toggle_vsync_new->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
||||
const bool not_running = !Core::System::GetInstance().IsPoweredOn();
|
||||
const bool hw_renderer_enabled = ui->toggle_hw_renderer->isChecked();
|
||||
ui->toggle_hw_renderer->setEnabled(not_running);
|
||||
ui->hw_renderer_group->setEnabled(hw_renderer_enabled && not_running);
|
||||
ui->toggle_vsync_new->setEnabled(not_running);
|
||||
ui->graphics_api_combo->setEnabled(not_running);
|
||||
ui->toggle_shader_jit->setEnabled(not_running);
|
||||
ui->toggle_disk_shader_cache->setEnabled(hw_renderer_enabled && not_running);
|
||||
ui->toggle_async_recording->setEnabled(hw_renderer_enabled && not_running);
|
||||
ui->physical_device_combo->setEnabled(not_running);
|
||||
SetPhysicalDeviceComboVisibility(ui->graphics_api_combo->currentIndex());
|
||||
|
||||
connect(ui->graphics_api_combo, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
&ConfigureGraphics::SetPhysicalDeviceComboVisibility);
|
||||
|
||||
connect(ui->toggle_hw_renderer, &QCheckBox::toggled, this, [this] {
|
||||
auto checked = ui->toggle_hw_renderer->isChecked();
|
||||
@ -31,7 +44,7 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
|
||||
ui->toggle_hw_shader->isChecked());
|
||||
|
||||
connect(ui->toggle_hw_shader, &QCheckBox::toggled, this, [this] {
|
||||
auto checked = ui->toggle_hw_shader->isChecked();
|
||||
const bool checked = ui->toggle_hw_shader->isChecked();
|
||||
ui->hw_shader_group->setEnabled(checked);
|
||||
ui->toggle_disk_shader_cache->setEnabled(checked);
|
||||
});
|
||||
@ -69,6 +82,10 @@ void ConfigureGraphics::SetConfiguration() {
|
||||
ui->toggle_shader_jit->setChecked(Settings::values.use_shader_jit);
|
||||
ui->toggle_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache);
|
||||
ui->toggle_vsync_new->setChecked(Settings::values.use_vsync_new);
|
||||
ui->graphics_api_combo->setCurrentIndex(static_cast<int>(Settings::values.graphics_api));
|
||||
ui->physical_device_combo->setCurrentIndex(static_cast<int>(Settings::values.physical_device));
|
||||
ui->toggle_async_recording->setChecked(Settings::values.async_command_recording);
|
||||
ui->spirv_shader_gen->setChecked(Settings::values.spirv_shader_gen);
|
||||
}
|
||||
|
||||
void ConfigureGraphics::ApplyConfiguration() {
|
||||
@ -79,8 +96,32 @@ void ConfigureGraphics::ApplyConfiguration() {
|
||||
Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked();
|
||||
Settings::values.use_disk_shader_cache = ui->toggle_disk_shader_cache->isChecked();
|
||||
Settings::values.use_vsync_new = ui->toggle_vsync_new->isChecked();
|
||||
Settings::values.graphics_api =
|
||||
static_cast<Settings::GraphicsAPI>(ui->graphics_api_combo->currentIndex());
|
||||
Settings::values.physical_device = static_cast<u16>(ui->physical_device_combo->currentIndex());
|
||||
Settings::values.async_command_recording = ui->toggle_async_recording->isChecked();
|
||||
Settings::values.spirv_shader_gen = ui->spirv_shader_gen->isChecked();
|
||||
}
|
||||
|
||||
void ConfigureGraphics::RetranslateUI() {
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
|
||||
void ConfigureGraphics::DiscoverPhysicalDevices() {
|
||||
Vulkan::Instance instance{};
|
||||
const auto physical_devices = instance.GetPhysicalDevices();
|
||||
|
||||
ui->physical_device_combo->clear();
|
||||
for (const vk::PhysicalDevice& physical_device : physical_devices) {
|
||||
const QString name = QString::fromLocal8Bit(physical_device.getProperties().deviceName);
|
||||
ui->physical_device_combo->addItem(name);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureGraphics::SetPhysicalDeviceComboVisibility(int index) {
|
||||
const auto graphics_api = static_cast<Settings::GraphicsAPI>(index);
|
||||
const bool is_visible = graphics_api == Settings::GraphicsAPI::Vulkan;
|
||||
ui->physical_device_label->setVisible(is_visible);
|
||||
ui->physical_device_combo->setVisible(is_visible);
|
||||
ui->spirv_shader_gen->setVisible(is_visible);
|
||||
}
|
||||
|
@ -24,6 +24,11 @@ public:
|
||||
|
||||
void UpdateBackgroundColorButton(const QColor& color);
|
||||
|
||||
private:
|
||||
void DiscoverPhysicalDevices();
|
||||
void SetPhysicalDeviceComboVisibility(int index);
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::ConfigureGraphics> ui;
|
||||
QColor bg_color;
|
||||
};
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>430</height>
|
||||
<height>513</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
@ -20,6 +20,66 @@
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="apiBox">
|
||||
<property name="title">
|
||||
<string>API Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="graphics_api_label">
|
||||
<property name="text">
|
||||
<string>Graphics API</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="graphics_api_combo">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>OpenGL</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>OpenGLES</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Vulkan</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="physical_device_label">
|
||||
<property name="text">
|
||||
<string>Physical device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="physical_device_combo"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="spirv_shader_gen">
|
||||
<property name="text">
|
||||
<string>SPIR-V Shader Generation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="rendererBox">
|
||||
<property name="title">
|
||||
@ -118,6 +178,16 @@
|
||||
<string>Advanced</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle_async_recording">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Offloads command buffer recording and fragment shader generation to a worker thread. Can improve performance especially on weaker systems. Disable if you notice better performance. If unsure leave it enabled,</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Async Command Recording</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle_disk_shader_cache">
|
||||
<property name="toolTip">
|
||||
|
@ -192,10 +192,10 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||
if (!button_map[button_id])
|
||||
continue;
|
||||
button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(button_map[button_id], &QPushButton::clicked, [=]() {
|
||||
connect(button_map[button_id], &QPushButton::clicked, [this, button_id]() {
|
||||
HandleClick(
|
||||
button_map[button_id],
|
||||
[=](const Common::ParamPackage& params) {
|
||||
[this, button_id](const Common::ParamPackage& params) {
|
||||
buttons_param[button_id] = params;
|
||||
// If the user closes the dialog, the changes are reverted in
|
||||
// `GMainWindow::OnConfigure()`
|
||||
@ -204,16 +204,16 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||
},
|
||||
InputCommon::Polling::DeviceType::Button);
|
||||
});
|
||||
connect(button_map[button_id], &QPushButton::customContextMenuRequested,
|
||||
[=](const QPoint& menu_location) {
|
||||
connect(button_map[button_id], &QPushButton::customContextMenuRequested, this,
|
||||
[this, button_id](const QPoint& menu_location) {
|
||||
QMenu context_menu;
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
context_menu.addAction(tr("Clear"), this, [&] {
|
||||
buttons_param[button_id].Clear();
|
||||
button_map[button_id]->setText(tr("[not set]"));
|
||||
ApplyConfiguration();
|
||||
Settings::SaveProfile(ui->profile->currentIndex());
|
||||
});
|
||||
context_menu.addAction(tr("Restore Default"), [&] {
|
||||
context_menu.addAction(tr("Restore Default"), this, [&] {
|
||||
buttons_param[button_id] = Common::ParamPackage{
|
||||
InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
|
||||
button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
|
||||
@ -230,27 +230,29 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||
continue;
|
||||
analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy(
|
||||
Qt::CustomContextMenu);
|
||||
connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, [=]() {
|
||||
HandleClick(
|
||||
analog_map_buttons[analog_id][sub_button_id],
|
||||
[=](const Common::ParamPackage& params) {
|
||||
SetAnalogButton(params, analogs_param[analog_id],
|
||||
analog_sub_buttons[sub_button_id]);
|
||||
ApplyConfiguration();
|
||||
Settings::SaveProfile(ui->profile->currentIndex());
|
||||
},
|
||||
InputCommon::Polling::DeviceType::Button);
|
||||
});
|
||||
connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, this,
|
||||
[this, analog_id, sub_button_id]() {
|
||||
HandleClick(
|
||||
analog_map_buttons[analog_id][sub_button_id],
|
||||
[this, analog_id, sub_button_id](const Common::ParamPackage& params) {
|
||||
SetAnalogButton(params, analogs_param[analog_id],
|
||||
analog_sub_buttons[sub_button_id]);
|
||||
ApplyConfiguration();
|
||||
Settings::SaveProfile(ui->profile->currentIndex());
|
||||
},
|
||||
InputCommon::Polling::DeviceType::Button);
|
||||
});
|
||||
connect(analog_map_buttons[analog_id][sub_button_id],
|
||||
&QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) {
|
||||
&QPushButton::customContextMenuRequested, this,
|
||||
[this, analog_id, sub_button_id](const QPoint& menu_location) {
|
||||
QMenu context_menu;
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
context_menu.addAction(tr("Clear"), this, [&] {
|
||||
analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
|
||||
analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
|
||||
ApplyConfiguration();
|
||||
Settings::SaveProfile(ui->profile->currentIndex());
|
||||
});
|
||||
context_menu.addAction(tr("Restore Default"), [&] {
|
||||
context_menu.addAction(tr("Restore Default"), this, [&] {
|
||||
Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
|
||||
Config::default_analogs[analog_id][sub_button_id])};
|
||||
SetAnalogButton(params, analogs_param[analog_id],
|
||||
@ -264,7 +266,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||
menu_location));
|
||||
});
|
||||
}
|
||||
connect(analog_map_stick[analog_id], &QPushButton::clicked, [=]() {
|
||||
connect(analog_map_stick[analog_id], &QPushButton::clicked, this, [this, analog_id]() {
|
||||
if (QMessageBox::information(
|
||||
this, tr("Information"),
|
||||
tr("After pressing OK, first move your joystick horizontally, "
|
||||
@ -272,7 +274,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||
QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
|
||||
HandleClick(
|
||||
analog_map_stick[analog_id],
|
||||
[=](const Common::ParamPackage& params) {
|
||||
[this, analog_id](const Common::ParamPackage& params) {
|
||||
analogs_param[analog_id] = params;
|
||||
ApplyConfiguration();
|
||||
Settings::SaveProfile(ui->profile->currentIndex());
|
||||
@ -280,29 +282,31 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||
InputCommon::Polling::DeviceType::Analog);
|
||||
}
|
||||
});
|
||||
connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, [=] {
|
||||
const int slider_value = analog_map_deadzone_and_modifier_slider[analog_id]->value();
|
||||
const auto engine = analogs_param[analog_id].Get("engine", "");
|
||||
if (engine == "sdl" || engine == "gcpad") {
|
||||
analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
|
||||
tr("Deadzone: %1%").arg(slider_value));
|
||||
analogs_param[analog_id].Set("deadzone", slider_value / 100.0f);
|
||||
} else {
|
||||
analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
|
||||
tr("Modifier Scale: %1%").arg(slider_value));
|
||||
analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f);
|
||||
}
|
||||
ApplyConfiguration();
|
||||
Settings::SaveProfile(ui->profile->currentIndex());
|
||||
});
|
||||
connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, this,
|
||||
[this, analog_id] {
|
||||
const int slider_value =
|
||||
analog_map_deadzone_and_modifier_slider[analog_id]->value();
|
||||
const auto engine = analogs_param[analog_id].Get("engine", "");
|
||||
if (engine == "sdl" || engine == "gcpad") {
|
||||
analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
|
||||
tr("Deadzone: %1%").arg(slider_value));
|
||||
analogs_param[analog_id].Set("deadzone", slider_value / 100.0f);
|
||||
} else {
|
||||
analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
|
||||
tr("Modifier Scale: %1%").arg(slider_value));
|
||||
analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f);
|
||||
}
|
||||
ApplyConfiguration();
|
||||
Settings::SaveProfile(ui->profile->currentIndex());
|
||||
});
|
||||
}
|
||||
|
||||
// The Circle Mod button is common for both the sticks, so update the modifier settings
|
||||
// for both the sticks.
|
||||
connect(ui->buttonCircleMod, &QPushButton::clicked, [=]() {
|
||||
connect(ui->buttonCircleMod, &QPushButton::clicked, this, [this]() {
|
||||
HandleClick(
|
||||
ui->buttonCircleMod,
|
||||
[=](const Common::ParamPackage& params) {
|
||||
[this](const Common::ParamPackage& params) {
|
||||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs;
|
||||
analog_id++) {
|
||||
SetAnalogButton(params, analogs_param[analog_id], "modifier");
|
||||
@ -312,10 +316,10 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||
},
|
||||
InputCommon::Polling::DeviceType::Button);
|
||||
});
|
||||
connect(ui->buttonCircleMod, &QPushButton::customContextMenuRequested,
|
||||
connect(ui->buttonCircleMod, &QPushButton::customContextMenuRequested, this,
|
||||
[&](const QPoint& menu_location) {
|
||||
QMenu context_menu;
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
context_menu.addAction(tr("Clear"), this, [&] {
|
||||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs;
|
||||
analog_id++) {
|
||||
analogs_param[analog_id].Erase("modifier");
|
||||
@ -325,7 +329,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||
Settings::SaveProfile(ui->profile->currentIndex());
|
||||
});
|
||||
|
||||
context_menu.addAction(tr("Restore Default"), [&] {
|
||||
context_menu.addAction(tr("Restore Default"), this, [&] {
|
||||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs;
|
||||
analog_id++) {
|
||||
Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
|
||||
@ -341,7 +345,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||
context_menu.exec(ui->buttonCircleMod->mapToGlobal(menu_location));
|
||||
});
|
||||
|
||||
connect(ui->buttonMotionTouch, &QPushButton::clicked, [this] {
|
||||
connect(ui->buttonMotionTouch, &QPushButton::clicked, this, [this] {
|
||||
QDialog* motion_touch_dialog = new ConfigureMotionTouch(this);
|
||||
return motion_touch_dialog->exec();
|
||||
});
|
||||
@ -356,18 +360,17 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||
connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureInput::DeleteProfile);
|
||||
connect(ui->buttonRename, &QPushButton::clicked, this, &ConfigureInput::RenameProfile);
|
||||
|
||||
connect(ui->profile, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
||||
[this](int i) {
|
||||
ApplyConfiguration();
|
||||
Settings::SaveProfile(Settings::values.current_input_profile_index);
|
||||
Settings::LoadProfile(i);
|
||||
LoadConfiguration();
|
||||
});
|
||||
connect(ui->profile, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int i) {
|
||||
ApplyConfiguration();
|
||||
Settings::SaveProfile(Settings::values.current_input_profile_index);
|
||||
Settings::LoadProfile(i);
|
||||
LoadConfiguration();
|
||||
});
|
||||
|
||||
timeout_timer->setSingleShot(true);
|
||||
connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); });
|
||||
connect(timeout_timer.get(), &QTimer::timeout, this, [this]() { SetPollingResult({}, true); });
|
||||
|
||||
connect(poll_timer.get(), &QTimer::timeout, [this]() {
|
||||
connect(poll_timer.get(), &QTimer::timeout, this, [this]() {
|
||||
Common::ParamPackage params;
|
||||
for (auto& poller : device_pollers) {
|
||||
params = poller->GetNextInput();
|
||||
@ -554,7 +557,7 @@ void ConfigureInput::AutoMap() {
|
||||
QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) {
|
||||
return;
|
||||
}
|
||||
input_setter = [=](const Common::ParamPackage& params) {
|
||||
input_setter = [this](const Common::ParamPackage& params) {
|
||||
MapFromButton(params);
|
||||
ApplyConfiguration();
|
||||
Settings::SaveProfile(ui->profile->currentIndex());
|
||||
|
@ -46,6 +46,9 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
|
||||
case CalibrationConfigurationJob::Status::Completed:
|
||||
text = tr("Configuration completed!");
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR(Frontend, "Unknown calibration status {}", status);
|
||||
break;
|
||||
}
|
||||
QMetaObject::invokeMethod(this, "UpdateLabelText", Q_ARG(QString, text));
|
||||
if (status == CalibrationConfigurationJob::Status::Completed) {
|
||||
@ -99,9 +102,9 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent)
|
||||
"style=\"text-decoration: underline; color:#039be5;\">Learn More</span></a>"));
|
||||
|
||||
timeout_timer->setSingleShot(true);
|
||||
connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); });
|
||||
connect(timeout_timer.get(), &QTimer::timeout, this, [this]() { SetPollingResult({}, true); });
|
||||
|
||||
connect(poll_timer.get(), &QTimer::timeout, [this]() {
|
||||
connect(poll_timer.get(), &QTimer::timeout, this, [this]() {
|
||||
Common::ParamPackage params;
|
||||
for (auto& poller : device_pollers) {
|
||||
params = poller->GetNextInput();
|
||||
@ -202,7 +205,7 @@ void ConfigureMotionTouch::ConnectEvents() {
|
||||
connect(ui->touch_provider,
|
||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
||||
[this]([[maybe_unused]] int index) { UpdateUiDisplay(); });
|
||||
connect(ui->motion_controller_button, &QPushButton::clicked, [=]() {
|
||||
connect(ui->motion_controller_button, &QPushButton::clicked, this, [this]() {
|
||||
if (QMessageBox::information(this, tr("Information"),
|
||||
tr("After pressing OK, press a button on the controller whose "
|
||||
"motion you want to track."),
|
||||
@ -210,7 +213,7 @@ void ConfigureMotionTouch::ConnectEvents() {
|
||||
ui->motion_controller_button->setText(tr("[press button]"));
|
||||
ui->motion_controller_button->setFocus();
|
||||
|
||||
input_setter = [=](const Common::ParamPackage& params) {
|
||||
input_setter = [this](const Common::ParamPackage& params) {
|
||||
guid = params.Get("guid", "0");
|
||||
port = params.Get("port", 0);
|
||||
};
|
||||
|
@ -508,7 +508,7 @@ void TouchScreenPreview::mouseMoveEvent(QMouseEvent* event) {
|
||||
}
|
||||
const auto pos = MapToDeviceCoords(event->x(), event->y());
|
||||
if (pos) {
|
||||
coord_label->setText(QStringLiteral("X: %1, Y: %2").arg(pos->x()).arg(pos->y()));
|
||||
coord_label->setText(QStringLiteral("X: %1, Y: %2").arg(pos->x(), pos->y()));
|
||||
} else {
|
||||
coord_label->clear();
|
||||
}
|
||||
@ -568,7 +568,7 @@ bool TouchScreenPreview::eventFilter(QObject* obj, QEvent* event) {
|
||||
emit DotMoved(drag_state.dot->property(PropId).toInt(), *device_coord);
|
||||
if (coord_label) {
|
||||
coord_label->setText(
|
||||
QStringLiteral("X: %1, Y: %2").arg(device_coord->x()).arg(device_coord->y()));
|
||||
QStringLiteral("X: %1, Y: %2").arg(device_coord->x(), device_coord->y()));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include <QVBoxLayout>
|
||||
#include "citra_qt/debugger/graphics/graphics_breakpoints.h"
|
||||
#include "citra_qt/debugger/graphics/graphics_breakpoints_p.h"
|
||||
#include "common/assert.h"
|
||||
|
||||
BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_context, QObject* parent)
|
||||
: QAbstractListModel(parent), context_weak(debug_context),
|
||||
@ -60,12 +59,15 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const {
|
||||
}
|
||||
|
||||
Qt::ItemFlags BreakPointModel::flags(const QModelIndex& index) const {
|
||||
if (!index.isValid())
|
||||
return 0;
|
||||
if (!index.isValid()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Qt::ItemFlags flags = Qt::ItemIsEnabled;
|
||||
if (index.column() == 0)
|
||||
if (index.column() == 0) {
|
||||
flags |= Qt::ItemIsUserCheckable;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include <QTreeView>
|
||||
#include <QVBoxLayout>
|
||||
#include "citra_qt/debugger/graphics/graphics_cmdlists.h"
|
||||
#include "citra_qt/util/spinbox.h"
|
||||
#include "citra_qt/util/util.h"
|
||||
#include "common/vector_math.h"
|
||||
#include "core/core.h"
|
||||
@ -130,7 +129,7 @@ void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
|
||||
COMMAND_IN_RANGE(command_id, texturing.texture1) ||
|
||||
COMMAND_IN_RANGE(command_id, texturing.texture2)) {
|
||||
|
||||
unsigned texture_index;
|
||||
[[maybe_unused]] u32 texture_index;
|
||||
if (COMMAND_IN_RANGE(command_id, texturing.texture0)) {
|
||||
texture_index = 0;
|
||||
} else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) {
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "citra_qt/util/spinbox.h"
|
||||
#include "common/color.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hw/gpu.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/pica_state.h"
|
||||
#include "video_core/regs_framebuffer.h"
|
||||
@ -34,12 +33,15 @@ void SurfacePicture::mousePressEvent(QMouseEvent* event) {
|
||||
if (!(event->buttons() & Qt::LeftButton))
|
||||
return;
|
||||
|
||||
if (pixmap() == nullptr)
|
||||
const QPixmap pixmap = this->pixmap(Qt::ReturnByValue);
|
||||
if (pixmap.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (surface_widget)
|
||||
surface_widget->Pick(event->x() * pixmap()->width() / width(),
|
||||
event->y() * pixmap()->height() / height());
|
||||
if (surface_widget) {
|
||||
surface_widget->Pick(event->x() * pixmap.width() / width(),
|
||||
event->y() * pixmap.height() / height());
|
||||
}
|
||||
}
|
||||
|
||||
void SurfacePicture::mouseMoveEvent(QMouseEvent* event) {
|
||||
@ -314,57 +316,46 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
||||
case Format::RGBA8: {
|
||||
auto value = Color::DecodeRGBA8(pixel) / 255.0f;
|
||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
||||
.arg(QString::number(value.r(), 'f', 2))
|
||||
.arg(QString::number(value.g(), 'f', 2))
|
||||
.arg(QString::number(value.b(), 'f', 2))
|
||||
.arg(QString::number(value.a(), 'f', 2));
|
||||
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
||||
QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
|
||||
}
|
||||
case Format::RGB8: {
|
||||
auto value = Color::DecodeRGB8(pixel) / 255.0f;
|
||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3")
|
||||
.arg(QString::number(value.r(), 'f', 2))
|
||||
.arg(QString::number(value.g(), 'f', 2))
|
||||
.arg(QString::number(value.b(), 'f', 2));
|
||||
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
||||
QString::number(value.b(), 'f', 2));
|
||||
}
|
||||
case Format::RGB5A1: {
|
||||
auto value = Color::DecodeRGB5A1(pixel) / 255.0f;
|
||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
||||
.arg(QString::number(value.r(), 'f', 2))
|
||||
.arg(QString::number(value.g(), 'f', 2))
|
||||
.arg(QString::number(value.b(), 'f', 2))
|
||||
.arg(QString::number(value.a(), 'f', 2));
|
||||
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
||||
QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
|
||||
}
|
||||
case Format::RGB565: {
|
||||
auto value = Color::DecodeRGB565(pixel) / 255.0f;
|
||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3")
|
||||
.arg(QString::number(value.r(), 'f', 2))
|
||||
.arg(QString::number(value.g(), 'f', 2))
|
||||
.arg(QString::number(value.b(), 'f', 2));
|
||||
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
||||
QString::number(value.b(), 'f', 2));
|
||||
}
|
||||
case Format::RGBA4: {
|
||||
auto value = Color::DecodeRGBA4(pixel) / 255.0f;
|
||||
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
|
||||
.arg(QString::number(value.r(), 'f', 2))
|
||||
.arg(QString::number(value.g(), 'f', 2))
|
||||
.arg(QString::number(value.b(), 'f', 2))
|
||||
.arg(QString::number(value.a(), 'f', 2));
|
||||
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
|
||||
QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
|
||||
}
|
||||
case Format::IA8:
|
||||
return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0]).arg(pixel[1]);
|
||||
return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0], pixel[1]);
|
||||
case Format::RG8: {
|
||||
auto value = Color::DecodeRG8(pixel) / 255.0f;
|
||||
return QStringLiteral("Red: %1, Green: %2")
|
||||
.arg(QString::number(value.r(), 'f', 2))
|
||||
.arg(QString::number(value.g(), 'f', 2));
|
||||
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2));
|
||||
}
|
||||
case Format::I8:
|
||||
return QStringLiteral("Index: %1").arg(*pixel);
|
||||
case Format::A8:
|
||||
return QStringLiteral("Alpha: %1").arg(QString::number(*pixel / 255.0f, 'f', 2));
|
||||
case Format::IA4:
|
||||
return QStringLiteral("Index: %1, Alpha: %2")
|
||||
.arg(*pixel & 0xF)
|
||||
.arg((*pixel & 0xF0) >> 4);
|
||||
return QStringLiteral("Index: %1, Alpha: %2").arg(*pixel & 0xF, (*pixel & 0xF0) >> 4);
|
||||
case Format::I4: {
|
||||
u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF;
|
||||
return QStringLiteral("Index: %1").arg(i);
|
||||
@ -390,8 +381,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
||||
case Format::X24S8: {
|
||||
auto values = Color::DecodeD24S8(pixel);
|
||||
return QStringLiteral("Depth: %1, Stencil: %2")
|
||||
.arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4))
|
||||
.arg(values[1]);
|
||||
.arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4), values[1]);
|
||||
}
|
||||
case Format::Unknown:
|
||||
return QStringLiteral("Unknown format");
|
||||
@ -401,8 +391,8 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
||||
};
|
||||
|
||||
QString nibbles;
|
||||
for (unsigned i = 0; i < nibbles_per_pixel; i++) {
|
||||
unsigned nibble_index = i;
|
||||
for (u32 i = 0; i < nibbles_per_pixel; i++) {
|
||||
u32 nibble_index = i;
|
||||
if (nibble_mode) {
|
||||
nibble_index += (offset % 2) ? 0 : 1;
|
||||
}
|
||||
@ -412,7 +402,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
||||
}
|
||||
|
||||
surface_info_label->setText(
|
||||
QStringLiteral("Raw: 0x%3\n(%4)").arg(nibbles).arg(GetText(surface_format, pixel)));
|
||||
QStringLiteral("Raw: 0x%3\n(%4)").arg(nibbles, GetText(surface_format, pixel)));
|
||||
surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||||
}
|
||||
|
||||
@ -676,8 +666,8 @@ void GraphicsSurfaceWidget::SaveSurface() {
|
||||
}
|
||||
|
||||
if (selected_filter == png_filter) {
|
||||
const QPixmap* const pixmap = surface_picture_label->pixmap();
|
||||
ASSERT_MSG(pixmap != nullptr, "No pixmap set");
|
||||
const QPixmap pixmap = surface_picture_label->pixmap(Qt::ReturnByValue);
|
||||
ASSERT_MSG(!pixmap.isNull(), "No pixmap set");
|
||||
|
||||
QFile file{filename};
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
@ -685,7 +675,7 @@ void GraphicsSurfaceWidget::SaveSurface() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pixmap->save(&file, "PNG")) {
|
||||
if (!pixmap.save(&file, "PNG")) {
|
||||
QMessageBox::warning(this, tr("Error"),
|
||||
tr("Failed to save surface data to file '%1'").arg(filename));
|
||||
}
|
||||
|
@ -111,13 +111,13 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
|
||||
}
|
||||
};
|
||||
|
||||
const Instruction instr = par->info.code[index.row()];
|
||||
const Instruction& instr = par->info.code[index.row()];
|
||||
const OpCode opcode = instr.opcode;
|
||||
const OpCode::Info opcode_info = opcode.GetInfo();
|
||||
const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd
|
||||
? instr.mad.operand_desc_id.Value()
|
||||
: instr.common.operand_desc_id.Value();
|
||||
const SwizzlePattern swizzle = par->info.swizzle_info[operand_desc_id].pattern;
|
||||
const SwizzlePattern& swizzle = par->info.swizzle_info[operand_desc_id].pattern;
|
||||
|
||||
// longest known instruction name: "setemit "
|
||||
int kOpcodeColumnWidth = 8;
|
||||
@ -407,8 +407,8 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(
|
||||
static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
|
||||
input_data_mapper->setMapping(input_data[i], i);
|
||||
}
|
||||
connect(input_data_mapper, static_cast<void (QSignalMapper::*)(int)>(&QSignalMapper::mapped),
|
||||
this, &GraphicsVertexShaderWidget::OnInputAttributeChanged);
|
||||
connect(input_data_mapper, &QSignalMapper::mappedInt, this,
|
||||
&GraphicsVertexShaderWidget::OnInputAttributeChanged);
|
||||
|
||||
auto main_widget = new QWidget;
|
||||
auto main_layout = new QVBoxLayout;
|
||||
@ -514,8 +514,10 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
|
||||
info.code.push_back({instr});
|
||||
int num_attributes = shader_config.max_input_attribute_index + 1;
|
||||
|
||||
for (auto pattern : shader_setup.swizzle_data)
|
||||
info.swizzle_info.push_back({pattern});
|
||||
for (auto pattern : shader_setup.swizzle_data) {
|
||||
const nihstro::SwizzleInfo swizzle_info = {.pattern = nihstro::SwizzlePattern{pattern}};
|
||||
info.swizzle_info.push_back(swizzle_info);
|
||||
}
|
||||
|
||||
u32 entry_point = Pica::g_state.regs.vs.main_offset;
|
||||
info.labels.insert({entry_point, "main"});
|
||||
|
@ -57,6 +57,7 @@ QString IPCRecorderWidget::GetStatusStr(const IPCDebugger::RequestRecord& record
|
||||
return tr("HLE Unimplemented");
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return QLatin1String{};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,8 @@ void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* event) {
|
||||
}
|
||||
|
||||
void MicroProfileWidget::wheelEvent(QWheelEvent* event) {
|
||||
MicroProfileMousePosition(event->x() / x_scale, event->y() / y_scale, event->delta() / 120);
|
||||
MicroProfileMousePosition(event->position().x() / x_scale, event->position().y() / y_scale,
|
||||
event->angleDelta().y() / 120);
|
||||
event->accept();
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ void OptionSetDialog::InitializeUI(const std::string& initial_value) {
|
||||
ui->formatLabel->text().append(QStringLiteral("\n"));
|
||||
}
|
||||
ui->formatLabel->setText(
|
||||
ui->formatLabel->text().append(tr("Range: %1 - %2").arg(option.min).arg(option.max)));
|
||||
ui->formatLabel->text().append(tr("Range: %1 - %2").arg(option.min, option.max)));
|
||||
}
|
||||
|
||||
// Decide and initialize layout
|
||||
|
@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QHBoxLayout>
|
||||
@ -31,6 +32,8 @@
|
||||
#include "core/file_sys/archive_extsavedata.h"
|
||||
#include "core/file_sys/archive_source_sd_savedata.h"
|
||||
#include "core/hle/service/fs/archive.h"
|
||||
#include "core/settings.h"
|
||||
#include "qcursor.h"
|
||||
|
||||
GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist, QObject* parent)
|
||||
: QObject(parent), gamelist{gamelist} {}
|
||||
@ -169,8 +172,7 @@ GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
|
||||
* @return true if the haystack contains all words of userinput
|
||||
*/
|
||||
static bool ContainsAllWords(const QString& haystack, const QString& userinput) {
|
||||
const QStringList userinput_split =
|
||||
userinput.split(QLatin1Char{' '}, QString::SplitBehavior::SkipEmptyParts);
|
||||
const QStringList userinput_split = userinput.split(QLatin1Char{' '}, Qt::SkipEmptyParts);
|
||||
|
||||
return std::all_of(userinput_split.begin(), userinput_split.end(),
|
||||
[&haystack](const QString& s) { return haystack.contains(s); });
|
||||
@ -463,6 +465,7 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
context_menu.exec(tree_view->viewport()->mapToGlobal(menu_location));
|
||||
}
|
||||
|
||||
@ -476,19 +479,27 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, u64 progra
|
||||
QAction* open_texture_load_location =
|
||||
context_menu.addAction(tr("Open Custom Texture Location"));
|
||||
QAction* open_mods_location = context_menu.addAction(tr("Open Mods Location"));
|
||||
QMenu* shader_menu = context_menu.addMenu(tr("Disk Shader Cache"));
|
||||
QAction* dump_romfs = context_menu.addAction(tr("Dump RomFS"));
|
||||
QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry"));
|
||||
|
||||
QAction* open_shader_cache_location = shader_menu->addAction(tr("Open Shader Cache Location"));
|
||||
shader_menu->addSeparator();
|
||||
QAction* delete_opengl_disk_shader_cache =
|
||||
shader_menu->addAction(tr("Delete OpenGL Shader Cache"));
|
||||
QAction* delete_vulkan_disk_shader_cache =
|
||||
shader_menu->addAction(tr("Delete Vulkan Shader Cache"));
|
||||
|
||||
const bool is_application =
|
||||
0x0004000000000000 <= program_id && program_id <= 0x00040000FFFFFFFF;
|
||||
|
||||
std::string sdmc_dir = FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir);
|
||||
open_save_location->setVisible(
|
||||
open_save_location->setEnabled(
|
||||
is_application && FileUtil::Exists(FileSys::ArchiveSource_SDSaveData::GetSaveDataPathFor(
|
||||
sdmc_dir, program_id)));
|
||||
|
||||
if (extdata_id) {
|
||||
open_extdata_location->setVisible(
|
||||
open_extdata_location->setEnabled(
|
||||
is_application &&
|
||||
FileUtil::Exists(FileSys::GetExtDataPathFromId(sdmc_dir, extdata_id)));
|
||||
} else {
|
||||
@ -496,9 +507,9 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, u64 progra
|
||||
}
|
||||
|
||||
auto media_type = Service::AM::GetTitleMediaType(program_id);
|
||||
open_application_location->setVisible(path.toStdString() ==
|
||||
open_application_location->setEnabled(path.toStdString() ==
|
||||
Service::AM::GetTitleContentPath(media_type, program_id));
|
||||
open_update_location->setVisible(
|
||||
open_update_location->setEnabled(
|
||||
is_application && FileUtil::Exists(Service::AM::GetTitlePath(Service::FS::MediaType::SDMC,
|
||||
program_id + 0xe00000000) +
|
||||
"content/"));
|
||||
@ -511,44 +522,71 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, u64 progra
|
||||
|
||||
navigate_to_gamedb_entry->setVisible(it != compatibility_list.end());
|
||||
|
||||
connect(open_save_location, &QAction::triggered, [this, program_id] {
|
||||
connect(open_save_location, &QAction::triggered, this, [this, program_id] {
|
||||
emit OpenFolderRequested(program_id, GameListOpenTarget::SAVE_DATA);
|
||||
});
|
||||
connect(open_extdata_location, &QAction::triggered, [this, extdata_id] {
|
||||
connect(open_extdata_location, &QAction::triggered, this, [this, extdata_id] {
|
||||
emit OpenFolderRequested(extdata_id, GameListOpenTarget::EXT_DATA);
|
||||
});
|
||||
connect(open_application_location, &QAction::triggered, [this, program_id] {
|
||||
connect(open_application_location, &QAction::triggered, this, [this, program_id] {
|
||||
emit OpenFolderRequested(program_id, GameListOpenTarget::APPLICATION);
|
||||
});
|
||||
connect(open_update_location, &QAction::triggered, [this, program_id] {
|
||||
connect(open_update_location, &QAction::triggered, this, [this, program_id] {
|
||||
emit OpenFolderRequested(program_id, GameListOpenTarget::UPDATE_DATA);
|
||||
});
|
||||
connect(open_texture_dump_location, &QAction::triggered, [this, program_id] {
|
||||
connect(open_texture_dump_location, &QAction::triggered, this, [this, program_id] {
|
||||
if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::DumpDir),
|
||||
program_id))) {
|
||||
emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_DUMP);
|
||||
}
|
||||
});
|
||||
connect(open_texture_load_location, &QAction::triggered, [this, program_id] {
|
||||
connect(open_texture_load_location, &QAction::triggered, this, [this, program_id] {
|
||||
if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
|
||||
program_id))) {
|
||||
emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_LOAD);
|
||||
}
|
||||
});
|
||||
connect(open_mods_location, &QAction::triggered, [this, program_id] {
|
||||
connect(open_texture_load_location, &QAction::triggered, this, [this, program_id] {
|
||||
if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
|
||||
program_id))) {
|
||||
emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_LOAD);
|
||||
}
|
||||
});
|
||||
connect(open_mods_location, &QAction::triggered, this, [this, program_id] {
|
||||
if (FileUtil::CreateFullPath(fmt::format("{}mods/{:016X}/",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
|
||||
program_id))) {
|
||||
emit OpenFolderRequested(program_id, GameListOpenTarget::MODS);
|
||||
}
|
||||
});
|
||||
connect(dump_romfs, &QAction::triggered,
|
||||
connect(dump_romfs, &QAction::triggered, this,
|
||||
[this, path, program_id] { emit DumpRomFSRequested(path, program_id); });
|
||||
connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() {
|
||||
connect(navigate_to_gamedb_entry, &QAction::triggered, this, [this, program_id]() {
|
||||
emit NavigateToGamedbEntryRequested(program_id, compatibility_list);
|
||||
});
|
||||
connect(open_shader_cache_location, &QAction::triggered, this, [this, program_id] {
|
||||
if (FileUtil::CreateFullPath(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir))) {
|
||||
emit OpenFolderRequested(program_id, GameListOpenTarget::SHADER_CACHE);
|
||||
}
|
||||
});
|
||||
connect(delete_opengl_disk_shader_cache, &QAction::triggered, this, [program_id] {
|
||||
const std::string_view cache_type =
|
||||
Settings::values.separable_shader ? "separable" : "conventional";
|
||||
const std::string path = fmt::format("{}opengl/precompiled/{}/{:016X}.bin",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir),
|
||||
cache_type, program_id);
|
||||
QFile file{QString::fromStdString(path)};
|
||||
file.remove();
|
||||
});
|
||||
connect(delete_vulkan_disk_shader_cache, &QAction::triggered, this, [] {
|
||||
const std::string path =
|
||||
fmt::format("{}vulkan", FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir));
|
||||
QDir dir{QString::fromStdString(path)};
|
||||
dir.removeRecursively();
|
||||
});
|
||||
};
|
||||
|
||||
void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||
@ -561,11 +599,11 @@ void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||
deep_scan->setCheckable(true);
|
||||
deep_scan->setChecked(game_dir.deep_scan);
|
||||
|
||||
connect(deep_scan, &QAction::triggered, [this, &game_dir] {
|
||||
connect(deep_scan, &QAction::triggered, this, [this, &game_dir] {
|
||||
game_dir.deep_scan = !game_dir.deep_scan;
|
||||
PopulateAsync(UISettings::values.game_dirs);
|
||||
});
|
||||
connect(delete_dir, &QAction::triggered, [this, &game_dir, selected] {
|
||||
connect(delete_dir, &QAction::triggered, this, [this, &game_dir, selected] {
|
||||
UISettings::values.game_dirs.removeOne(game_dir);
|
||||
item_model->invisibleRootItem()->removeRow(selected.row());
|
||||
});
|
||||
@ -583,7 +621,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||
move_up->setEnabled(row > 0);
|
||||
move_down->setEnabled(row < item_model->rowCount() - 2);
|
||||
|
||||
connect(move_up, &QAction::triggered, [this, selected, row, game_dir_index] {
|
||||
connect(move_up, &QAction::triggered, this, [this, selected, row, game_dir_index] {
|
||||
const int other_index = selected.sibling(row - 1, 0).data(GameListDir::GameDirRole).toInt();
|
||||
// swap the items in the settings
|
||||
std::swap(UISettings::values.game_dirs[game_dir_index],
|
||||
@ -598,7 +636,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||
tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded);
|
||||
});
|
||||
|
||||
connect(move_down, &QAction::triggered, [this, selected, row, game_dir_index] {
|
||||
connect(move_down, &QAction::triggered, this, [this, selected, row, game_dir_index] {
|
||||
const int other_index = selected.sibling(row + 1, 0).data(GameListDir::GameDirRole).toInt();
|
||||
// swap the items in the settings
|
||||
std::swap(UISettings::values.game_dirs[game_dir_index],
|
||||
@ -613,7 +651,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||
tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded);
|
||||
});
|
||||
|
||||
connect(open_directory_location, &QAction::triggered, [this, game_dir_index] {
|
||||
connect(open_directory_location, &QAction::triggered, this, [this, game_dir_index] {
|
||||
emit OpenDirectory(UISettings::values.game_dirs[game_dir_index].path);
|
||||
});
|
||||
}
|
||||
@ -640,7 +678,7 @@ void GameList::LoadCompatibilityList() {
|
||||
const QJsonDocument json = QJsonDocument::fromJson(content);
|
||||
const QJsonArray arr = json.array();
|
||||
|
||||
for (const QJsonValue value : arr) {
|
||||
for (const QJsonValue& value : arr) {
|
||||
const QJsonObject game = value.toObject();
|
||||
const QString compatibility_key = QStringLiteral("compatibility");
|
||||
|
||||
@ -652,7 +690,7 @@ void GameList::LoadCompatibilityList() {
|
||||
const QString directory = game[QStringLiteral("directory")].toString();
|
||||
const QJsonArray ids = game[QStringLiteral("releases")].toArray();
|
||||
|
||||
for (const QJsonValue id_ref : ids) {
|
||||
for (const QJsonValue& id_ref : ids) {
|
||||
const QJsonObject id_object = id_ref.toObject();
|
||||
const QString id = id_object[QStringLiteral("id")].toString();
|
||||
|
||||
|
@ -37,6 +37,7 @@ enum class GameListOpenTarget {
|
||||
TEXTURE_DUMP = 4,
|
||||
TEXTURE_LOAD = 5,
|
||||
MODS = 6,
|
||||
SHADER_CACHE = 7
|
||||
};
|
||||
|
||||
class GameList : public QWidget {
|
||||
|
@ -11,18 +11,11 @@
|
||||
#include <QFutureWatcher>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QOpenGLFunctions_4_3_Core>
|
||||
#include <QSysInfo>
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
#include <QtGui>
|
||||
#include <QtWidgets>
|
||||
#include <fmt/format.h>
|
||||
#ifdef __APPLE__
|
||||
#include <unistd.h> // for chdir
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include "citra_qt/aboutdialog.h"
|
||||
#include "citra_qt/applets/mii_selector.h"
|
||||
#include "citra_qt/applets/swkbd.h"
|
||||
@ -62,12 +55,11 @@
|
||||
#include "common/detached_tasks.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/backend.h"
|
||||
#include "common/logging/filter.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/logging/text_formatter.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/scm_rev.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/string_util.h"
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
#include "common/x64/cpu_detect.h"
|
||||
#endif
|
||||
@ -76,20 +68,23 @@
|
||||
#include "core/file_sys/archive_extsavedata.h"
|
||||
#include "core/file_sys/archive_source_sd_savedata.h"
|
||||
#include "core/frontend/applets/default_applets.h"
|
||||
#include "core/frontend/scope_acquire_context.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/hle/service/fs/archive.h"
|
||||
#include "core/hle/service/nfc/nfc.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/movie.h"
|
||||
#include "core/savestate.h"
|
||||
#include "core/settings.h"
|
||||
#include "game_list_p.h"
|
||||
#include "network/network_settings.h"
|
||||
#include "ui_main.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <unistd.h> // for chdir
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
#include "citra_qt/discord_impl.h"
|
||||
#endif
|
||||
@ -152,8 +147,8 @@ static void InitializeLogging() {
|
||||
}
|
||||
|
||||
GMainWindow::GMainWindow()
|
||||
: config(std::make_unique<Config>()), emu_thread(nullptr),
|
||||
ui(std::make_unique<Ui::MainWindow>()) {
|
||||
: ui{std::make_unique<Ui::MainWindow>()}, config{std::make_unique<Config>()}, emu_thread{
|
||||
nullptr} {
|
||||
InitializeLogging();
|
||||
Debugger::ToggleConsole();
|
||||
Settings::LogSettings();
|
||||
@ -263,7 +258,7 @@ void GMainWindow::InitializeWidgets() {
|
||||
loading_screen = new LoadingScreen(this);
|
||||
loading_screen->hide();
|
||||
ui->horizontalLayout->addWidget(loading_screen);
|
||||
connect(loading_screen, &LoadingScreen::Hidden, [&] {
|
||||
connect(loading_screen, &LoadingScreen::Hidden, this, [&] {
|
||||
loading_screen->Clear();
|
||||
if (emulation_running) {
|
||||
render_window->show();
|
||||
@ -282,7 +277,6 @@ void GMainWindow::InitializeWidgets() {
|
||||
// Create status bar
|
||||
message_label = new QLabel();
|
||||
// Configured separately for left alignment
|
||||
message_label->setVisible(false);
|
||||
message_label->setFrameStyle(QFrame::NoFrame);
|
||||
message_label->setContentsMargins(4, 0, 4, 0);
|
||||
message_label->setAlignment(Qt::AlignLeft);
|
||||
@ -307,10 +301,28 @@ void GMainWindow::InitializeWidgets() {
|
||||
label->setVisible(false);
|
||||
label->setFrameStyle(QFrame::NoFrame);
|
||||
label->setContentsMargins(4, 0, 4, 0);
|
||||
statusBar()->addPermanentWidget(label, 0);
|
||||
statusBar()->addPermanentWidget(label);
|
||||
}
|
||||
statusBar()->addPermanentWidget(multiplayer_state->GetStatusText(), 0);
|
||||
statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon(), 0);
|
||||
|
||||
// Setup Graphics API button
|
||||
graphics_api_button = new QPushButton();
|
||||
graphics_api_button->setObjectName(QStringLiteral("GraphicsAPIStatusBarButton"));
|
||||
graphics_api_button->setFocusPolicy(Qt::NoFocus);
|
||||
UpdateAPIIndicator(false);
|
||||
|
||||
connect(graphics_api_button, &QPushButton::clicked, this, [this] {
|
||||
if (emulation_running) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateAPIIndicator(true);
|
||||
});
|
||||
|
||||
statusBar()->insertPermanentWidget(0, graphics_api_button);
|
||||
|
||||
statusBar()->addPermanentWidget(multiplayer_state->GetStatusText());
|
||||
statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon());
|
||||
|
||||
statusBar()->setVisible(true);
|
||||
|
||||
// Removes an ugly inner border from the status bar widgets under Linux
|
||||
@ -432,13 +444,13 @@ void GMainWindow::InitializeSaveStateMenuActions() {
|
||||
ui->menu_Save_State->addAction(actions_save_state[i]);
|
||||
}
|
||||
|
||||
connect(ui->action_Load_from_Newest_Slot, &QAction::triggered, [this] {
|
||||
connect(ui->action_Load_from_Newest_Slot, &QAction::triggered, this, [this] {
|
||||
UpdateSaveStates();
|
||||
if (newest_slot != 0) {
|
||||
actions_load_state[newest_slot - 1]->trigger();
|
||||
}
|
||||
});
|
||||
connect(ui->action_Save_to_Oldest_Slot, &QAction::triggered, [this] {
|
||||
connect(ui->action_Save_to_Oldest_Slot, &QAction::triggered, this, [this] {
|
||||
UpdateSaveStates();
|
||||
actions_save_state[oldest_slot - 1]->trigger();
|
||||
});
|
||||
@ -674,7 +686,7 @@ void GMainWindow::ConnectWidgetEvents() {
|
||||
connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this,
|
||||
&GMainWindow::OnGameListAddDirectory);
|
||||
connect(game_list, &GameList::ShowList, this, &GMainWindow::OnGameListShowList);
|
||||
connect(game_list, &GameList::PopulatingCompleted,
|
||||
connect(game_list, &GameList::PopulatingCompleted, this,
|
||||
[this] { multiplayer_state->UpdateGameList(game_list->GetModel()); });
|
||||
|
||||
connect(this, &GMainWindow::EmulationStarting, render_window,
|
||||
@ -765,7 +777,7 @@ void GMainWindow::ConnectMenuEvents() {
|
||||
connect(ui->action_Close_Movie, &QAction::triggered, this, &GMainWindow::OnCloseMovie);
|
||||
connect(ui->action_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie);
|
||||
connect(ui->action_Movie_Read_Only_Mode, &QAction::toggled, this,
|
||||
[this](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); });
|
||||
[](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); });
|
||||
connect(ui->action_Enable_Frame_Advancing, &QAction::triggered, this, [this] {
|
||||
if (emulation_running) {
|
||||
Core::System::GetInstance().frame_limiter.SetFrameAdvancing(
|
||||
@ -914,20 +926,10 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||
|
||||
render_window->InitRenderTarget();
|
||||
|
||||
Frontend::ScopeAcquireContext scope(*render_window);
|
||||
const auto scope = render_window->Acquire();
|
||||
|
||||
const QString below_gl43_title = tr("OpenGL 4.3 Unsupported");
|
||||
const QString below_gl43_message = tr("Your GPU may not support OpenGL 4.3, or you do not "
|
||||
"have the latest graphics driver.");
|
||||
|
||||
if (!QOpenGLContext::globalShareContext()->versionFunctions<QOpenGLFunctions_4_3_Core>()) {
|
||||
QMessageBox::critical(this, below_gl43_title, below_gl43_message);
|
||||
return false;
|
||||
}
|
||||
|
||||
Core::System& system{Core::System::GetInstance()};
|
||||
|
||||
const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
|
||||
Core::System& system = Core::System::GetInstance();
|
||||
const Core::System::ResultStatus result = system.Load(*render_window, filename.toStdString());
|
||||
|
||||
if (result != Core::System::ResultStatus::Success) {
|
||||
switch (result) {
|
||||
@ -976,7 +978,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||
case Core::System::ResultStatus::ErrorVideoCore:
|
||||
QMessageBox::critical(
|
||||
this, tr("Video Core Error"),
|
||||
tr("An error has occurred. Please <a "
|
||||
tr("An error has occurred during intialization of the video backend. Please <a "
|
||||
"href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see "
|
||||
"the "
|
||||
"log</a> for more details. "
|
||||
@ -991,10 +993,6 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||
"proper drivers for your graphics card from the manufacturer's website."));
|
||||
break;
|
||||
|
||||
case Core::System::ResultStatus::ErrorVideoCore_ErrorBelowGL43:
|
||||
QMessageBox::critical(this, below_gl43_title, below_gl43_message);
|
||||
break;
|
||||
|
||||
default:
|
||||
QMessageBox::critical(
|
||||
this, tr("Error while loading ROM!"),
|
||||
@ -1206,7 +1204,6 @@ void GMainWindow::ShutdownGame() {
|
||||
|
||||
// Disable status bar updates
|
||||
status_bar_update_timer.stop();
|
||||
message_label->setVisible(false);
|
||||
message_label_used_for_movie = false;
|
||||
emu_speed_label->setVisible(false);
|
||||
game_fps_label->setVisible(false);
|
||||
@ -1343,26 +1340,35 @@ void GMainWindow::OnGameListOpenFolder(u64 data_id, GameListOpenTarget target) {
|
||||
path = Service::AM::GetTitlePath(media_type, data_id) + "content/";
|
||||
break;
|
||||
}
|
||||
case GameListOpenTarget::UPDATE_DATA:
|
||||
case GameListOpenTarget::UPDATE_DATA: {
|
||||
open_target = "Update Data";
|
||||
path = Service::AM::GetTitlePath(Service::FS::MediaType::SDMC, data_id + 0xe00000000) +
|
||||
"content/";
|
||||
break;
|
||||
case GameListOpenTarget::TEXTURE_DUMP:
|
||||
}
|
||||
case GameListOpenTarget::TEXTURE_DUMP: {
|
||||
open_target = "Dumped Textures";
|
||||
path = fmt::format("{}textures/{:016X}/",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), data_id);
|
||||
break;
|
||||
case GameListOpenTarget::TEXTURE_LOAD:
|
||||
}
|
||||
case GameListOpenTarget::TEXTURE_LOAD: {
|
||||
open_target = "Custom Textures";
|
||||
path = fmt::format("{}textures/{:016X}/",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), data_id);
|
||||
break;
|
||||
case GameListOpenTarget::MODS:
|
||||
}
|
||||
case GameListOpenTarget::MODS: {
|
||||
open_target = "Mods";
|
||||
path = fmt::format("{}mods/{:016X}/", FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
|
||||
data_id);
|
||||
break;
|
||||
}
|
||||
case GameListOpenTarget::SHADER_CACHE: {
|
||||
open_target = "Shader Cache";
|
||||
path = FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR(Frontend, "Unexpected target {}", static_cast<int>(target));
|
||||
return;
|
||||
@ -1410,7 +1416,7 @@ void GMainWindow::OnGameListDumpRomFS(QString game_path, u64 program_id) {
|
||||
program_id | 0x0004000e00000000);
|
||||
using FutureWatcher = QFutureWatcher<std::pair<Loader::ResultStatus, Loader::ResultStatus>>;
|
||||
auto* future_watcher = new FutureWatcher(this);
|
||||
connect(future_watcher, &FutureWatcher::finished,
|
||||
connect(future_watcher, &FutureWatcher::finished, this,
|
||||
[this, dialog, base_path, update_path, future_watcher] {
|
||||
dialog->hide();
|
||||
const auto& [base, update] = future_watcher->result();
|
||||
@ -1512,7 +1518,7 @@ void GMainWindow::InstallCIA(QStringList filepaths) {
|
||||
const auto cia_progress = [&](std::size_t written, std::size_t total) {
|
||||
emit UpdateProgress(written, total);
|
||||
};
|
||||
for (const auto current_path : filepaths) {
|
||||
for (const auto& current_path : filepaths) {
|
||||
status = Service::AM::InstallCIA(current_path.toStdString(), cia_progress);
|
||||
emit CIAInstallReport(status, current_path);
|
||||
}
|
||||
@ -1550,6 +1556,10 @@ void GMainWindow::OnCIAInstallReport(Service::AM::InstallStatus status, QString
|
||||
"before being used with Citra. A real 3DS is required.")
|
||||
.arg(filename));
|
||||
break;
|
||||
case Service::AM::InstallStatus::ErrorFileNotFound:
|
||||
QMessageBox::critical(this, tr("Unable to find File"),
|
||||
tr("Could not find %1").arg(filename));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1727,6 +1737,8 @@ void GMainWindow::ToggleScreenLayout() {
|
||||
case Settings::LayoutOption::SideScreen:
|
||||
new_layout = Settings::LayoutOption::Default;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR(Frontend, "Unknown layout option {}", Settings::values.layout_option);
|
||||
}
|
||||
|
||||
Settings::values.layout_option = new_layout;
|
||||
@ -1796,6 +1808,7 @@ void GMainWindow::OnConfigure() {
|
||||
} else {
|
||||
setMouseTracking(false);
|
||||
}
|
||||
UpdateAPIIndicator(false);
|
||||
} else {
|
||||
Settings::values.input_profiles = old_input_profiles;
|
||||
Settings::values.touch_from_button_maps = old_touch_from_button_maps;
|
||||
@ -1973,7 +1986,7 @@ void GMainWindow::OnCaptureScreenshot() {
|
||||
const QString filename = game_title.remove(QRegularExpression(QStringLiteral("[\\/:?\"<>|]")));
|
||||
const QString timestamp =
|
||||
QDateTime::currentDateTime().toString(QStringLiteral("dd.MM.yy_hh.mm.ss.z"));
|
||||
path.append(QStringLiteral("/%1_%2.png").arg(filename).arg(timestamp));
|
||||
path.append(QStringLiteral("/%1_%2.png").arg(filename, timestamp));
|
||||
render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path);
|
||||
OnStartGame();
|
||||
}
|
||||
@ -2048,7 +2061,7 @@ void GMainWindow::UpdateStatusBar() {
|
||||
message_label_used_for_movie = true;
|
||||
ui->action_Save_Movie->setEnabled(true);
|
||||
} else if (play_mode == Core::Movie::PlayMode::Playing) {
|
||||
message_label->setText(tr("Playing %1 / %2").arg(current).arg(total));
|
||||
message_label->setText(tr("Playing %1 / %2").arg(current, total));
|
||||
message_label->setVisible(true);
|
||||
message_label_used_for_movie = true;
|
||||
ui->action_Save_Movie->setEnabled(false);
|
||||
@ -2107,6 +2120,26 @@ void GMainWindow::ShowMouseCursor() {
|
||||
}
|
||||
}
|
||||
|
||||
void GMainWindow::UpdateAPIIndicator(bool override) {
|
||||
static std::array graphics_apis = {QStringLiteral("OPENGL"), QStringLiteral("OPENGLES"),
|
||||
QStringLiteral("VULKAN")};
|
||||
|
||||
static std::array graphics_api_colors = {QStringLiteral("#00ccdd"), QStringLiteral("#ba2a8d"),
|
||||
QStringLiteral("#91242a")};
|
||||
|
||||
u32 api_index = static_cast<u32>(Settings::values.graphics_api);
|
||||
if (override) {
|
||||
api_index = (api_index + 1) % graphics_apis.size();
|
||||
Settings::values.graphics_api = static_cast<Settings::GraphicsAPI>(api_index);
|
||||
}
|
||||
|
||||
const QString style_sheet = QStringLiteral("QPushButton { font-weight: bold; color: %0; }")
|
||||
.arg(graphics_api_colors[api_index]);
|
||||
|
||||
graphics_api_button->setText(graphics_apis[api_index]);
|
||||
graphics_api_button->setStyleSheet(style_sheet);
|
||||
}
|
||||
|
||||
void GMainWindow::OnMouseActivity() {
|
||||
ShowMouseCursor();
|
||||
}
|
||||
@ -2292,8 +2325,16 @@ void GMainWindow::UpdateUITheme() {
|
||||
QStringList theme_paths(default_theme_paths);
|
||||
|
||||
if (is_default_theme || current_theme.isEmpty()) {
|
||||
qApp->setStyleSheet({});
|
||||
setStyleSheet({});
|
||||
const QString theme_uri(QStringLiteral(":default/style.qss"));
|
||||
QFile f(theme_uri);
|
||||
if (f.open(QFile::ReadOnly | QFile::Text)) {
|
||||
QTextStream ts(&f);
|
||||
qApp->setStyleSheet(ts.readAll());
|
||||
setStyleSheet(ts.readAll());
|
||||
} else {
|
||||
qApp->setStyleSheet({});
|
||||
setStyleSheet({});
|
||||
}
|
||||
theme_paths.append(default_icons);
|
||||
QIcon::setThemeName(default_icons);
|
||||
} else {
|
||||
@ -2440,14 +2481,6 @@ int main(int argc, char* argv[]) {
|
||||
QCoreApplication::setOrganizationName(QStringLiteral("Citra team"));
|
||||
QCoreApplication::setApplicationName(QStringLiteral("Citra"));
|
||||
|
||||
QSurfaceFormat format;
|
||||
format.setVersion(4, 3);
|
||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||
format.setSwapInterval(0);
|
||||
// TODO: expose a setting for buffer value (ie default/single/double/triple)
|
||||
format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior);
|
||||
QSurfaceFormat::setDefaultFormat(format);
|
||||
|
||||
#ifdef __APPLE__
|
||||
std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + "..";
|
||||
chdir(bin_path.c_str());
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <QMainWindow>
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
#include <QTranslator>
|
||||
#include "citra_qt/compatibility_list.h"
|
||||
@ -234,6 +235,7 @@ private:
|
||||
void InstallCIA(QStringList filepaths);
|
||||
void HideMouseCursor();
|
||||
void ShowMouseCursor();
|
||||
void UpdateAPIIndicator(bool override);
|
||||
|
||||
std::unique_ptr<Ui::MainWindow> ui;
|
||||
|
||||
@ -248,6 +250,7 @@ private:
|
||||
QLabel* emu_speed_label = nullptr;
|
||||
QLabel* game_fps_label = nullptr;
|
||||
QLabel* emu_frametime_label = nullptr;
|
||||
QPushButton* graphics_api_button = nullptr;
|
||||
QTimer status_bar_update_timer;
|
||||
bool message_label_used_for_movie = false;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <QDialog>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <QIcon>
|
||||
#include <QMessageBox>
|
||||
#include <QStandardItemModel>
|
||||
#include "citra_qt/game_list.h"
|
||||
#include "citra_qt/multiplayer/client_room.h"
|
||||
#include "citra_qt/multiplayer/direct_connect.h"
|
||||
#include "citra_qt/multiplayer/host_room.h"
|
||||
@ -16,7 +15,6 @@
|
||||
#include "citra_qt/multiplayer/state.h"
|
||||
#include "citra_qt/uisettings.h"
|
||||
#include "citra_qt/util/clickable_label.h"
|
||||
#include "common/announce_multiplayer_room.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_list_model,
|
||||
@ -231,8 +229,9 @@ bool MultiplayerState::OnCloseRoom() {
|
||||
if (room->GetState() != Network::Room::State::Open) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Save ban list
|
||||
UISettings::values.ban_list = std::move(room->GetBanList());
|
||||
UISettings::values.ban_list = room->GetBanList();
|
||||
|
||||
room->Destroy();
|
||||
announce_multiplayer_session->Stop();
|
||||
|
@ -78,6 +78,7 @@ add_library(common STATIC
|
||||
logging/backend.h
|
||||
logging/filter.cpp
|
||||
logging/filter.h
|
||||
logging/formatter.h
|
||||
logging/log.h
|
||||
logging/text_formatter.cpp
|
||||
logging/text_formatter.h
|
||||
|
@ -59,6 +59,60 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
||||
|
||||
#endif // _MSC_VER ndef
|
||||
|
||||
#define DECLARE_ENUM_FLAG_OPERATORS(type) \
|
||||
[[nodiscard]] constexpr type operator|(type a, type b) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(static_cast<T>(a) | static_cast<T>(b)); \
|
||||
} \
|
||||
[[nodiscard]] constexpr type operator&(type a, type b) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \
|
||||
} \
|
||||
[[nodiscard]] constexpr type operator^(type a, type b) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(static_cast<T>(a) ^ static_cast<T>(b)); \
|
||||
} \
|
||||
[[nodiscard]] constexpr type operator<<(type a, type b) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(static_cast<T>(a) << static_cast<T>(b)); \
|
||||
} \
|
||||
[[nodiscard]] constexpr type operator>>(type a, type b) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(static_cast<T>(a) >> static_cast<T>(b)); \
|
||||
} \
|
||||
constexpr type& operator|=(type& a, type b) noexcept { \
|
||||
a = a | b; \
|
||||
return a; \
|
||||
} \
|
||||
constexpr type& operator&=(type& a, type b) noexcept { \
|
||||
a = a & b; \
|
||||
return a; \
|
||||
} \
|
||||
constexpr type& operator^=(type& a, type b) noexcept { \
|
||||
a = a ^ b; \
|
||||
return a; \
|
||||
} \
|
||||
constexpr type& operator<<=(type& a, type b) noexcept { \
|
||||
a = a << b; \
|
||||
return a; \
|
||||
} \
|
||||
constexpr type& operator>>=(type& a, type b) noexcept { \
|
||||
a = a >> b; \
|
||||
return a; \
|
||||
} \
|
||||
[[nodiscard]] constexpr type operator~(type key) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(~static_cast<T>(key)); \
|
||||
} \
|
||||
[[nodiscard]] constexpr bool True(type key) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<T>(key) != 0; \
|
||||
} \
|
||||
[[nodiscard]] constexpr bool False(type key) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<T>(key) == 0; \
|
||||
}
|
||||
|
||||
// Generic function to get last error message.
|
||||
// Call directly after the command or use the error num.
|
||||
// This function might change the error code.
|
||||
|
@ -31,8 +31,10 @@
|
||||
#endif
|
||||
|
||||
// 64 bit offsets for MSVC and MinGW. MinGW also needs this for using _wstat64
|
||||
#ifndef __MINGW64__
|
||||
#define stat _stat64
|
||||
#define fstat _fstat64
|
||||
#endif
|
||||
|
||||
#else
|
||||
#ifdef __APPLE__
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include "common/cityhash.h"
|
||||
@ -41,6 +42,13 @@ inline u64 HashCombine(std::size_t& seed, const u64 hash) {
|
||||
return seed ^= hash + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct IdentityHash {
|
||||
T operator()(const T& value) const {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
/// A helper template that ensures the padding in a struct is initialized by memsetting to 0.
|
||||
template <typename T>
|
||||
struct HashableStruct {
|
||||
|
@ -235,6 +235,7 @@ void DebuggerBackend::Write(const Entry& entry) {
|
||||
CLS(Render) \
|
||||
SUB(Render, Software) \
|
||||
SUB(Render, OpenGL) \
|
||||
SUB(Render, Vulkan) \
|
||||
CLS(Audio) \
|
||||
SUB(Audio, DSP) \
|
||||
SUB(Audio, Sink) \
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <array>
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/formatter.h"
|
||||
|
||||
namespace Log {
|
||||
|
||||
// trims up to and including the last of ../, ..\, src/, src\ in a string
|
||||
@ -102,6 +103,7 @@ enum class Class : ClassType {
|
||||
Render, ///< Emulator video output and hardware acceleration
|
||||
Render_Software, ///< Software renderer backend
|
||||
Render_OpenGL, ///< OpenGL backend
|
||||
Render_Vulkan, ///< Vulkan backend
|
||||
Audio, ///< Audio emulation
|
||||
Audio_DSP, ///< The HLE and LLE implementations of the DSP
|
||||
Audio_Sink, ///< Emulator audio output backend
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <compare>
|
||||
#include <cstdlib>
|
||||
#include <type_traits>
|
||||
|
||||
@ -23,19 +24,31 @@ struct Rectangle {
|
||||
constexpr Rectangle(T left, T top, T right, T bottom)
|
||||
: left(left), top(top), right(right), bottom(bottom) {}
|
||||
|
||||
[[nodiscard]] T GetWidth() const {
|
||||
constexpr auto operator<=>(const Rectangle&) const = default;
|
||||
|
||||
constexpr void operator*=(const T value) {
|
||||
left *= value;
|
||||
top *= value;
|
||||
right *= value;
|
||||
bottom *= value;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Rectangle operator*(const T value) const {
|
||||
return Rectangle{left * value, top * value, right * value, bottom * value};
|
||||
}
|
||||
[[nodiscard]] constexpr T GetWidth() const {
|
||||
return std::abs(static_cast<std::make_signed_t<T>>(right - left));
|
||||
}
|
||||
[[nodiscard]] T GetHeight() const {
|
||||
[[nodiscard]] constexpr T GetHeight() const {
|
||||
return std::abs(static_cast<std::make_signed_t<T>>(bottom - top));
|
||||
}
|
||||
[[nodiscard]] Rectangle<T> TranslateX(const T x) const {
|
||||
[[nodiscard]] constexpr Rectangle<T> TranslateX(const T x) const {
|
||||
return Rectangle{left + x, top, right + x, bottom};
|
||||
}
|
||||
[[nodiscard]] Rectangle<T> TranslateY(const T y) const {
|
||||
[[nodiscard]] constexpr Rectangle<T> TranslateY(const T y) const {
|
||||
return Rectangle{left, top + y, right, bottom + y};
|
||||
}
|
||||
[[nodiscard]] Rectangle<T> Scale(const float s) const {
|
||||
[[nodiscard]] constexpr Rectangle<T> Scale(const float s) const {
|
||||
return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
|
||||
static_cast<T>(top + GetHeight() * s)};
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
@ -65,8 +65,11 @@ private:
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(BufferMem);
|
||||
|
||||
/// A managed reference to host-side memory. Fast enough to be used everywhere instead of u8*
|
||||
/// Supports serialization.
|
||||
/**
|
||||
* A managed reference to host-side memory.
|
||||
* Fast enough to be used everywhere instead of u8*
|
||||
* Supports serialization.
|
||||
*/
|
||||
class MemoryRef {
|
||||
public:
|
||||
MemoryRef() = default;
|
||||
@ -75,35 +78,52 @@ public:
|
||||
: backing_mem(std::move(backing_mem_)), offset(0) {
|
||||
Init();
|
||||
}
|
||||
|
||||
MemoryRef(std::shared_ptr<BackingMem> backing_mem_, u64 offset_)
|
||||
: backing_mem(std::move(backing_mem_)), offset(offset_) {
|
||||
ASSERT(offset <= backing_mem->GetSize());
|
||||
Init();
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return cptr != nullptr;
|
||||
}
|
||||
|
||||
operator u8*() {
|
||||
return cptr;
|
||||
}
|
||||
u8* GetPtr() {
|
||||
return cptr;
|
||||
}
|
||||
|
||||
operator const u8*() const {
|
||||
return cptr;
|
||||
}
|
||||
|
||||
u8* GetPtr() {
|
||||
return cptr;
|
||||
}
|
||||
|
||||
const u8* GetPtr() const {
|
||||
return cptr;
|
||||
}
|
||||
|
||||
auto GetWriteBytes(std::size_t size) {
|
||||
return std::span{reinterpret_cast<std::byte*>(cptr), size > csize ? csize : size};
|
||||
}
|
||||
|
||||
auto GetReadBytes(std::size_t size) const {
|
||||
return std::span{reinterpret_cast<const std::byte*>(cptr), size > csize ? csize : size};
|
||||
}
|
||||
|
||||
std::size_t GetSize() const {
|
||||
return csize;
|
||||
}
|
||||
|
||||
MemoryRef& operator+=(u32 offset_by) {
|
||||
ASSERT(offset_by < csize);
|
||||
offset += offset_by;
|
||||
Init();
|
||||
return *this;
|
||||
}
|
||||
|
||||
MemoryRef operator+(u32 offset_by) const {
|
||||
ASSERT(offset_by < csize);
|
||||
return MemoryRef(backing_mem, offset + offset_by);
|
||||
|
@ -23,12 +23,3 @@ typedef void* HANDLE;
|
||||
#include <microprofile.h>
|
||||
|
||||
#define MP_RGB(r, g, b) ((r) << 16 | (g) << 8 | (b) << 0)
|
||||
|
||||
// On OS X, some Mach header included by MicroProfile defines these as macros, conflicting with
|
||||
// identifiers we use.
|
||||
#ifdef PAGE_SIZE
|
||||
#undef PAGE_SIZE
|
||||
#endif
|
||||
#ifdef PAGE_MASK
|
||||
#undef PAGE_MASK
|
||||
#endif
|
||||
|
@ -110,8 +110,6 @@ add_library(core STATIC
|
||||
frontend/input.h
|
||||
frontend/mic.cpp
|
||||
frontend/mic.h
|
||||
frontend/scope_acquire_context.cpp
|
||||
frontend/scope_acquire_context.h
|
||||
gdbstub/gdbstub.cpp
|
||||
gdbstub/gdbstub.h
|
||||
hle/applets/applet.cpp
|
||||
|
@ -261,6 +261,8 @@ u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) const {
|
||||
default:
|
||||
UNREACHABLE_MSG("Unknown CP15 register: {}", reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) {
|
||||
|
@ -849,17 +849,13 @@ static int InterpreterTranslateBlock(ARMul_State* cpu, std::size_t& bb_start, u3
|
||||
// Save start addr of basicblock in CreamCache
|
||||
ARM_INST_PTR inst_base = nullptr;
|
||||
TransExtData ret = TransExtData::NON_BRANCH;
|
||||
int size = 0; // instruction size of basic block
|
||||
bb_start = trans_cache_buf_top;
|
||||
|
||||
u32 phys_addr = addr;
|
||||
u32 pc_start = cpu->Reg[15];
|
||||
|
||||
while (ret == TransExtData::NON_BRANCH) {
|
||||
unsigned int inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base);
|
||||
|
||||
size++;
|
||||
|
||||
u32 inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base);
|
||||
phys_addr += inst_size;
|
||||
|
||||
if ((phys_addr & 0xfff) == 0) {
|
||||
@ -972,7 +968,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
|
||||
|
||||
// GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a
|
||||
// clunky switch statement.
|
||||
#if defined __GNUC__ || defined __clang__
|
||||
#if defined __GNUC__ || (defined __clang__ && !defined _MSC_VER)
|
||||
#define GOTO_NEXT_INST \
|
||||
GDB_BP_CHECK; \
|
||||
if (num_instrs >= cpu->NumInstrsToExecute) \
|
||||
|
@ -1218,7 +1218,7 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) {
|
||||
|
||||
for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
|
||||
u32 except;
|
||||
char type;
|
||||
[[maybe_unused]] char type;
|
||||
|
||||
type = (fop->flags & OP_SD) ? 's' : 'd';
|
||||
if (op == FOP_EXT)
|
||||
|
@ -1242,7 +1242,7 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) {
|
||||
for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
|
||||
s32 m = vfp_get_float(state, sm);
|
||||
u32 except;
|
||||
char type;
|
||||
[[maybe_unused]] char type;
|
||||
|
||||
type = (fop->flags & OP_DD) ? 'd' : 's';
|
||||
if (op == FOP_EXT)
|
||||
|
@ -47,7 +47,7 @@ void CheatEngine::AddCheat(const std::shared_ptr<CheatBase>& cheat) {
|
||||
|
||||
void CheatEngine::RemoveCheat(int index) {
|
||||
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
|
||||
if (index < 0 || index >= cheats_list.size()) {
|
||||
if (index < 0 || index >= static_cast<int>(cheats_list.size())) {
|
||||
LOG_ERROR(Core_Cheats, "Invalid index {}", index);
|
||||
return;
|
||||
}
|
||||
@ -56,7 +56,7 @@ void CheatEngine::RemoveCheat(int index) {
|
||||
|
||||
void CheatEngine::UpdateCheat(int index, const std::shared_ptr<CheatBase>& new_cheat) {
|
||||
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
|
||||
if (index < 0 || index >= cheats_list.size()) {
|
||||
if (index < 0 || index >= static_cast<int>(cheats_list.size())) {
|
||||
LOG_ERROR(Core_Cheats, "Invalid index {}", index);
|
||||
return;
|
||||
}
|
||||
|
@ -424,8 +424,6 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
|
||||
switch (result) {
|
||||
case VideoCore::ResultStatus::ErrorGenericDrivers:
|
||||
return ResultStatus::ErrorVideoCore_ErrorGenericDrivers;
|
||||
case VideoCore::ResultStatus::ErrorBelowGL43:
|
||||
return ResultStatus::ErrorVideoCore_ErrorBelowGL43;
|
||||
default:
|
||||
return ResultStatus::ErrorVideoCore;
|
||||
}
|
||||
|
@ -88,8 +88,6 @@ public:
|
||||
ErrorVideoCore, ///< Error in the video core
|
||||
ErrorVideoCore_ErrorGenericDrivers, ///< Error in the video core due to the user having
|
||||
/// generic drivers installed
|
||||
ErrorVideoCore_ErrorBelowGL43, ///< Error in the video core due to the user not having
|
||||
/// OpenGL 4.3 or higher
|
||||
ErrorSavestate, ///< Error saving or loading
|
||||
ShutdownRequested, ///< Emulated program requested a system shutdown
|
||||
ErrorUnknown ///< Any other error
|
||||
|
@ -301,10 +301,6 @@ private:
|
||||
std::vector<std::shared_ptr<Timer>> timers;
|
||||
Timer* current_timer = nullptr;
|
||||
|
||||
// Stores a scaling for the internal clockspeed. Changing this number results in
|
||||
// under/overclocking the guest cpu
|
||||
double cpu_clock_scale = 1.0;
|
||||
|
||||
// When true, the event queue can't be modified. Used while deserializing to workaround
|
||||
// destructor side effects.
|
||||
bool event_queue_locked = false;
|
||||
|
@ -12,6 +12,17 @@
|
||||
|
||||
namespace Frontend {
|
||||
|
||||
/// Information for the Graphics Backends signifying what type of screen pointer is in
|
||||
/// WindowInformation
|
||||
enum class WindowSystemType : u8 {
|
||||
Headless,
|
||||
Android,
|
||||
Windows,
|
||||
MacOS,
|
||||
X11,
|
||||
Wayland,
|
||||
};
|
||||
|
||||
struct Frame;
|
||||
/**
|
||||
* For smooth Vsync rendering, we want to always present the latest frame that the core generates,
|
||||
@ -60,11 +71,33 @@ class GraphicsContext {
|
||||
public:
|
||||
virtual ~GraphicsContext();
|
||||
|
||||
/// Inform the driver to swap the front/back buffers and present the current image
|
||||
virtual void SwapBuffers(){};
|
||||
|
||||
/// Makes the graphics context current for the caller thread
|
||||
virtual void MakeCurrent() = 0;
|
||||
virtual void MakeCurrent(){};
|
||||
|
||||
/// Releases (dunno if this is the "right" word) the context from the caller thread
|
||||
virtual void DoneCurrent() = 0;
|
||||
virtual void DoneCurrent(){};
|
||||
|
||||
class Scoped {
|
||||
public:
|
||||
explicit Scoped(GraphicsContext& context_) : context(context_) {
|
||||
context.MakeCurrent();
|
||||
}
|
||||
~Scoped() {
|
||||
context.DoneCurrent();
|
||||
}
|
||||
|
||||
private:
|
||||
GraphicsContext& context;
|
||||
};
|
||||
|
||||
/// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
|
||||
/// ends
|
||||
[[nodiscard]] Scoped Acquire() {
|
||||
return Scoped{*this};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -95,6 +128,23 @@ public:
|
||||
std::pair<unsigned, unsigned> min_client_area_size;
|
||||
};
|
||||
|
||||
/// Data describing host window system information
|
||||
struct WindowSystemInfo {
|
||||
// Window system type. Determines which GL context or Vulkan WSI is used.
|
||||
WindowSystemType type = WindowSystemType::Headless;
|
||||
|
||||
// Connection to a display server. This is used on X11 and Wayland platforms.
|
||||
void* display_connection = nullptr;
|
||||
|
||||
// Render surface. This is a pointer to the native window handle, which depends
|
||||
// on the platform. e.g. HWND for Windows, Window for X11. If the surface is
|
||||
// set to nullptr, the video backend will run in headless mode.
|
||||
void* render_surface = nullptr;
|
||||
|
||||
// Scale of the render surface. For hidpi systems, this will be >1.
|
||||
float render_surface_scale = 1.0f;
|
||||
};
|
||||
|
||||
/// Polls window events
|
||||
virtual void PollEvents() = 0;
|
||||
|
||||
@ -158,6 +208,13 @@ public:
|
||||
config = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns system information about the drawing area.
|
||||
*/
|
||||
const WindowSystemInfo& GetWindowInfo() const {
|
||||
return window_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the framebuffer layout (width, height, and screen regions)
|
||||
* @note This method is thread-safe
|
||||
@ -204,6 +261,8 @@ protected:
|
||||
framebuffer_layout = layout;
|
||||
}
|
||||
|
||||
WindowSystemInfo window_info;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Handler called when the minimal client area was requested to be changed via SetConfig.
|
||||
|
@ -1,17 +0,0 @@
|
||||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/frontend/scope_acquire_context.h"
|
||||
|
||||
namespace Frontend {
|
||||
|
||||
ScopeAcquireContext::ScopeAcquireContext(Frontend::GraphicsContext& context) : context{context} {
|
||||
context.MakeCurrent();
|
||||
}
|
||||
ScopeAcquireContext::~ScopeAcquireContext() {
|
||||
context.DoneCurrent();
|
||||
}
|
||||
|
||||
} // namespace Frontend
|
@ -1,23 +0,0 @@
|
||||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Frontend {
|
||||
|
||||
class GraphicsContext;
|
||||
|
||||
/// Helper class to acquire/release window context within a given scope
|
||||
class ScopeAcquireContext : NonCopyable {
|
||||
public:
|
||||
explicit ScopeAcquireContext(Frontend::GraphicsContext& context);
|
||||
~ScopeAcquireContext();
|
||||
|
||||
private:
|
||||
Frontend::GraphicsContext& context;
|
||||
};
|
||||
|
||||
} // namespace Frontend
|
@ -80,7 +80,7 @@ private:
|
||||
std::shared_ptr<Callback> timeout_callback;
|
||||
|
||||
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||
std::shared_ptr<WaitObject> object);
|
||||
std::shared_ptr<WaitObject> object) override;
|
||||
|
||||
class DummyCallback : public WakeupCallback {
|
||||
public:
|
||||
|
@ -138,10 +138,10 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
|
||||
u32 size = static_cast<u32>(descInfo.size);
|
||||
IPC::MappedBufferPermissions permissions = descInfo.perms;
|
||||
|
||||
VAddr page_start = Common::AlignDown(source_address, Memory::PAGE_SIZE);
|
||||
VAddr page_start = Common::AlignDown(source_address, Memory::CITRA_PAGE_SIZE);
|
||||
u32 page_offset = source_address - page_start;
|
||||
u32 num_pages =
|
||||
Common::AlignUp(page_offset + size, Memory::PAGE_SIZE) >> Memory::PAGE_BITS;
|
||||
u32 num_pages = Common::AlignUp(page_offset + size, Memory::CITRA_PAGE_SIZE) >>
|
||||
Memory::CITRA_PAGE_BITS;
|
||||
|
||||
// Skip when the size is zero and num_pages == 0
|
||||
if (size == 0) {
|
||||
@ -171,8 +171,8 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
|
||||
found->target_address, size);
|
||||
}
|
||||
|
||||
VAddr prev_reserve = page_start - Memory::PAGE_SIZE;
|
||||
VAddr next_reserve = page_start + num_pages * Memory::PAGE_SIZE;
|
||||
VAddr prev_reserve = page_start - Memory::CITRA_PAGE_SIZE;
|
||||
VAddr next_reserve = page_start + num_pages * Memory::CITRA_PAGE_SIZE;
|
||||
|
||||
auto& prev_vma = src_process->vm_manager.FindVMA(prev_reserve)->second;
|
||||
auto& next_vma = src_process->vm_manager.FindVMA(next_reserve)->second;
|
||||
@ -180,8 +180,9 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
|
||||
next_vma.meminfo_state == MemoryState::Reserved);
|
||||
|
||||
// Unmap the buffer and guard pages from the source process
|
||||
ResultCode result = src_process->vm_manager.UnmapRange(
|
||||
page_start - Memory::PAGE_SIZE, (num_pages + 2) * Memory::PAGE_SIZE);
|
||||
ResultCode result =
|
||||
src_process->vm_manager.UnmapRange(page_start - Memory::CITRA_PAGE_SIZE,
|
||||
(num_pages + 2) * Memory::CITRA_PAGE_SIZE);
|
||||
ASSERT(result == RESULT_SUCCESS);
|
||||
|
||||
mapped_buffer_context.erase(found);
|
||||
@ -196,13 +197,13 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
|
||||
|
||||
// Reserve a page of memory before the mapped buffer
|
||||
std::shared_ptr<BackingMem> reserve_buffer =
|
||||
std::make_shared<BufferMem>(Memory::PAGE_SIZE);
|
||||
std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE);
|
||||
dst_process->vm_manager.MapBackingMemoryToBase(
|
||||
Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer,
|
||||
Memory::PAGE_SIZE, Kernel::MemoryState::Reserved);
|
||||
Memory::CITRA_PAGE_SIZE, Kernel::MemoryState::Reserved);
|
||||
|
||||
std::shared_ptr<BackingMem> buffer =
|
||||
std::make_shared<BufferMem>(num_pages * Memory::PAGE_SIZE);
|
||||
std::make_shared<BufferMem>(num_pages * Memory::CITRA_PAGE_SIZE);
|
||||
memory.ReadBlock(*src_process, source_address, buffer->GetPtr() + page_offset, size);
|
||||
|
||||
// Map the page(s) into the target process' address space.
|
||||
|
@ -127,7 +127,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) {
|
||||
// Mapped memory page
|
||||
AddressMapping mapping;
|
||||
mapping.address = descriptor << 12;
|
||||
mapping.size = Memory::PAGE_SIZE;
|
||||
mapping.size = Memory::CITRA_PAGE_SIZE;
|
||||
mapping.read_only = false;
|
||||
mapping.unk_flag = false;
|
||||
|
||||
@ -265,7 +265,7 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
|
||||
|
||||
// Free heaps block by block
|
||||
CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(target, size));
|
||||
for (const auto [backing_memory, block_size] : backing_blocks) {
|
||||
for (const auto& [backing_memory, block_size] : backing_blocks) {
|
||||
memory_region->Free(kernel.memory.GetFCRAMOffset(backing_memory.GetPtr()), block_size);
|
||||
}
|
||||
|
||||
@ -396,7 +396,7 @@ ResultCode Process::Map(VAddr target, VAddr source, u32 size, VMAPermission perm
|
||||
|
||||
CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(source, size));
|
||||
VAddr interval_target = target;
|
||||
for (const auto [backing_memory, block_size] : backing_blocks) {
|
||||
for (const auto& [backing_memory, block_size] : backing_blocks) {
|
||||
auto target_vma =
|
||||
vm_manager.MapBackingMemory(interval_target, backing_memory, block_size, target_state);
|
||||
ASSERT(target_vma.Succeeded());
|
||||
|
@ -219,10 +219,10 @@ ResultCode SVC::ControlMemory(u32* out_addr, u32 addr0, u32 addr1, u32 size, u32
|
||||
"size=0x{:X}, permissions=0x{:08X}",
|
||||
operation, addr0, addr1, size, permissions);
|
||||
|
||||
if ((addr0 & Memory::PAGE_MASK) != 0 || (addr1 & Memory::PAGE_MASK) != 0) {
|
||||
if ((addr0 & Memory::CITRA_PAGE_MASK) != 0 || (addr1 & Memory::CITRA_PAGE_MASK) != 0) {
|
||||
return ERR_MISALIGNED_ADDRESS;
|
||||
}
|
||||
if ((size & Memory::PAGE_MASK) != 0) {
|
||||
if ((size & Memory::CITRA_PAGE_MASK) != 0) {
|
||||
return ERR_MISALIGNED_SIZE;
|
||||
}
|
||||
|
||||
@ -1288,7 +1288,7 @@ s64 SVC::GetSystemTick() {
|
||||
/// Creates a memory block at the specified address with the specified permissions and size
|
||||
ResultCode SVC::CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission,
|
||||
u32 other_permission) {
|
||||
if (size % Memory::PAGE_SIZE != 0)
|
||||
if (size % Memory::CITRA_PAGE_SIZE != 0)
|
||||
return ERR_MISALIGNED_SIZE;
|
||||
|
||||
std::shared_ptr<SharedMemory> shared_memory = nullptr;
|
||||
@ -1393,7 +1393,7 @@ ResultCode SVC::AcceptSession(Handle* out_server_session, Handle server_port_han
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static void CopyStringPart(char* out, const char* in, int offset, int max_length) {
|
||||
static void CopyStringPart(char* out, const char* in, size_t offset, size_t max_length) {
|
||||
size_t str_size = strlen(in);
|
||||
if (offset < str_size) {
|
||||
strncpy(out, in + offset, max_length - 1);
|
||||
@ -1509,7 +1509,7 @@ ResultCode SVC::GetProcessInfo(s64* out, Handle process_handle, u32 type) {
|
||||
// TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure
|
||||
// what's the difference between them.
|
||||
*out = process->memory_used;
|
||||
if (*out % Memory::PAGE_SIZE != 0) {
|
||||
if (*out % Memory::CITRA_PAGE_SIZE != 0) {
|
||||
LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned");
|
||||
return ERR_MISALIGNED_SIZE;
|
||||
}
|
||||
|
@ -105,9 +105,9 @@ void Thread::Stop() {
|
||||
ReleaseThreadMutexes(this);
|
||||
|
||||
// Mark the TLS slot in the thread's page as free.
|
||||
u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
|
||||
u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::CITRA_PAGE_SIZE;
|
||||
u32 tls_slot =
|
||||
((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
|
||||
((tls_address - Memory::TLS_AREA_VADDR) % Memory::CITRA_PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
|
||||
ASSERT(owner_process.lock());
|
||||
owner_process.lock()->tls_slots[tls_page].reset(tls_slot);
|
||||
}
|
||||
@ -374,13 +374,13 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
|
||||
auto memory_region = GetMemoryRegion(MemoryRegion::BASE);
|
||||
|
||||
// Allocate some memory from the end of the linear heap for this region.
|
||||
auto offset = memory_region->LinearAllocate(Memory::PAGE_SIZE);
|
||||
auto offset = memory_region->LinearAllocate(Memory::CITRA_PAGE_SIZE);
|
||||
if (!offset) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Not enough space in region to allocate a new TLS page for thread");
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
owner_process->memory_used += Memory::PAGE_SIZE;
|
||||
owner_process->memory_used += Memory::CITRA_PAGE_SIZE;
|
||||
|
||||
tls_slots.emplace_back(0); // The page is completely available at the start
|
||||
available_page = tls_slots.size() - 1;
|
||||
@ -390,14 +390,14 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
|
||||
|
||||
// Map the page to the current process' address space.
|
||||
vm_manager.MapBackingMemory(
|
||||
Memory::TLS_AREA_VADDR + static_cast<VAddr>(available_page) * Memory::PAGE_SIZE,
|
||||
memory.GetFCRAMRef(*offset), Memory::PAGE_SIZE, MemoryState::Locked);
|
||||
Memory::TLS_AREA_VADDR + static_cast<VAddr>(available_page) * Memory::CITRA_PAGE_SIZE,
|
||||
memory.GetFCRAMRef(*offset), Memory::CITRA_PAGE_SIZE, MemoryState::Locked);
|
||||
}
|
||||
|
||||
// Mark the slot as used
|
||||
tls_slots[available_page].set(available_slot);
|
||||
thread->tls_address = Memory::TLS_AREA_VADDR +
|
||||
static_cast<VAddr>(available_page) * Memory::PAGE_SIZE +
|
||||
static_cast<VAddr>(available_page) * Memory::CITRA_PAGE_SIZE +
|
||||
static_cast<VAddr>(available_slot) * Memory::TLS_ENTRY_SIZE;
|
||||
|
||||
memory.ZeroBlock(*owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE);
|
||||
|
@ -260,8 +260,8 @@ VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle& iter) {
|
||||
}
|
||||
|
||||
ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
|
||||
ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size);
|
||||
ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: {:#010X}", base);
|
||||
ASSERT_MSG((size & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size);
|
||||
ASSERT_MSG((base & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned base: {:#010X}", base);
|
||||
|
||||
VMAIter vma_handle = StripIterConstness(FindVMA(base));
|
||||
if (vma_handle == vma_map.end()) {
|
||||
@ -296,8 +296,8 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
|
||||
}
|
||||
|
||||
ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u32 size) {
|
||||
ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size);
|
||||
ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: {:#010X}", target);
|
||||
ASSERT_MSG((size & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size);
|
||||
ASSERT_MSG((target & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned base: {:#010X}", target);
|
||||
|
||||
const VAddr target_end = target + size;
|
||||
ASSERT(target_end >= target);
|
||||
|
@ -17,12 +17,9 @@
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/file_sys/ncch_container.h"
|
||||
#include "core/file_sys/title_metadata.h"
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/session.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
@ -610,7 +607,6 @@ void Module::Interface::FindDLCContentInfos(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
std::string tmd_path = GetTitleMetadataPath(media_type, title_id);
|
||||
|
||||
u32 content_read = 0;
|
||||
FileSys::TitleMetadata tmd;
|
||||
if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) {
|
||||
std::size_t write_offset = 0;
|
||||
@ -642,7 +638,6 @@ void Module::Interface::FindDLCContentInfos(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
content_info_out.Write(&content_info, write_offset, sizeof(ContentInfo));
|
||||
write_offset += sizeof(ContentInfo);
|
||||
content_read++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/common_paths.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/applets/applet.h"
|
||||
#include "core/hle/service/apt/applet_manager.h"
|
||||
@ -27,47 +26,66 @@ struct AppletTitleData {
|
||||
|
||||
static constexpr std::size_t NumApplets = 29;
|
||||
static constexpr std::array<AppletTitleData, NumApplets> applet_titleids = {{
|
||||
{AppletId::HomeMenu, AppletId::None, 0x4003000008202, 0x4003000008F02, 0x4003000009802,
|
||||
0x4003000008202, 0x400300000A102, 0x400300000A902, 0x400300000B102},
|
||||
{AppletId::AlternateMenu, AppletId::None, 0x4003000008102, 0x4003000008102, 0x4003000008102,
|
||||
0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102},
|
||||
{AppletId::Camera, AppletId::None, 0x4003000008402, 0x4003000009002, 0x4003000009902,
|
||||
0x4003000008402, 0x400300000A202, 0x400300000AA02, 0x400300000B202},
|
||||
{AppletId::FriendList, AppletId::None, 0x4003000008D02, 0x4003000009602, 0x4003000009F02,
|
||||
0x4003000008D02, 0x400300000A702, 0x400300000AF02, 0x400300000B702},
|
||||
{AppletId::GameNotes, AppletId::None, 0x4003000008702, 0x4003000009302, 0x4003000009C02,
|
||||
0x4003000008702, 0x400300000A502, 0x400300000AD02, 0x400300000B502},
|
||||
{AppletId::InternetBrowser, AppletId::None, 0x4003000008802, 0x4003000009402, 0x4003000009D02,
|
||||
0x4003000008802, 0x400300000A602, 0x400300000AE02, 0x400300000B602},
|
||||
{AppletId::InstructionManual, AppletId::None, 0x4003000008602, 0x4003000009202, 0x4003000009B02,
|
||||
0x4003000008602, 0x400300000A402, 0x400300000AC02, 0x400300000B402},
|
||||
{AppletId::Notifications, AppletId::None, 0x4003000008E02, 0x4003000009702, 0x400300000A002,
|
||||
0x4003000008E02, 0x400300000A802, 0x400300000B002, 0x400300000B802},
|
||||
{AppletId::Miiverse, AppletId::None, 0x400300000BC02, 0x400300000BD02, 0x400300000BE02,
|
||||
0x400300000BC02, 0x4003000009E02, 0x4003000009502, 0x400300000B902},
|
||||
{{AppletId::HomeMenu, AppletId::None},
|
||||
{0x4003000008202, 0x4003000008F02, 0x4003000009802, 0x4003000008202, 0x400300000A102,
|
||||
0x400300000A902, 0x400300000B102}},
|
||||
{{AppletId::AlternateMenu, AppletId::None},
|
||||
{0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102,
|
||||
0x4003000008102, 0x4003000008102}},
|
||||
{{AppletId::Camera, AppletId::None},
|
||||
{0x4003000008402, 0x4003000009002, 0x4003000009902, 0x4003000008402, 0x400300000A202,
|
||||
0x400300000AA02, 0x400300000B202}},
|
||||
{{AppletId::FriendList, AppletId::None},
|
||||
{0x4003000008D02, 0x4003000009602, 0x4003000009F02, 0x4003000008D02, 0x400300000A702,
|
||||
0x400300000AF02, 0x400300000B702}},
|
||||
{{AppletId::GameNotes, AppletId::None},
|
||||
{0x4003000008702, 0x4003000009302, 0x4003000009C02, 0x4003000008702, 0x400300000A502,
|
||||
0x400300000AD02, 0x400300000B502}},
|
||||
{{AppletId::InternetBrowser, AppletId::None},
|
||||
{0x4003000008802, 0x4003000009402, 0x4003000009D02, 0x4003000008802, 0x400300000A602,
|
||||
0x400300000AE02, 0x400300000B602}},
|
||||
{{AppletId::InstructionManual, AppletId::None},
|
||||
{0x4003000008602, 0x4003000009202, 0x4003000009B02, 0x4003000008602, 0x400300000A402,
|
||||
0x400300000AC02, 0x400300000B402}},
|
||||
{{AppletId::Notifications, AppletId::None},
|
||||
{0x4003000008E02, 0x4003000009702, 0x400300000A002, 0x4003000008E02, 0x400300000A802,
|
||||
0x400300000B002, 0x400300000B802}},
|
||||
{{AppletId::Miiverse, AppletId::None},
|
||||
{0x400300000BC02, 0x400300000BD02, 0x400300000BE02, 0x400300000BC02, 0x4003000009E02,
|
||||
0x4003000009502, 0x400300000B902}},
|
||||
// These values obtained from an older NS dump firmware 4.5
|
||||
{AppletId::MiiversePost, AppletId::None, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02,
|
||||
0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02},
|
||||
{{AppletId::MiiversePost, AppletId::None},
|
||||
{0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02,
|
||||
0x400300000BA02, 0x400300000BA02}},
|
||||
// {AppletId::MiiversePost, AppletId::None, 0x4003000008302, 0x4003000008B02, 0x400300000BA02,
|
||||
// 0x4003000008302, 0x0, 0x0, 0x0},
|
||||
{AppletId::AmiiboSettings, AppletId::None, 0x4003000009502, 0x4003000009E02, 0x400300000B902,
|
||||
0x4003000009502, 0x0, 0x4003000008C02, 0x400300000BF02},
|
||||
{AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2, 0x400300000C002, 0x400300000C802,
|
||||
0x400300000D002, 0x400300000C002, 0x400300000D802, 0x400300000DE02, 0x400300000E402},
|
||||
{AppletId::Ed1, AppletId::Ed2, 0x400300000C102, 0x400300000C902, 0x400300000D102,
|
||||
0x400300000C102, 0x400300000D902, 0x400300000DF02, 0x400300000E502},
|
||||
{AppletId::PnoteApp, AppletId::PnoteApp2, 0x400300000C302, 0x400300000CB02, 0x400300000D302,
|
||||
0x400300000C302, 0x400300000DB02, 0x400300000E102, 0x400300000E702},
|
||||
{AppletId::SnoteApp, AppletId::SnoteApp2, 0x400300000C402, 0x400300000CC02, 0x400300000D402,
|
||||
0x400300000C402, 0x400300000DC02, 0x400300000E202, 0x400300000E802},
|
||||
{AppletId::Error, AppletId::Error2, 0x400300000C502, 0x400300000C502, 0x400300000C502,
|
||||
0x400300000C502, 0x400300000CF02, 0x400300000CF02, 0x400300000CF02},
|
||||
{AppletId::Mint, AppletId::Mint2, 0x400300000C602, 0x400300000CE02, 0x400300000D602,
|
||||
0x400300000C602, 0x400300000DD02, 0x400300000E302, 0x400300000E902},
|
||||
{AppletId::Extrapad, AppletId::Extrapad2, 0x400300000CD02, 0x400300000CD02, 0x400300000CD02,
|
||||
0x400300000CD02, 0x400300000D502, 0x400300000D502, 0x400300000D502},
|
||||
{AppletId::Memolib, AppletId::Memolib2, 0x400300000F602, 0x400300000F602, 0x400300000F602,
|
||||
0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602},
|
||||
{{AppletId::AmiiboSettings, AppletId::None},
|
||||
{0x4003000009502, 0x4003000009E02, 0x400300000B902, 0x4003000009502, 0x0, 0x4003000008C02,
|
||||
0x400300000BF02}},
|
||||
{{AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2},
|
||||
{0x400300000C002, 0x400300000C802, 0x400300000D002, 0x400300000C002, 0x400300000D802,
|
||||
0x400300000DE02, 0x400300000E402}},
|
||||
{{AppletId::Ed1, AppletId::Ed2},
|
||||
{0x400300000C102, 0x400300000C902, 0x400300000D102, 0x400300000C102, 0x400300000D902,
|
||||
0x400300000DF02, 0x400300000E502}},
|
||||
{{AppletId::PnoteApp, AppletId::PnoteApp2},
|
||||
{0x400300000C302, 0x400300000CB02, 0x400300000D302, 0x400300000C302, 0x400300000DB02,
|
||||
0x400300000E102, 0x400300000E702}},
|
||||
{{AppletId::SnoteApp, AppletId::SnoteApp2},
|
||||
{0x400300000C402, 0x400300000CC02, 0x400300000D402, 0x400300000C402, 0x400300000DC02,
|
||||
0x400300000E202, 0x400300000E802}},
|
||||
{{AppletId::Error, AppletId::Error2},
|
||||
{0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000CF02,
|
||||
0x400300000CF02, 0x400300000CF02}},
|
||||
{{AppletId::Mint, AppletId::Mint2},
|
||||
{0x400300000C602, 0x400300000CE02, 0x400300000D602, 0x400300000C602, 0x400300000DD02,
|
||||
0x400300000E302, 0x400300000E902}},
|
||||
{{AppletId::Extrapad, AppletId::Extrapad2},
|
||||
{0x400300000CD02, 0x400300000CD02, 0x400300000CD02, 0x400300000CD02, 0x400300000D502,
|
||||
0x400300000D502, 0x400300000D502}},
|
||||
{{AppletId::Memolib, AppletId::Memolib2},
|
||||
{0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602,
|
||||
0x400300000F602, 0x400300000F602}},
|
||||
// TODO(Subv): Fill in the rest of the titleids
|
||||
}};
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <cryptopp/osrng.h>
|
||||
#include <cryptopp/sha.h>
|
||||
#include "common/archives.h"
|
||||
#include "common/common_paths.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
@ -107,7 +106,6 @@ static_assert(sizeof(ConsoleCountryInfo) == 4, "ConsoleCountryInfo must be exact
|
||||
|
||||
constexpr EULAVersion MAX_EULA_VERSION{0x7F, 0x7F};
|
||||
constexpr ConsoleModelInfo CONSOLE_MODEL_OLD{NINTENDO_3DS_XL, {0, 0, 0}};
|
||||
constexpr ConsoleModelInfo CONSOLE_MODEL_NEW{NEW_NINTENDO_3DS_XL, {0, 0, 0}};
|
||||
constexpr u8 CONSOLE_LANGUAGE = LANGUAGE_EN;
|
||||
constexpr UsernameBlock CONSOLE_USERNAME_BLOCK{u"CITRA", 0, 0};
|
||||
constexpr BirthdayBlock PROFILE_BIRTHDAY{3, 25}; // March 25th, 2014
|
||||
@ -269,7 +267,7 @@ void Module::Interface::GetSystemModel(Kernel::HLERequestContext& ctx) {
|
||||
void Module::Interface::GetModelNintendo2DS(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx, 0x06, 0, 0);
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
u32 data;
|
||||
u32 data{};
|
||||
|
||||
// TODO(Subv): Find out the correct error codes
|
||||
rb.Push(cfg->GetConfigInfoBlock(ConsoleModelBlockID, 4, 0x8, reinterpret_cast<u8*>(&data)));
|
||||
@ -370,7 +368,7 @@ ResultVal<void*> Module::GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 f
|
||||
}
|
||||
|
||||
ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) {
|
||||
void* pointer;
|
||||
void* pointer = nullptr;
|
||||
CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
|
||||
memcpy(output, pointer, size);
|
||||
|
||||
@ -378,7 +376,7 @@ ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* ou
|
||||
}
|
||||
|
||||
ResultCode Module::SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input) {
|
||||
void* pointer;
|
||||
void* pointer = nullptr;
|
||||
CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
|
||||
memcpy(pointer, input, size);
|
||||
return RESULT_SUCCESS;
|
||||
@ -701,7 +699,7 @@ void Module::SetSystemLanguage(SystemLanguage language) {
|
||||
}
|
||||
|
||||
SystemLanguage Module::GetSystemLanguage() {
|
||||
u8 block;
|
||||
u8 block{};
|
||||
GetConfigInfoBlock(LanguageBlockID, sizeof(block), 8, &block);
|
||||
return static_cast<SystemLanguage>(block);
|
||||
}
|
||||
@ -712,7 +710,7 @@ void Module::SetSoundOutputMode(SoundOutputMode mode) {
|
||||
}
|
||||
|
||||
SoundOutputMode Module::GetSoundOutputMode() {
|
||||
u8 block;
|
||||
u8 block{};
|
||||
GetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 8, &block);
|
||||
return static_cast<SoundOutputMode>(block);
|
||||
}
|
||||
@ -723,7 +721,7 @@ void Module::SetCountryCode(u8 country_code) {
|
||||
}
|
||||
|
||||
u8 Module::GetCountryCode() {
|
||||
ConsoleCountryInfo block;
|
||||
ConsoleCountryInfo block{};
|
||||
GetConfigInfoBlock(CountryInfoBlockID, sizeof(block), 8, &block);
|
||||
return block.country_code;
|
||||
}
|
||||
@ -734,7 +732,7 @@ void Module::SetCountryInfo(u8 country_code, u8 state_code) {
|
||||
}
|
||||
|
||||
u8 Module::GetStateCode() {
|
||||
ConsoleCountryInfo block;
|
||||
ConsoleCountryInfo block{};
|
||||
GetConfigInfoBlock(CountryInfoBlockID, sizeof(block), 8, &block);
|
||||
return block.state_code;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
|
@ -192,7 +192,7 @@ static_assert(sizeof(CaptureState) == 0x8, "CaptureState structure size is wrong
|
||||
|
||||
void CSND_SND::Initialize(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx, 0x01, 5, 0);
|
||||
const u32 size = Common::AlignUp(rp.Pop<u32>(), Memory::PAGE_SIZE);
|
||||
const u32 size = Common::AlignUp(rp.Pop<u32>(), Memory::CITRA_PAGE_SIZE);
|
||||
master_state_offset = rp.Pop<u32>();
|
||||
channel_state_offset = rp.Pop<u32>();
|
||||
capture_state_offset = rp.Pop<u32>();
|
||||
|
@ -95,6 +95,9 @@ void DSP_DSP::WriteProcessPipe(Kernel::HLERequestContext& ctx) {
|
||||
buffer[6] = 0;
|
||||
buffer[7] = 0;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR(Service_DSP, "Unknown pipe {}", pipe);
|
||||
break;
|
||||
}
|
||||
|
||||
system.DSP().PipeWrite(pipe, buffer);
|
||||
|
@ -884,6 +884,8 @@ ResultVal<u16> FS_USER::GetSpecialContentIndexFromTMD(MediaType media_type, u64
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
return ResultCode(-1);
|
||||
}
|
||||
|
||||
FS_USER::FS_USER(Core::System& system)
|
||||
|
@ -8,9 +8,7 @@
|
||||
#include "common/microprofile.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/kernel/shared_page.h"
|
||||
#include "core/hle/result.h"
|
||||
@ -83,7 +81,9 @@ u32 GSP_GPU::GetUnusedThreadId() const {
|
||||
if (!used_thread_ids[id])
|
||||
return id;
|
||||
}
|
||||
ASSERT_MSG(false, "All GSP threads are in use");
|
||||
|
||||
UNREACHABLE_MSG("All GSP threads are in use");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Gets a pointer to a thread command buffer in GSP shared memory
|
||||
|
@ -1502,7 +1502,7 @@ u32 CROHelper::Fix(u32 fix_level) {
|
||||
}
|
||||
}
|
||||
|
||||
fix_end = Common::AlignUp(fix_end, Memory::PAGE_SIZE);
|
||||
fix_end = Common::AlignUp(fix_end, Memory::CITRA_PAGE_SIZE);
|
||||
|
||||
u32 fixed_size = fix_end - module_address;
|
||||
SetField(FixedSize, fixed_size);
|
||||
@ -1525,8 +1525,8 @@ std::tuple<VAddr, u32> CROHelper::GetExecutablePages() const {
|
||||
SegmentEntry entry;
|
||||
GetEntry(system.Memory(), i, entry);
|
||||
if (entry.type == SegmentType::Code && entry.size != 0) {
|
||||
VAddr begin = Common::AlignDown(entry.offset, Memory::PAGE_SIZE);
|
||||
VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::PAGE_SIZE);
|
||||
VAddr begin = Common::AlignDown(entry.offset, Memory::CITRA_PAGE_SIZE);
|
||||
VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::CITRA_PAGE_SIZE);
|
||||
return std::make_tuple(begin, end - begin);
|
||||
}
|
||||
}
|
||||
|
@ -87,19 +87,19 @@ void RO::Initialize(Kernel::HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (crs_buffer_ptr & Memory::PAGE_MASK) {
|
||||
if (crs_buffer_ptr & Memory::CITRA_PAGE_MASK) {
|
||||
LOG_ERROR(Service_LDR, "CRS original address is not aligned");
|
||||
rb.Push(ERROR_MISALIGNED_ADDRESS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (crs_address & Memory::PAGE_MASK) {
|
||||
if (crs_address & Memory::CITRA_PAGE_MASK) {
|
||||
LOG_ERROR(Service_LDR, "CRS mapping address is not aligned");
|
||||
rb.Push(ERROR_MISALIGNED_ADDRESS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (crs_size & Memory::PAGE_MASK) {
|
||||
if (crs_size & Memory::CITRA_PAGE_MASK) {
|
||||
LOG_ERROR(Service_LDR, "CRS size is not aligned");
|
||||
rb.Push(ERROR_MISALIGNED_SIZE);
|
||||
return;
|
||||
@ -207,21 +207,21 @@ void RO::LoadCRO(Kernel::HLERequestContext& ctx, bool link_on_load_bug_fix) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cro_buffer_ptr & Memory::PAGE_MASK) {
|
||||
if (cro_buffer_ptr & Memory::CITRA_PAGE_MASK) {
|
||||
LOG_ERROR(Service_LDR, "CRO original address is not aligned");
|
||||
rb.Push(ERROR_MISALIGNED_ADDRESS);
|
||||
rb.Push<u32>(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cro_address & Memory::PAGE_MASK) {
|
||||
if (cro_address & Memory::CITRA_PAGE_MASK) {
|
||||
LOG_ERROR(Service_LDR, "CRO mapping address is not aligned");
|
||||
rb.Push(ERROR_MISALIGNED_ADDRESS);
|
||||
rb.Push<u32>(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cro_size & Memory::PAGE_MASK) {
|
||||
if (cro_size & Memory::CITRA_PAGE_MASK) {
|
||||
LOG_ERROR(Service_LDR, "CRO size is not aligned");
|
||||
rb.Push(ERROR_MISALIGNED_SIZE);
|
||||
rb.Push<u32>(0);
|
||||
@ -354,7 +354,7 @@ void RO::UnloadCRO(Kernel::HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cro_address & Memory::PAGE_MASK) {
|
||||
if (cro_address & Memory::CITRA_PAGE_MASK) {
|
||||
LOG_ERROR(Service_LDR, "CRO address is not aligned");
|
||||
rb.Push(ERROR_MISALIGNED_ADDRESS);
|
||||
return;
|
||||
@ -421,7 +421,7 @@ void RO::LinkCRO(Kernel::HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cro_address & Memory::PAGE_MASK) {
|
||||
if (cro_address & Memory::CITRA_PAGE_MASK) {
|
||||
LOG_ERROR(Service_LDR, "CRO address is not aligned");
|
||||
rb.Push(ERROR_MISALIGNED_ADDRESS);
|
||||
return;
|
||||
@ -461,7 +461,7 @@ void RO::UnlinkCRO(Kernel::HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cro_address & Memory::PAGE_MASK) {
|
||||
if (cro_address & Memory::CITRA_PAGE_MASK) {
|
||||
LOG_ERROR(Service_LDR, "CRO address is not aligned");
|
||||
rb.Push(ERROR_MISALIGNED_ADDRESS);
|
||||
return;
|
||||
|
@ -92,7 +92,8 @@ u16 NWM_UDS::GetNextAvailableNodeId() {
|
||||
}
|
||||
|
||||
// Any connection attempts to an already full network should have been refused.
|
||||
ASSERT_MSG(false, "No available connection slots in the network");
|
||||
UNREACHABLE_MSG("No available connection slots in the network");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NWM_UDS::BroadcastNodeMap() {
|
||||
|
@ -15,9 +15,6 @@
|
||||
|
||||
namespace Service::NWM {
|
||||
|
||||
// 802.11 broadcast MAC address
|
||||
constexpr MacAddress BroadcastMac = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
constexpr u64 DefaultNetworkUptime = 900000000; // 15 minutes in microseconds.
|
||||
|
||||
// Note: These values were taken from a packet capture of an o3DS XL
|
||||
|
@ -178,15 +178,6 @@ static const std::unordered_map<int, int> sockopt_map = {{
|
||||
{0x1009, SO_ERROR},
|
||||
}};
|
||||
|
||||
/// Converts a socket option from 3ds-specific to platform-specific
|
||||
static int TranslateSockOpt(int console_opt_name) {
|
||||
auto found = sockopt_map.find(console_opt_name);
|
||||
if (found != sockopt_map.end()) {
|
||||
return found->second;
|
||||
}
|
||||
return console_opt_name;
|
||||
}
|
||||
|
||||
/// Structure to represent the 3ds' pollfd structure, which is different than most implementations
|
||||
struct CTRPollFD {
|
||||
u32 fd; ///< Socket handle
|
||||
|
@ -68,9 +68,11 @@ struct Regs {
|
||||
case PixelFormat::RGB5A1:
|
||||
case PixelFormat::RGBA4:
|
||||
return 2;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
INSERT_PADDING_WORDS(0x4);
|
||||
|
@ -94,13 +94,13 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process)
|
||||
codeset->CodeSegment().offset = 0;
|
||||
codeset->CodeSegment().addr = overlay_ncch->exheader_header.codeset_info.text.address;
|
||||
codeset->CodeSegment().size =
|
||||
overlay_ncch->exheader_header.codeset_info.text.num_max_pages * Memory::PAGE_SIZE;
|
||||
overlay_ncch->exheader_header.codeset_info.text.num_max_pages * Memory::CITRA_PAGE_SIZE;
|
||||
|
||||
codeset->RODataSegment().offset =
|
||||
codeset->CodeSegment().offset + codeset->CodeSegment().size;
|
||||
codeset->RODataSegment().addr = overlay_ncch->exheader_header.codeset_info.ro.address;
|
||||
codeset->RODataSegment().size =
|
||||
overlay_ncch->exheader_header.codeset_info.ro.num_max_pages * Memory::PAGE_SIZE;
|
||||
overlay_ncch->exheader_header.codeset_info.ro.num_max_pages * Memory::CITRA_PAGE_SIZE;
|
||||
|
||||
// TODO(yuriks): Not sure if the bss size is added to the page-aligned .data size or just
|
||||
// to the regular size. Playing it safe for now.
|
||||
@ -111,7 +111,8 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process)
|
||||
codeset->RODataSegment().offset + codeset->RODataSegment().size;
|
||||
codeset->DataSegment().addr = overlay_ncch->exheader_header.codeset_info.data.address;
|
||||
codeset->DataSegment().size =
|
||||
overlay_ncch->exheader_header.codeset_info.data.num_max_pages * Memory::PAGE_SIZE +
|
||||
overlay_ncch->exheader_header.codeset_info.data.num_max_pages *
|
||||
Memory::CITRA_PAGE_SIZE +
|
||||
bss_page_size;
|
||||
|
||||
// Apply patches now that the entire codeset (including .bss) has been allocated
|
||||
|
@ -55,20 +55,20 @@ public:
|
||||
private:
|
||||
bool* At(VAddr addr) {
|
||||
if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
|
||||
return &vram[(addr - VRAM_VADDR) / PAGE_SIZE];
|
||||
return &vram[(addr - VRAM_VADDR) / CITRA_PAGE_SIZE];
|
||||
}
|
||||
if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) {
|
||||
return &linear_heap[(addr - LINEAR_HEAP_VADDR) / PAGE_SIZE];
|
||||
return &linear_heap[(addr - LINEAR_HEAP_VADDR) / CITRA_PAGE_SIZE];
|
||||
}
|
||||
if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) {
|
||||
return &new_linear_heap[(addr - NEW_LINEAR_HEAP_VADDR) / PAGE_SIZE];
|
||||
return &new_linear_heap[(addr - NEW_LINEAR_HEAP_VADDR) / CITRA_PAGE_SIZE];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::array<bool, VRAM_SIZE / PAGE_SIZE> vram{};
|
||||
std::array<bool, LINEAR_HEAP_SIZE / PAGE_SIZE> linear_heap{};
|
||||
std::array<bool, NEW_LINEAR_HEAP_SIZE / PAGE_SIZE> new_linear_heap{};
|
||||
std::array<bool, VRAM_SIZE / CITRA_PAGE_SIZE> vram{};
|
||||
std::array<bool, LINEAR_HEAP_SIZE / CITRA_PAGE_SIZE> linear_heap{};
|
||||
std::array<bool, NEW_LINEAR_HEAP_SIZE / CITRA_PAGE_SIZE> new_linear_heap{};
|
||||
|
||||
static_assert(sizeof(bool) == 1);
|
||||
friend class boost::serialization::access;
|
||||
@ -221,10 +221,10 @@ std::shared_ptr<PageTable> MemorySystem::GetCurrentPageTable() const {
|
||||
|
||||
void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory,
|
||||
PageType type) {
|
||||
LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(), base * PAGE_SIZE,
|
||||
(base + size) * PAGE_SIZE);
|
||||
LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(),
|
||||
base * CITRA_PAGE_SIZE, (base + size) * CITRA_PAGE_SIZE);
|
||||
|
||||
RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE,
|
||||
RasterizerFlushVirtualRegion(base << CITRA_PAGE_BITS, size * CITRA_PAGE_SIZE,
|
||||
FlushMode::FlushAndInvalidate);
|
||||
|
||||
u32 end = base + size;
|
||||
@ -235,36 +235,38 @@ void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef
|
||||
page_table.pointers[base] = memory;
|
||||
|
||||
// If the memory to map is already rasterizer-cached, mark the page
|
||||
if (type == PageType::Memory && impl->cache_marker.IsCached(base * PAGE_SIZE)) {
|
||||
if (type == PageType::Memory && impl->cache_marker.IsCached(base * CITRA_PAGE_SIZE)) {
|
||||
page_table.attributes[base] = PageType::RasterizerCachedMemory;
|
||||
page_table.pointers[base] = nullptr;
|
||||
}
|
||||
|
||||
base += 1;
|
||||
if (memory != nullptr && memory.GetSize() > PAGE_SIZE)
|
||||
memory += PAGE_SIZE;
|
||||
if (memory != nullptr && memory.GetSize() > CITRA_PAGE_SIZE)
|
||||
memory += CITRA_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void MemorySystem::MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, MemoryRef target) {
|
||||
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
|
||||
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
|
||||
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory);
|
||||
ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
|
||||
ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
|
||||
MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, target, PageType::Memory);
|
||||
}
|
||||
|
||||
void MemorySystem::MapIoRegion(PageTable& page_table, VAddr base, u32 size,
|
||||
MMIORegionPointer mmio_handler) {
|
||||
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
|
||||
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
|
||||
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special);
|
||||
ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
|
||||
ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
|
||||
MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, nullptr,
|
||||
PageType::Special);
|
||||
|
||||
page_table.special_regions.emplace_back(SpecialRegion{base, size, mmio_handler});
|
||||
}
|
||||
|
||||
void MemorySystem::UnmapRegion(PageTable& page_table, VAddr base, u32 size) {
|
||||
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
|
||||
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
|
||||
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped);
|
||||
ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
|
||||
ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
|
||||
MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, nullptr,
|
||||
PageType::Unmapped);
|
||||
}
|
||||
|
||||
MemoryRef MemorySystem::GetPointerForRasterizerCache(VAddr addr) const {
|
||||
@ -309,15 +311,15 @@ T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr);
|
||||
|
||||
template <typename T>
|
||||
T MemorySystem::Read(const VAddr vaddr) {
|
||||
const u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||
const u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
|
||||
if (page_pointer) {
|
||||
// NOTE: Avoid adding any extra logic to this fast-path block
|
||||
T value;
|
||||
std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T));
|
||||
std::memcpy(&value, &page_pointer[vaddr & CITRA_PAGE_MASK], sizeof(T));
|
||||
return value;
|
||||
}
|
||||
|
||||
PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS];
|
||||
PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS];
|
||||
switch (type) {
|
||||
case PageType::Unmapped:
|
||||
LOG_ERROR(HW_Memory, "unmapped Read{} @ 0x{:08X} at PC 0x{:08X}", sizeof(T) * 8, vaddr,
|
||||
@ -345,14 +347,14 @@ void WriteMMIO(MMIORegionPointer mmio_handler, VAddr addr, const T data);
|
||||
|
||||
template <typename T>
|
||||
void MemorySystem::Write(const VAddr vaddr, const T data) {
|
||||
u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||
u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
|
||||
if (page_pointer) {
|
||||
// NOTE: Avoid adding any extra logic to this fast-path block
|
||||
std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
|
||||
std::memcpy(&page_pointer[vaddr & CITRA_PAGE_MASK], &data, sizeof(T));
|
||||
return;
|
||||
}
|
||||
|
||||
PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS];
|
||||
PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS];
|
||||
switch (type) {
|
||||
case PageType::Unmapped:
|
||||
LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}",
|
||||
@ -376,15 +378,15 @@ void MemorySystem::Write(const VAddr vaddr, const T data) {
|
||||
|
||||
template <typename T>
|
||||
bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expected) {
|
||||
u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||
u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
|
||||
|
||||
if (page_pointer) {
|
||||
const auto volatile_pointer =
|
||||
reinterpret_cast<volatile T*>(&page_pointer[vaddr & PAGE_MASK]);
|
||||
reinterpret_cast<volatile T*>(&page_pointer[vaddr & CITRA_PAGE_MASK]);
|
||||
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
|
||||
}
|
||||
|
||||
PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS];
|
||||
PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS];
|
||||
switch (type) {
|
||||
case PageType::Unmapped:
|
||||
LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}",
|
||||
@ -411,14 +413,14 @@ bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expec
|
||||
bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
|
||||
auto& page_table = *process.vm_manager.page_table;
|
||||
|
||||
auto page_pointer = page_table.pointers[vaddr >> PAGE_BITS];
|
||||
auto page_pointer = page_table.pointers[vaddr >> CITRA_PAGE_BITS];
|
||||
if (page_pointer)
|
||||
return true;
|
||||
|
||||
if (page_table.attributes[vaddr >> PAGE_BITS] == PageType::RasterizerCachedMemory)
|
||||
if (page_table.attributes[vaddr >> CITRA_PAGE_BITS] == PageType::RasterizerCachedMemory)
|
||||
return true;
|
||||
|
||||
if (page_table.attributes[vaddr >> PAGE_BITS] != PageType::Special)
|
||||
if (page_table.attributes[vaddr >> CITRA_PAGE_BITS] != PageType::Special)
|
||||
return false;
|
||||
|
||||
MMIORegionPointer mmio_region = GetMMIOHandler(page_table, vaddr);
|
||||
@ -434,12 +436,12 @@ bool MemorySystem::IsValidPhysicalAddress(const PAddr paddr) const {
|
||||
}
|
||||
|
||||
u8* MemorySystem::GetPointer(const VAddr vaddr) {
|
||||
u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||
u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
|
||||
if (page_pointer) {
|
||||
return page_pointer + (vaddr & PAGE_MASK);
|
||||
return page_pointer + (vaddr & CITRA_PAGE_MASK);
|
||||
}
|
||||
|
||||
if (impl->current_page_table->attributes[vaddr >> PAGE_BITS] ==
|
||||
if (impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS] ==
|
||||
PageType::RasterizerCachedMemory) {
|
||||
return GetPointerForRasterizerCache(vaddr);
|
||||
}
|
||||
@ -450,12 +452,12 @@ u8* MemorySystem::GetPointer(const VAddr vaddr) {
|
||||
}
|
||||
|
||||
const u8* MemorySystem::GetPointer(const VAddr vaddr) const {
|
||||
const u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||
const u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
|
||||
if (page_pointer) {
|
||||
return page_pointer + (vaddr & PAGE_MASK);
|
||||
return page_pointer + (vaddr & CITRA_PAGE_MASK);
|
||||
}
|
||||
|
||||
if (impl->current_page_table->attributes[vaddr >> PAGE_BITS] ==
|
||||
if (impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS] ==
|
||||
PageType::RasterizerCachedMemory) {
|
||||
return GetPointerForRasterizerCache(vaddr);
|
||||
}
|
||||
@ -487,35 +489,29 @@ const u8* MemorySystem::GetPhysicalPointer(PAddr address) const {
|
||||
}
|
||||
|
||||
MemoryRef MemorySystem::GetPhysicalRef(PAddr address) const {
|
||||
struct MemoryArea {
|
||||
PAddr paddr_base;
|
||||
u32 size;
|
||||
constexpr std::array memory_areas = {
|
||||
std::make_pair(VRAM_PADDR, VRAM_SIZE),
|
||||
std::make_pair(DSP_RAM_PADDR, DSP_RAM_SIZE),
|
||||
std::make_pair(FCRAM_PADDR, FCRAM_N3DS_SIZE),
|
||||
std::make_pair(N3DS_EXTRA_RAM_PADDR, N3DS_EXTRA_RAM_SIZE),
|
||||
};
|
||||
|
||||
static constexpr MemoryArea memory_areas[] = {
|
||||
{VRAM_PADDR, VRAM_SIZE},
|
||||
{DSP_RAM_PADDR, DSP_RAM_SIZE},
|
||||
{FCRAM_PADDR, FCRAM_N3DS_SIZE},
|
||||
{N3DS_EXTRA_RAM_PADDR, N3DS_EXTRA_RAM_SIZE},
|
||||
};
|
||||
const auto area = std::find_if(memory_areas.begin(), memory_areas.end(), [&](const auto& area) {
|
||||
// Note: the region end check is inclusive because the user can pass in an address that
|
||||
// represents an open right bound
|
||||
return address >= area.first && address <= area.first + area.second;
|
||||
});
|
||||
|
||||
const auto area =
|
||||
std::find_if(std::begin(memory_areas), std::end(memory_areas), [&](const auto& area) {
|
||||
// Note: the region end check is inclusive because the user can pass in an address that
|
||||
// represents an open right bound
|
||||
return address >= area.paddr_base && address <= area.paddr_base + area.size;
|
||||
});
|
||||
|
||||
if (area == std::end(memory_areas)) {
|
||||
LOG_ERROR(HW_Memory, "unknown GetPhysicalPointer @ 0x{:08X} at PC 0x{:08X}", address,
|
||||
if (area == memory_areas.end()) {
|
||||
LOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ {:#08X} at PC {:#08X}", address,
|
||||
Core::GetRunningCore().GetPC());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
u32 offset_into_region = address - area->paddr_base;
|
||||
u32 offset_into_region = address - area->first;
|
||||
|
||||
std::shared_ptr<BackingMem> target_mem = nullptr;
|
||||
switch (area->paddr_base) {
|
||||
switch (area->first) {
|
||||
case VRAM_PADDR:
|
||||
target_mem = impl->vram_mem;
|
||||
break;
|
||||
@ -564,14 +560,14 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached
|
||||
return;
|
||||
}
|
||||
|
||||
u32 num_pages = ((start + size - 1) >> PAGE_BITS) - (start >> PAGE_BITS) + 1;
|
||||
u32 num_pages = ((start + size - 1) >> CITRA_PAGE_BITS) - (start >> CITRA_PAGE_BITS) + 1;
|
||||
PAddr paddr = start;
|
||||
|
||||
for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) {
|
||||
for (unsigned i = 0; i < num_pages; ++i, paddr += CITRA_PAGE_SIZE) {
|
||||
for (VAddr vaddr : PhysicalToVirtualAddressForRasterizer(paddr)) {
|
||||
impl->cache_marker.Mark(vaddr, cached);
|
||||
for (auto page_table : impl->page_table_list) {
|
||||
PageType& page_type = page_table->attributes[vaddr >> PAGE_BITS];
|
||||
PageType& page_type = page_table->attributes[vaddr >> CITRA_PAGE_BITS];
|
||||
|
||||
if (cached) {
|
||||
// Switch page type to cached if now cached
|
||||
@ -582,7 +578,7 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached
|
||||
break;
|
||||
case PageType::Memory:
|
||||
page_type = PageType::RasterizerCachedMemory;
|
||||
page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
|
||||
page_table->pointers[vaddr >> CITRA_PAGE_BITS] = nullptr;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -596,8 +592,8 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached
|
||||
break;
|
||||
case PageType::RasterizerCachedMemory: {
|
||||
page_type = PageType::Memory;
|
||||
page_table->pointers[vaddr >> PAGE_BITS] =
|
||||
GetPointerForRasterizerCache(vaddr & ~PAGE_MASK);
|
||||
page_table->pointers[vaddr >> CITRA_PAGE_BITS] =
|
||||
GetPointerForRasterizerCache(vaddr & ~CITRA_PAGE_MASK);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -705,12 +701,12 @@ void MemorySystem::ReadBlock(const Kernel::Process& process, const VAddr src_add
|
||||
auto& page_table = *process.vm_manager.page_table;
|
||||
|
||||
std::size_t remaining_size = size;
|
||||
std::size_t page_index = src_addr >> PAGE_BITS;
|
||||
std::size_t page_offset = src_addr & PAGE_MASK;
|
||||
std::size_t page_index = src_addr >> CITRA_PAGE_BITS;
|
||||
std::size_t page_offset = src_addr & CITRA_PAGE_MASK;
|
||||
|
||||
while (remaining_size > 0) {
|
||||
const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size);
|
||||
const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
|
||||
const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size);
|
||||
const VAddr current_vaddr = static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset);
|
||||
|
||||
switch (page_table.attributes[page_index]) {
|
||||
case PageType::Unmapped: {
|
||||
@ -787,12 +783,12 @@ void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_a
|
||||
const void* src_buffer, const std::size_t size) {
|
||||
auto& page_table = *process.vm_manager.page_table;
|
||||
std::size_t remaining_size = size;
|
||||
std::size_t page_index = dest_addr >> PAGE_BITS;
|
||||
std::size_t page_offset = dest_addr & PAGE_MASK;
|
||||
std::size_t page_index = dest_addr >> CITRA_PAGE_BITS;
|
||||
std::size_t page_offset = dest_addr & CITRA_PAGE_MASK;
|
||||
|
||||
while (remaining_size > 0) {
|
||||
const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size);
|
||||
const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
|
||||
const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size);
|
||||
const VAddr current_vaddr = static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset);
|
||||
|
||||
switch (page_table.attributes[page_index]) {
|
||||
case PageType::Unmapped: {
|
||||
@ -836,14 +832,14 @@ void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_ad
|
||||
const std::size_t size) {
|
||||
auto& page_table = *process.vm_manager.page_table;
|
||||
std::size_t remaining_size = size;
|
||||
std::size_t page_index = dest_addr >> PAGE_BITS;
|
||||
std::size_t page_offset = dest_addr & PAGE_MASK;
|
||||
std::size_t page_index = dest_addr >> CITRA_PAGE_BITS;
|
||||
std::size_t page_offset = dest_addr & CITRA_PAGE_MASK;
|
||||
|
||||
static const std::array<u8, PAGE_SIZE> zeros = {};
|
||||
static const std::array<u8, CITRA_PAGE_SIZE> zeros = {};
|
||||
|
||||
while (remaining_size > 0) {
|
||||
const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size);
|
||||
const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
|
||||
const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size);
|
||||
const VAddr current_vaddr = static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset);
|
||||
|
||||
switch (page_table.attributes[page_index]) {
|
||||
case PageType::Unmapped: {
|
||||
@ -892,12 +888,12 @@ void MemorySystem::CopyBlock(const Kernel::Process& dest_process,
|
||||
std::size_t size) {
|
||||
auto& page_table = *src_process.vm_manager.page_table;
|
||||
std::size_t remaining_size = size;
|
||||
std::size_t page_index = src_addr >> PAGE_BITS;
|
||||
std::size_t page_offset = src_addr & PAGE_MASK;
|
||||
std::size_t page_index = src_addr >> CITRA_PAGE_BITS;
|
||||
std::size_t page_offset = src_addr & CITRA_PAGE_MASK;
|
||||
|
||||
while (remaining_size > 0) {
|
||||
const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size);
|
||||
const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
|
||||
const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size);
|
||||
const VAddr current_vaddr = static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset);
|
||||
|
||||
switch (page_table.attributes[page_index]) {
|
||||
case PageType::Unmapped: {
|
||||
|
@ -3,7 +3,6 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
@ -27,17 +26,14 @@ class DspInterface;
|
||||
|
||||
namespace Memory {
|
||||
|
||||
// Are defined in a system header
|
||||
#undef PAGE_SIZE
|
||||
#undef PAGE_MASK
|
||||
/**
|
||||
* Page size used by the ARM architecture. This is the smallest granularity with which memory can
|
||||
* be mapped.
|
||||
*/
|
||||
const u32 PAGE_SIZE = 0x1000;
|
||||
const u32 PAGE_MASK = PAGE_SIZE - 1;
|
||||
const int PAGE_BITS = 12;
|
||||
const std::size_t PAGE_TABLE_NUM_ENTRIES = 1 << (32 - PAGE_BITS);
|
||||
constexpr u32 CITRA_PAGE_SIZE = 0x1000;
|
||||
constexpr u32 CITRA_PAGE_MASK = CITRA_PAGE_SIZE - 1;
|
||||
constexpr int CITRA_PAGE_BITS = 12;
|
||||
constexpr std::size_t PAGE_TABLE_NUM_ENTRIES = 1 << (32 - CITRA_PAGE_BITS);
|
||||
|
||||
enum class PageType {
|
||||
/// Page is unmapped and should cause an access error.
|
||||
@ -367,6 +363,7 @@ public:
|
||||
u8* GetPointer(VAddr vaddr);
|
||||
const u8* GetPointer(VAddr vaddr) const;
|
||||
|
||||
/// Returns true if the address refers to a valid memory region
|
||||
bool IsValidPhysicalAddress(PAddr paddr) const;
|
||||
|
||||
/// Gets offset in FCRAM from a pointer inside FCRAM range
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "audio_core/dsp_interface.h"
|
||||
#include "core/core.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/hle/kernel/shared_page.h"
|
||||
#include "core/hle/service/cam/cam.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/ir/ir_rst.h"
|
||||
@ -19,10 +18,20 @@
|
||||
|
||||
namespace Settings {
|
||||
|
||||
std::string_view GetAPIName(GraphicsAPI api) {
|
||||
switch (api) {
|
||||
case GraphicsAPI::OpenGL:
|
||||
return "OpenGL";
|
||||
case GraphicsAPI::OpenGLES:
|
||||
return "OpenGLES";
|
||||
case GraphicsAPI::Vulkan:
|
||||
return "Vulkan";
|
||||
}
|
||||
}
|
||||
|
||||
Values values = {};
|
||||
|
||||
void Apply() {
|
||||
|
||||
GDBStub::SetServerPort(values.gdbstub_port);
|
||||
GDBStub::ToggleServer(values.use_gdbstub);
|
||||
|
||||
@ -73,62 +82,62 @@ void Apply() {
|
||||
}
|
||||
|
||||
void LogSettings() {
|
||||
const auto log_setting = [](std::string_view name, const auto& value) {
|
||||
const auto LogSetting = [](std::string_view name, const auto& value) {
|
||||
LOG_INFO(Config, "{}: {}", name, value);
|
||||
};
|
||||
|
||||
LOG_INFO(Config, "Citra Configuration:");
|
||||
log_setting("Core_UseCpuJit", values.use_cpu_jit);
|
||||
log_setting("Core_CPUClockPercentage", values.cpu_clock_percentage);
|
||||
log_setting("Renderer_UseGLES", values.use_gles);
|
||||
log_setting("Renderer_UseHwRenderer", values.use_hw_renderer);
|
||||
log_setting("Renderer_UseHwShader", values.use_hw_shader);
|
||||
log_setting("Renderer_SeparableShader", values.separable_shader);
|
||||
log_setting("Renderer_ShadersAccurateMul", values.shaders_accurate_mul);
|
||||
log_setting("Renderer_UseShaderJit", values.use_shader_jit);
|
||||
log_setting("Renderer_UseResolutionFactor", values.resolution_factor);
|
||||
log_setting("Renderer_FrameLimit", values.frame_limit);
|
||||
log_setting("Renderer_UseFrameLimitAlternate", values.use_frame_limit_alternate);
|
||||
log_setting("Renderer_FrameLimitAlternate", values.frame_limit_alternate);
|
||||
log_setting("Renderer_VSyncNew", values.use_vsync_new);
|
||||
log_setting("Renderer_PostProcessingShader", values.pp_shader_name);
|
||||
log_setting("Renderer_FilterMode", values.filter_mode);
|
||||
log_setting("Renderer_TextureFilterName", values.texture_filter_name);
|
||||
log_setting("Stereoscopy_Render3d", values.render_3d);
|
||||
log_setting("Stereoscopy_Factor3d", values.factor_3d);
|
||||
log_setting("Layout_LayoutOption", values.layout_option);
|
||||
log_setting("Layout_SwapScreen", values.swap_screen);
|
||||
log_setting("Layout_UprightScreen", values.upright_screen);
|
||||
log_setting("Utility_DumpTextures", values.dump_textures);
|
||||
log_setting("Utility_CustomTextures", values.custom_textures);
|
||||
log_setting("Utility_UseDiskShaderCache", values.use_disk_shader_cache);
|
||||
log_setting("Audio_EnableDspLle", values.enable_dsp_lle);
|
||||
log_setting("Audio_EnableDspLleMultithread", values.enable_dsp_lle_multithread);
|
||||
log_setting("Audio_OutputEngine", values.sink_id);
|
||||
log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching);
|
||||
log_setting("Audio_OutputDevice", values.audio_device_id);
|
||||
log_setting("Audio_InputDeviceType", values.mic_input_type);
|
||||
log_setting("Audio_InputDevice", values.mic_input_device);
|
||||
using namespace Service::CAM;
|
||||
log_setting("Camera_OuterRightName", values.camera_name[OuterRightCamera]);
|
||||
log_setting("Camera_OuterRightConfig", values.camera_config[OuterRightCamera]);
|
||||
log_setting("Camera_OuterRightFlip", values.camera_flip[OuterRightCamera]);
|
||||
log_setting("Camera_InnerName", values.camera_name[InnerCamera]);
|
||||
log_setting("Camera_InnerConfig", values.camera_config[InnerCamera]);
|
||||
log_setting("Camera_InnerFlip", values.camera_flip[InnerCamera]);
|
||||
log_setting("Camera_OuterLeftName", values.camera_name[OuterLeftCamera]);
|
||||
log_setting("Camera_OuterLeftConfig", values.camera_config[OuterLeftCamera]);
|
||||
log_setting("Camera_OuterLeftFlip", values.camera_flip[OuterLeftCamera]);
|
||||
log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd);
|
||||
log_setting("DataStorage_UseCustomStorage", values.use_custom_storage);
|
||||
LogSetting("Core_UseCpuJit", values.use_cpu_jit);
|
||||
LogSetting("Core_CPUClockPercentage", values.cpu_clock_percentage);
|
||||
LogSetting("Renderer_GraphicsAPI", GetAPIName(values.graphics_api));
|
||||
LogSetting("Renderer_AsyncRecording", values.async_command_recording);
|
||||
LogSetting("Renderer_UseHwRenderer", values.use_hw_renderer);
|
||||
LogSetting("Renderer_UseHwShader", values.use_hw_shader);
|
||||
LogSetting("Renderer_SeparableShader", values.separable_shader);
|
||||
LogSetting("Renderer_ShadersAccurateMul", values.shaders_accurate_mul);
|
||||
LogSetting("Renderer_UseShaderJit", values.use_shader_jit);
|
||||
LogSetting("Renderer_UseResolutionFactor", values.resolution_factor);
|
||||
LogSetting("Renderer_FrameLimit", values.frame_limit);
|
||||
LogSetting("Renderer_UseFrameLimitAlternate", values.use_frame_limit_alternate);
|
||||
LogSetting("Renderer_FrameLimitAlternate", values.frame_limit_alternate);
|
||||
LogSetting("Renderer_VSyncNew", values.use_vsync_new);
|
||||
LogSetting("Renderer_PostProcessingShader", values.pp_shader_name);
|
||||
LogSetting("Renderer_FilterMode", values.filter_mode);
|
||||
LogSetting("Renderer_TextureFilterName", values.texture_filter_name);
|
||||
LogSetting("Stereoscopy_Render3d", values.render_3d);
|
||||
LogSetting("Stereoscopy_Factor3d", values.factor_3d);
|
||||
LogSetting("Layout_LayoutOption", values.layout_option);
|
||||
LogSetting("Layout_SwapScreen", values.swap_screen);
|
||||
LogSetting("Layout_UprightScreen", values.upright_screen);
|
||||
LogSetting("Utility_DumpTextures", values.dump_textures);
|
||||
LogSetting("Utility_CustomTextures", values.custom_textures);
|
||||
LogSetting("Utility_UseDiskShaderCache", values.use_disk_shader_cache);
|
||||
LogSetting("Audio_EnableDspLle", values.enable_dsp_lle);
|
||||
LogSetting("Audio_EnableDspLleMultithread", values.enable_dsp_lle_multithread);
|
||||
LogSetting("Audio_OutputEngine", values.sink_id);
|
||||
LogSetting("Audio_EnableAudioStretching", values.enable_audio_stretching);
|
||||
LogSetting("Audio_OutputDevice", values.audio_device_id);
|
||||
LogSetting("Audio_InputDeviceType", values.mic_input_type);
|
||||
LogSetting("Audio_InputDevice", values.mic_input_device);
|
||||
LogSetting("Camera_OuterRightName", values.camera_name[Service::CAM::OuterRightCamera]);
|
||||
LogSetting("Camera_OuterRightConfig", values.camera_config[Service::CAM::OuterRightCamera]);
|
||||
LogSetting("Camera_OuterRightFlip", values.camera_flip[Service::CAM::OuterRightCamera]);
|
||||
LogSetting("Camera_InnerName", values.camera_name[Service::CAM::InnerCamera]);
|
||||
LogSetting("Camera_InnerConfig", values.camera_config[Service::CAM::InnerCamera]);
|
||||
LogSetting("Camera_InnerFlip", values.camera_flip[Service::CAM::InnerCamera]);
|
||||
LogSetting("Camera_OuterLeftName", values.camera_name[Service::CAM::OuterLeftCamera]);
|
||||
LogSetting("Camera_OuterLeftConfig", values.camera_config[Service::CAM::OuterLeftCamera]);
|
||||
LogSetting("Camera_OuterLeftFlip", values.camera_flip[Service::CAM::OuterLeftCamera]);
|
||||
LogSetting("DataStorage_UseVirtualSd", values.use_virtual_sd);
|
||||
LogSetting("DataStorage_UseCustomStorage", values.use_custom_storage);
|
||||
if (values.use_custom_storage) {
|
||||
log_setting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
|
||||
log_setting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
|
||||
LogSetting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
|
||||
LogSetting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
|
||||
}
|
||||
log_setting("System_IsNew3ds", values.is_new_3ds);
|
||||
log_setting("System_RegionValue", values.region_value);
|
||||
log_setting("Debugging_UseGdbstub", values.use_gdbstub);
|
||||
log_setting("Debugging_GdbstubPort", values.gdbstub_port);
|
||||
LogSetting("System_IsNew3ds", values.is_new_3ds);
|
||||
LogSetting("System_RegionValue", values.region_value);
|
||||
LogSetting("Debugging_UseGdbstub", values.use_gdbstub);
|
||||
LogSetting("Debugging_GdbstubPort", values.gdbstub_port);
|
||||
}
|
||||
|
||||
void LoadProfile(int index) {
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
namespace Settings {
|
||||
|
||||
enum class GraphicsAPI { OpenGL = 0, OpenGLES = 1, Vulkan = 2 };
|
||||
|
||||
enum class InitClock {
|
||||
SystemTime = 0,
|
||||
FixedTime = 1,
|
||||
@ -163,13 +165,19 @@ struct Values {
|
||||
u64 init_time;
|
||||
|
||||
// Renderer
|
||||
bool use_gles;
|
||||
GraphicsAPI graphics_api;
|
||||
u16 physical_device;
|
||||
bool spirv_shader_gen;
|
||||
bool renderer_debug;
|
||||
bool dump_command_buffers;
|
||||
bool async_command_recording;
|
||||
bool use_hw_renderer;
|
||||
bool use_hw_shader;
|
||||
bool separable_shader;
|
||||
bool use_disk_shader_cache;
|
||||
bool shaders_accurate_mul;
|
||||
bool use_shader_jit;
|
||||
bool use_vsync_new;
|
||||
u16 resolution_factor;
|
||||
bool use_frame_limit_alternate;
|
||||
u16 frame_limit;
|
||||
@ -203,12 +211,11 @@ struct Values {
|
||||
bool filter_mode;
|
||||
std::string pp_shader_name;
|
||||
|
||||
// Custom textures
|
||||
bool dump_textures;
|
||||
bool custom_textures;
|
||||
bool preload_textures;
|
||||
|
||||
bool use_vsync_new;
|
||||
|
||||
// Audio
|
||||
bool enable_dsp_lle;
|
||||
bool enable_dsp_lle_multithread;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user