Compare commits

...

29 Commits

Author SHA1 Message Date
d42d094bc6 pica_core: Propogate vertex uniforms to geometry setup when not in exclusive mode 2024-01-24 04:40:31 +02:00
6cbdc73f53 boss: Fix debug assert when session is not initialized. (#7337) 2024-01-10 13:00:03 -08:00
81ee7ad893 boss: Add some missing result codes. (#7334) 2024-01-09 19:32:52 -08:00
2ce0a9e899 renderer_vulkan: Update to support MoltenVK 1.2.7 (#7335) 2024-01-09 11:33:47 -08:00
015e42be05 Port yuzu-emu/yuzu#7506 & yuzu-emu/yuzu#7861: "Fix yuzu-emu/yuzu#7502" & "yuzu: Mute audio when in background" (#7321) 2024-01-09 09:56:39 -08:00
57696b2c11 core: Persist plg:ldr state across resets without static state. (#7327) 2024-01-08 09:20:14 -08:00
c8c2beaeff misc: fix issues pointed out by msvc (#7316)
* do not move constant variables

* applet_manager: avoid possible use after move

* use constant references where pointed out by msvc

* extra_hid: initialize response

* ValidateSaveState: passing slot separately is not necessary

* common: mark HashCombine as nodiscard

* cityhash: remove use of using namespace std

* Prefix all size_t with std::

done automatically by executing regex replace `([^:0-9a-zA-Z_])size_t([^0-9a-zA-Z_])` -> `$1std::size_t$2`
based on 7d8f115

* shared_memory.cpp: fix log error format

* fix compiling with pch off
2024-01-07 12:37:42 -08:00
6069fac76d video_core: Fix crash when no debug context is provided. (#7324) 2024-01-07 10:29:43 -08:00
7bacb78ce3 boss: Add some missing property IDs and fix file enumeration. (#7322) 2024-01-07 09:38:41 -08:00
0165012ba4 core_timing: Allow configuring a fixed or random initial system tick value. (#7309)
* core_timing: Apply random base ticks value on startup.

* core: Maintain consistent base system ticks in TAS movies.

* frontend: Add setting to configure a fixed base system ticks value.
2024-01-07 09:38:02 -08:00
96aa1b3a08 memory: Fix order of checks in PhysicalToVirtualAddressForRasterizer. (#7328) 2024-01-06 22:49:32 -08:00
b2c740ee0e plg_ldr: Revert state back to static for now. (#7326) 2024-01-06 15:21:42 -08:00
bc352e8168 applet_manager: Fix checking if HLE applet exists. (#7325) 2024-01-06 15:21:35 -08:00
4f00eb20db add volume quicksetting with volume slider (#7307)
Co-authored-by: Jonas Gutenschwager <spam.saikai@googlemail.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
2024-01-06 10:30:22 -08:00
8b6a9b0dd8 dsp: Fix mask sizes in LoadComponent. (#7319) 2024-01-06 08:46:19 -08:00
62409f8139 kernel: Release thread resource limit in Thread::Stop (#7318)
* core: Config plg_ldr after its creation

* Also use service manager to retrieve the service

* thread: Release resource limit in Thread::Stop

* service: Undo plgldr change
2024-01-05 16:12:00 -08:00
0df72f3873 ir: Set ir:rst max sessions to 2. (#7317) 2024-01-05 14:21:30 -08:00
f2ee9baec7 core: Eliminate more uses of Core::System::GetInstance(). (#7313) 2024-01-05 12:07:28 -08:00
8e2037b3ff audio_core: Clean up AAC decoder infrastructure. (#7310) 2024-01-04 11:00:03 -08:00
c6bcbc02de frontend: Fix missing persistence for texture sampling setting. (#7305) 2024-01-02 12:05:22 -08:00
36db566428 qt: Add support for opening files directly on macOS. (#7304)
* Associate 3ds files with Citra in Info.plist

* qt: Add support for opening files directly on macOS.

---------

Co-authored-by: shinra-electric <50119606+shinra-electric@users.noreply.github.com>
2024-01-02 12:05:12 -08:00
9b147d3f9c framebuffer_layout.cpp mini refactor (#7300)
* framebuffer_layout.cpp: simplify FrameLayoutFromResolutionScale

- upright_screen seems to only be swapped width and height calculation, so it is replaced with std::swap
- Get rid of call to GetCardboardSettings, The FrameLayoutFromResolutionScale function is used for Screenshots and Video Dumping where we dont need 3D effects

* framebuffer_layout.cpp: Combine SideFrameLayout and MobileLandscapeFrameLayout into variants of LargeFrameLayout

* framebuffer_layout.{cpp,h}: rename maxRectangle to MaxRectangle, plus

minor documentation update

* clang-format
2024-01-02 00:52:03 -08:00
7dd9174d31 cheats: Use global cheat engine (#7291)
* cheats: Use global cheat engine

* cheats: Prevent wasted double-load of cheat file.

* android: Fix for cheat engine updates.

---------

Co-authored-by: GPUCode <geoster3d@gmail.com>
2024-01-01 12:49:08 -08:00
5a7f615da1 kernel: Update to use atmosphere macros and correct Result (#7242)
* kernel: Switch to atmosphere style macros

* code: Rename ResultCode to Result

* code: Result constants are lower case

* Address review comments

* core: Remove CASCADE_CODE

* R_TRY replaces completely

* core: Run clang format
2023-12-31 09:01:40 -08:00
811303ea54 kernel: Fix freeing shared memory with wrong region. (#7301) 2023-12-30 15:36:12 -08:00
5bcdcffd96 kernel: Add some missing state to process serialization. (#7295) 2023-12-28 08:25:46 -08:00
2bb7f89c30 video_core: Refactor GPU interface (#7272)
* video_core: Refactor GPU interface

* citra_qt: Better debug widget lifetime
2023-12-28 11:46:57 +01:00
602f4f60d8 boss: Implement some NsData header and read commands. (#7283)
* boss: Implement some NsData header and read commands.

Co-authored-by: Rokkubro <lachlanb03@gmail.com>

* boss: Move opening ext data to common function and improve logging.

---------

Co-authored-by: Rokkubro <lachlanb03@gmail.com>
2023-12-26 09:01:32 -08:00
3113ae6616 cfg: Only select preferred region once per instance. (#7284) 2023-12-26 09:01:16 -08:00
395 changed files with 8664 additions and 10123 deletions

View File

@ -121,7 +121,7 @@ function(download_moltenvk)
set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
if (NOT EXISTS ${MOLTENVK_DIR})
if (NOT EXISTS ${MOLTENVK_TAR})
file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/latest/download/MoltenVK-all.tar
file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/download/v1.2.7-rc1/MoltenVK-all.tar
${MOLTENVK_TAR} SHOW_PROGRESS)
endif()

View File

@ -26,16 +26,14 @@ set(HASH_FILES
"${VIDEO_CORE}/shader/generator/spv_fs_shader_gen.h"
"${VIDEO_CORE}/shader/shader.cpp"
"${VIDEO_CORE}/shader/shader.h"
"${VIDEO_CORE}/pica.cpp"
"${VIDEO_CORE}/pica.h"
"${VIDEO_CORE}/regs_framebuffer.h"
"${VIDEO_CORE}/regs_lighting.h"
"${VIDEO_CORE}/regs_pipeline.h"
"${VIDEO_CORE}/regs_rasterizer.h"
"${VIDEO_CORE}/regs_shader.h"
"${VIDEO_CORE}/regs_texturing.h"
"${VIDEO_CORE}/regs.cpp"
"${VIDEO_CORE}/regs.h"
"${VIDEO_CORE}/pica/regs_framebuffer.h"
"${VIDEO_CORE}/pica/regs_lighting.h"
"${VIDEO_CORE}/pica/regs_pipeline.h"
"${VIDEO_CORE}/pica/regs_rasterizer.h"
"${VIDEO_CORE}/pica/regs_shader.h"
"${VIDEO_CORE}/pica/regs_texturing.h"
"${VIDEO_CORE}/pica/regs_internal.cpp"
"${VIDEO_CORE}/pica/regs_internal.h"
)
set(COMBINED "")
foreach (F IN LISTS HASH_FILES)

View File

@ -26,6 +26,38 @@
<!-- Fixed -->
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>3ds</string>
<string>3dsx</string>
<string>cci</string>
<string>cxi</string>
<string>cia</string>
</array>
<key>CFBundleTypeName</key>
<string>Nintendo 3DS File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Default</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>elf</string>
<string>axf</string>
</array>
<key>CFBundleTypeName</key>
<string>Unix Executable and Linkable Format</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
</dict>
</array>
<key>NSCameraUsageDescription</key>
<string>This app requires camera access to emulate the 3DS&apos;s cameras.</string>
<key>NSMicrophoneUsageDescription</key>

View File

@ -12,18 +12,19 @@ QPushButton#GraphicsAPIStatusBarButton:hover {
border: 1px solid #76797C;
}
QPushButton#3DOptionStatusBarButton {
color: #A5A5A5;
font-weight: bold;
QPushButton#TogglableStatusBarButton {
color: #959595;
border: 1px solid transparent;
background-color: transparent;
padding: 0px 3px 0px 3px;
text-align: center;
min-width: 60px;
min-height: 20px;
}
QPushButton#3DOptionStatusBarButton:hover {
QPushButton#TogglableStatusBarButton:checked {
color: #00FF00;
}
QPushButton#TogglableStatusBarButton:hover {
border: 1px solid #76797C;
}

View File

@ -1,19 +1,3 @@
QPushButton#TogglableStatusBarButton {
color: #959595;
border: 1px solid transparent;
background-color: transparent;
padding: 0px 3px 0px 3px;
text-align: center;
}
QPushButton#TogglableStatusBarButton:checked {
color: palette(text);
}
QPushButton#TogglableStatusBarButton:hover {
border: 1px solid #76797C;
}
QPushButton#GraphicsAPIStatusBarButton {
color: #656565;
border: 1px solid transparent;
@ -26,6 +10,23 @@ QPushButton#GraphicsAPIStatusBarButton:hover {
border: 1px solid #76797C;
}
QPushButton#TogglableStatusBarButton {
min-width: 0px;
color: #656565;
border: 1px solid transparent;
background-color: transparent;
padding: 0px 3px 0px 3px;
text-align: center;
}
QPushButton#TogglableStatusBarButton:checked {
color: #00FF00;
}
QPushButton#TogglableStatusBarButton:hover {
border: 1px solid #76797C;
}
QToolTip {
border: 1px solid #76797C;
background-color: #5A7566;

View File

@ -395,9 +395,6 @@ if(USE_SYSTEM_VULKAN_HEADERS)
else()
target_include_directories(vulkan-headers SYSTEM INTERFACE ./vulkan-headers/include)
endif()
if (APPLE)
target_include_directories(vulkan-headers SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK)
endif()
# adrenotools
if (ANDROID AND "arm64" IN_LIST ARCHITECTURE)

File diff suppressed because it is too large Load Diff

View File

@ -7,25 +7,13 @@ package org.citra.citra_emu.features.cheats.model
import androidx.annotation.Keep
@Keep
class CheatEngine(titleId: Long) {
@Keep
private val mPointer: Long
init {
mPointer = initialize(titleId)
}
protected external fun finalize()
object CheatEngine {
external fun loadCheatFile(titleId: Long)
external fun saveCheatFile(titleId: Long)
external fun getCheats(): Array<Cheat>
external fun addCheat(cheat: Cheat?)
external fun removeCheat(index: Int)
external fun updateCheat(index: Int, newCheat: Cheat?)
external fun saveCheatFile()
companion object {
@JvmStatic
private external fun initialize(titleId: Long): Long
}
}

View File

@ -47,18 +47,19 @@ class CheatsViewModel : ViewModel() {
val detailsViewFocusChange get() = _detailsViewFocusChange.asStateFlow()
private val _detailsViewFocusChange = MutableStateFlow(false)
private var cheatEngine: CheatEngine? = null
private var titleId: Long = 0
lateinit var cheats: Array<Cheat>
private var cheatsNeedSaving = false
private var selectedCheatPosition = -1
fun initialize(titleId: Long) {
cheatEngine = CheatEngine(titleId)
fun initialize(titleId_: Long) {
titleId = titleId_;
load()
}
private fun load() {
cheats = cheatEngine!!.getCheats()
CheatEngine.loadCheatFile(titleId)
cheats = CheatEngine.getCheats()
for (i in cheats.indices) {
cheats[i].setEnabledChangedCallback {
cheatsNeedSaving = true
@ -69,7 +70,7 @@ class CheatsViewModel : ViewModel() {
fun saveIfNeeded() {
if (cheatsNeedSaving) {
cheatEngine!!.saveCheatFile()
CheatEngine.saveCheatFile(titleId)
cheatsNeedSaving = false
}
}
@ -107,7 +108,7 @@ class CheatsViewModel : ViewModel() {
_isAdding.value = false
_isEditing.value = false
val position = cheats.size
cheatEngine!!.addCheat(cheat)
CheatEngine.addCheat(cheat)
cheatsNeedSaving = true
load()
notifyCheatAdded(position)
@ -123,7 +124,7 @@ class CheatsViewModel : ViewModel() {
}
fun updateSelectedCheat(newCheat: Cheat?) {
cheatEngine!!.updateCheat(selectedCheatPosition, newCheat)
CheatEngine.updateCheat(selectedCheatPosition, newCheat)
cheatsNeedSaving = true
load()
notifyCheatUpdated(selectedCheatPosition)
@ -141,7 +142,7 @@ class CheatsViewModel : ViewModel() {
fun deleteSelectedCheat() {
val position = selectedCheatPosition
setSelectedCheat(null, -1)
cheatEngine!!.removeCheat(position)
CheatEngine.removeCheat(position)
cheatsNeedSaving = true
load()
notifyCheatDeleted(position)

View File

@ -15,24 +15,24 @@
extern "C" {
static Cheats::CheatEngine* GetPointer(JNIEnv* env, jobject obj) {
return reinterpret_cast<Cheats::CheatEngine*>(
env->GetLongField(obj, IDCache::GetCheatEnginePointer()));
static Cheats::CheatEngine& GetEngine() {
Core::System& system{Core::System::GetInstance()};
return system.CheatEngine();
}
JNIEXPORT jlong JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_initialize(
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_loadCheatFile(
JNIEnv* env, jclass, jlong title_id) {
return reinterpret_cast<jlong>(new Cheats::CheatEngine(title_id, Core::System::GetInstance()));
GetEngine().LoadCheatFile(title_id);
}
JNIEXPORT void JNICALL
Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_finalize(JNIEnv* env, jobject obj) {
delete GetPointer(env, obj);
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_saveCheatFile(
JNIEnv* env, jclass, jlong title_id) {
GetEngine().SaveCheatFile(title_id);
}
JNIEXPORT jobjectArray JNICALL
Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_getCheats(JNIEnv* env, jobject obj) {
auto cheats = GetPointer(env, obj)->GetCheats();
Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_getCheats(JNIEnv* env, jclass) {
auto cheats = GetEngine().GetCheats();
const jobjectArray array =
env->NewObjectArray(static_cast<jsize>(cheats.size()), IDCache::GetCheatClass(), nullptr);
@ -45,22 +45,19 @@ Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_getCheats(JNIEnv* en
}
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_addCheat(
JNIEnv* env, jobject obj, jobject j_cheat) {
GetPointer(env, obj)->AddCheat(*CheatFromJava(env, j_cheat));
JNIEnv* env, jclass, jobject j_cheat) {
auto cheat = *CheatFromJava(env, j_cheat);
GetEngine().AddCheat(std::move(cheat));
}
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_removeCheat(
JNIEnv* env, jobject obj, jint index) {
GetPointer(env, obj)->RemoveCheat(index);
JNIEnv* env, jclass, jint index) {
GetEngine().RemoveCheat(index);
}
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_updateCheat(
JNIEnv* env, jobject obj, jint index, jobject j_new_cheat) {
GetPointer(env, obj)->UpdateCheat(index, *CheatFromJava(env, j_new_cheat));
}
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_saveCheatFile(
JNIEnv* env, jobject obj) {
GetPointer(env, obj)->SaveCheatFile();
JNIEnv* env, jclass, jint index, jobject j_new_cheat) {
auto cheat = *CheatFromJava(env, j_new_cheat);
GetEngine().UpdateCheat(index, std::move(cheat));
}
}

View File

@ -146,6 +146,7 @@ void Config::ReadValues() {
ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
ReadSetting("Renderer", Settings::values.use_vsync_new);
ReadSetting("Renderer", Settings::values.texture_filter);
ReadSetting("Renderer", Settings::values.texture_sampling);
// Work around to map Android setting for enabling the frame limiter to the format Citra expects
if (sdl2_config->GetBoolean("Renderer", "use_frame_limit", true)) {
@ -214,6 +215,8 @@ void Config::ReadValues() {
} catch (...) {
}
}
ReadSetting("System", Settings::values.init_ticks_type);
ReadSetting("System", Settings::values.init_ticks_override);
ReadSetting("System", Settings::values.plugin_loader_enabled);
ReadSetting("System", Settings::values.allow_plugin_loader);

View File

@ -288,6 +288,14 @@ init_clock =
# Note: 3DS can only handle times later then Jan 1 2000
init_time =
# The system ticks count to use when citra starts
# 0: Random (default), 1: Fixed
init_ticks_type =
# Tick count to use when init_ticks_type is set to Fixed.
# Defaults to 0.
init_ticks_override =
# Plugin loader state, if enabled plugins will be loaded from the SD card.
# You can also set if homebrew apps are allowed to enable the plugin loader
plugin_loader =

View File

@ -15,7 +15,6 @@
#include "jni/input_manager.h"
#include "network/network.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
static bool IsPortraitMode() {
return JNI_FALSE != IDCache::GetEnvForThread()->CallStaticBooleanMethod(

View File

@ -7,6 +7,10 @@
#include <vector>
#include "core/frontend/emu_window.h"
namespace Core {
class System;
}
class EmuWindow_Android : public Frontend::EmuWindow {
public:
EmuWindow_Android(ANativeWindow* surface);

View File

@ -12,10 +12,11 @@
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/core.h"
#include "input_common/main.h"
#include "jni/emu_window/emu_window_gl.h"
#include "video_core/gpu.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
static constexpr std::array<EGLint, 15> egl_attribs{EGL_SURFACE_TYPE,
EGL_WINDOW_BIT,
@ -71,8 +72,8 @@ private:
EGLContext egl_context{};
};
EmuWindow_Android_OpenGL::EmuWindow_Android_OpenGL(ANativeWindow* surface)
: EmuWindow_Android{surface} {
EmuWindow_Android_OpenGL::EmuWindow_Android_OpenGL(Core::System& system_, ANativeWindow* surface)
: EmuWindow_Android{surface}, system{system_} {
if (egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); egl_display == EGL_NO_DISPLAY) {
LOG_CRITICAL(Frontend, "eglGetDisplay() failed");
return;
@ -199,6 +200,9 @@ void EmuWindow_Android_OpenGL::StopPresenting() {
}
void EmuWindow_Android_OpenGL::TryPresenting() {
if (!system.IsPoweredOn()) {
return;
}
if (presenting_state == PresentingState::Initial) [[unlikely]] {
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
@ -208,8 +212,6 @@ void EmuWindow_Android_OpenGL::TryPresenting() {
return;
}
eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0);
if (VideoCore::g_renderer) {
VideoCore::g_renderer->TryPresent(0);
eglSwapBuffers(egl_display, egl_surface);
}
system.GPU().Renderer().TryPresent(0);
eglSwapBuffers(egl_display, egl_surface);
}

View File

@ -11,11 +11,15 @@
#include "jni/emu_window/emu_window.h"
namespace Core {
class System;
}
struct ANativeWindow;
class EmuWindow_Android_OpenGL : public EmuWindow_Android {
public:
EmuWindow_Android_OpenGL(ANativeWindow* surface);
EmuWindow_Android_OpenGL(Core::System& system, ANativeWindow* surface);
~EmuWindow_Android_OpenGL() override = default;
void TryPresenting() override;
@ -30,6 +34,7 @@ private:
void DestroyContext() override;
private:
Core::System& system;
EGLConfig egl_config;
EGLSurface egl_surface{};
EGLContext egl_context{};

View File

@ -7,7 +7,6 @@
#include "common/logging/log.h"
#include "common/settings.h"
#include "jni/emu_window/emu_window_vk.h"
#include "video_core/video_core.h"
class GraphicsContext_Android final : public Frontend::GraphicsContext {
public:

View File

@ -81,8 +81,8 @@ jstring Java_org_citra_citra_1emu_model_GameInfo_getTitle(JNIEnv* env, jobject o
Loader::SMDH::TitleLanguage language = Loader::SMDH::TitleLanguage::English;
// Get the title from SMDH in UTF-16 format
std::u16string title{
reinterpret_cast<char16_t*>(smdh->titles[static_cast<size_t>(language)].long_title.data())};
std::u16string title{reinterpret_cast<char16_t*>(
smdh->titles[static_cast<std::size_t>(language)].long_title.data())};
return ToJString(env, Common::UTF16ToUTF8(title).data());
}
@ -93,8 +93,8 @@ jstring Java_org_citra_citra_1emu_model_GameInfo_getCompany(JNIEnv* env, jobject
// Get the Publisher's name from SMDH in UTF-16 format
char16_t* publisher;
publisher =
reinterpret_cast<char16_t*>(smdh->titles[static_cast<size_t>(language)].publisher.data());
publisher = reinterpret_cast<char16_t*>(
smdh->titles[static_cast<std::size_t>(language)].publisher.data());
return ToJString(env, Common::UTF16ToUTF8(publisher).data());
}

View File

@ -35,8 +35,6 @@ static jclass s_cheat_class;
static jfieldID s_cheat_pointer;
static jmethodID s_cheat_constructor;
static jfieldID s_cheat_engine_pointer;
static jfieldID s_game_info_pointer;
static jclass s_disk_cache_progress_class;
@ -116,10 +114,6 @@ jmethodID GetCheatConstructor() {
return s_cheat_constructor;
}
jfieldID GetCheatEnginePointer() {
return s_cheat_engine_pointer;
}
jfieldID GetGameInfoPointer() {
return s_game_info_pointer;
}
@ -195,12 +189,6 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
s_cheat_constructor = env->GetMethodID(cheat_class, "<init>", "(J)V");
env->DeleteLocalRef(cheat_class);
// Initialize CheatEngine
const jclass cheat_engine_class =
env->FindClass("org/citra/citra_emu/features/cheats/model/CheatEngine");
s_cheat_engine_pointer = env->GetFieldID(cheat_engine_class, "mPointer", "J");
env->DeleteLocalRef(cheat_engine_class);
// Initialize GameInfo
const jclass game_info_class = env->FindClass("org/citra/citra_emu/model/GameInfo");
s_game_info_pointer = env->GetFieldID(game_info_class, "pointer", "J");

View File

@ -35,8 +35,6 @@ jclass GetCheatClass();
jfieldID GetCheatPointer();
jmethodID GetCheatConstructor();
jfieldID GetCheatEnginePointer();
jfieldID GetGameInfoPointer();
jclass GetDiskCacheProgressClass();

View File

@ -51,8 +51,9 @@
#include "jni/id_cache.h"
#include "jni/input_manager.h"
#include "jni/ndk_motion.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/gpu.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
#if CITRA_ARCH(arm64)
#include <adrenotools/driver.h>
@ -126,7 +127,7 @@ static bool CheckMicPermission() {
static Core::System::ResultStatus RunCitra(const std::string& filepath) {
// Citra core only supports a single running instance
std::lock_guard<std::mutex> lock(running_mutex);
std::scoped_lock lock(running_mutex);
LOG_INFO(Frontend, "Citra starting...");
@ -137,10 +138,12 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
return Core::System::ResultStatus::ErrorLoader;
}
Core::System& system{Core::System::GetInstance()};
const auto graphics_api = Settings::values.graphics_api.GetValue();
switch (graphics_api) {
case Settings::GraphicsAPI::OpenGL:
window = std::make_unique<EmuWindow_Android_OpenGL>(s_surf);
window = std::make_unique<EmuWindow_Android_OpenGL>(system, s_surf);
break;
case Settings::GraphicsAPI::Vulkan:
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf, vulkan_library);
@ -150,8 +153,6 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf, vulkan_library);
}
Core::System& system{Core::System::GetInstance()};
// Forces a config reload on game boot, if the user changed settings in the UI
Config{};
// Replace with game-specific settings
@ -179,6 +180,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
// Register microphone permission check
system.RegisterMicPermissionCheck(&CheckMicPermission);
Pica::g_debug_context = Pica::DebugContext::Construct();
InputManager::Init();
window->MakeCurrent();
@ -196,7 +198,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
std::unique_ptr<Frontend::GraphicsContext> cpu_context;
system.Renderer().Rasterizer()->LoadDiskResources(stop_run, &LoadDiskCacheProgress);
system.GPU().Renderer().Rasterizer()->LoadDiskResources(stop_run, &LoadDiskCacheProgress);
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
@ -275,8 +277,10 @@ void Java_org_citra_citra_1emu_NativeLibrary_surfaceChanged(JNIEnv* env,
if (window) {
window->OnSurfaceChanged(s_surf);
}
if (VideoCore::g_renderer) {
VideoCore::g_renderer->NotifySurfaceChanged();
auto& system = Core::System::GetInstance();
if (system.IsPoweredOn()) {
system.GPU().Renderer().NotifySurfaceChanged();
}
LOG_INFO(Frontend, "Surface changed");
@ -311,8 +315,9 @@ void Java_org_citra_citra_1emu_NativeLibrary_notifyOrientationChange([[maybe_unu
jint layout_option,
jint rotation) {
Settings::values.layout_option = static_cast<Settings::LayoutOption>(layout_option);
if (VideoCore::g_renderer) {
VideoCore::g_renderer->UpdateCurrentFramebufferLayout(!(rotation % 2));
auto& system = Core::System::GetInstance();
if (system.IsPoweredOn()) {
system.GPU().Renderer().UpdateCurrentFramebufferLayout(!(rotation % 2));
}
InputManager::screen_rotation = rotation;
Camera::NDK::g_rotation = rotation;
@ -322,8 +327,9 @@ void Java_org_citra_citra_1emu_NativeLibrary_swapScreens([[maybe_unused]] JNIEnv
[[maybe_unused]] jobject obj,
jboolean swap_screens, jint rotation) {
Settings::values.swap_screen = swap_screens;
if (VideoCore::g_renderer) {
VideoCore::g_renderer->UpdateCurrentFramebufferLayout(!(rotation % 2));
auto& system = Core::System::GetInstance();
if (system.IsPoweredOn()) {
system.GPU().Renderer().UpdateCurrentFramebufferLayout(!(rotation % 2));
}
InputManager::screen_rotation = rotation;
Camera::NDK::g_rotation = rotation;
@ -655,8 +661,8 @@ void Java_org_citra_citra_1emu_NativeLibrary_removeAmiibo([[maybe_unused]] JNIEn
JNIEXPORT jobject JNICALL Java_org_citra_citra_1emu_utils_CiaInstallWorker_installCIA(
JNIEnv* env, jobject jobj, jstring jpath) {
std::string path = GetJString(env, jpath);
Service::AM::InstallStatus res =
Service::AM::InstallCIA(path, [env, jobj](size_t total_bytes_read, size_t file_size) {
Service::AM::InstallStatus res = Service::AM::InstallCIA(
path, [env, jobj](std::size_t total_bytes_read, std::size_t file_size) {
env->CallVoidMethod(jobj, IDCache::GetCiaInstallHelperSetProgress(),
static_cast<jint>(file_size), static_cast<jint>(total_bytes_read));
});

View File

@ -4,11 +4,11 @@ add_library(audio_core STATIC
codec.h
dsp_interface.cpp
dsp_interface.h
hle/aac_decoder.cpp
hle/aac_decoder.h
hle/common.h
hle/decoder.cpp
hle/decoder.h
hle/faad2_decoder.cpp
hle/faad2_decoder.h
hle/filter.cpp
hle/filter.h
hle/hle.cpp

View File

@ -3,30 +3,11 @@
// Refer to the license.txt file included.
#include <neaacdec.h>
#include "audio_core/hle/faad2_decoder.h"
#include "audio_core/hle/aac_decoder.h"
namespace AudioCore::HLE {
class FAAD2Decoder::Impl {
public:
explicit Impl(Memory::MemorySystem& memory);
~Impl();
std::optional<BinaryMessage> ProcessRequest(const BinaryMessage& request);
bool IsValid() const {
return decoder != nullptr;
}
private:
std::optional<BinaryMessage> Initalize(const BinaryMessage& request);
std::optional<BinaryMessage> Decode(const BinaryMessage& request);
Memory::MemorySystem& memory;
NeAACDecHandle decoder = nullptr;
};
FAAD2Decoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) {
AACDecoder::AACDecoder(Memory::MemorySystem& memory) : memory(memory) {
decoder = NeAACDecOpen();
if (decoder == nullptr) {
LOG_CRITICAL(Audio_DSP, "Could not open FAAD2 decoder.");
@ -46,7 +27,7 @@ FAAD2Decoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) {
LOG_INFO(Audio_DSP, "Created FAAD2 AAC decoder.");
}
FAAD2Decoder::Impl::~Impl() {
AACDecoder::~AACDecoder() {
if (decoder) {
NeAACDecClose(decoder);
decoder = nullptr;
@ -55,16 +36,23 @@ FAAD2Decoder::Impl::~Impl() {
}
}
std::optional<BinaryMessage> FAAD2Decoder::Impl::ProcessRequest(const BinaryMessage& request) {
BinaryMessage AACDecoder::ProcessRequest(const BinaryMessage& request) {
if (request.header.codec != DecoderCodec::DecodeAAC) {
LOG_ERROR(Audio_DSP, "FAAD2 AAC Decoder cannot handle such codec: {}",
LOG_ERROR(Audio_DSP, "AAC decoder received unsupported codec: {}",
static_cast<u16>(request.header.codec));
return {};
return {
.header =
{
.result = ResultStatus::Error,
},
};
}
switch (request.header.cmd) {
case DecoderCommand::Init: {
return Initalize(request);
BinaryMessage response = request;
response.header.result = ResultStatus::Success;
return response;
}
case DecoderCommand::EncodeDecode: {
return Decode(request);
@ -72,26 +60,25 @@ std::optional<BinaryMessage> FAAD2Decoder::Impl::ProcessRequest(const BinaryMess
case DecoderCommand::Shutdown:
case DecoderCommand::SaveState:
case DecoderCommand::LoadState: {
LOG_WARNING(Audio_DSP, "Got unimplemented binary request: {}",
LOG_WARNING(Audio_DSP, "Got unimplemented AAC binary request: {}",
static_cast<u16>(request.header.cmd));
BinaryMessage response = request;
response.header.result = ResultStatus::Success;
return response;
}
default:
LOG_ERROR(Audio_DSP, "Got unknown binary request: {}",
LOG_ERROR(Audio_DSP, "Got unknown AAC binary request: {}",
static_cast<u16>(request.header.cmd));
return {};
return {
.header =
{
.result = ResultStatus::Error,
},
};
}
}
std::optional<BinaryMessage> FAAD2Decoder::Impl::Initalize(const BinaryMessage& request) {
BinaryMessage response = request;
response.header.result = ResultStatus::Success;
return response;
}
std::optional<BinaryMessage> FAAD2Decoder::Impl::Decode(const BinaryMessage& request) {
BinaryMessage AACDecoder::Decode(const BinaryMessage& request) {
BinaryMessage response{};
response.header.codec = request.header.codec;
response.header.cmd = request.header.cmd;
@ -101,6 +88,10 @@ std::optional<BinaryMessage> FAAD2Decoder::Impl::Decode(const BinaryMessage& req
response.decode_aac_response.num_channels = 2;
response.decode_aac_response.num_samples = 1024;
if (decoder == nullptr) {
return response;
}
if (request.decode_aac_request.src_addr < Memory::FCRAM_PADDR ||
request.decode_aac_request.src_addr + request.decode_aac_request.size >
Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) {
@ -171,16 +162,4 @@ std::optional<BinaryMessage> FAAD2Decoder::Impl::Decode(const BinaryMessage& req
return response;
}
FAAD2Decoder::FAAD2Decoder(Memory::MemorySystem& memory) : impl(std::make_unique<Impl>(memory)) {}
FAAD2Decoder::~FAAD2Decoder() = default;
std::optional<BinaryMessage> FAAD2Decoder::ProcessRequest(const BinaryMessage& request) {
return impl->ProcessRequest(request);
}
bool FAAD2Decoder::IsValid() const {
return impl->IsValid();
}
} // namespace AudioCore::HLE

View File

@ -0,0 +1,26 @@
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "audio_core/hle/decoder.h"
namespace AudioCore::HLE {
using NeAACDecHandle = void*;
class AACDecoder final : public DecoderBase {
public:
explicit AACDecoder(Memory::MemorySystem& memory);
~AACDecoder() override;
BinaryMessage ProcessRequest(const BinaryMessage& request) override;
private:
BinaryMessage Decode(const BinaryMessage& request);
Memory::MemorySystem& memory;
NeAACDecHandle decoder = nullptr;
};
} // namespace AudioCore::HLE

View File

@ -32,34 +32,4 @@ DecoderSampleRate GetSampleRateEnum(u32 sample_rate) {
}
}
DecoderBase::~DecoderBase(){};
NullDecoder::NullDecoder() = default;
NullDecoder::~NullDecoder() = default;
std::optional<BinaryMessage> NullDecoder::ProcessRequest(const BinaryMessage& request) {
BinaryMessage response{};
switch (request.header.cmd) {
case DecoderCommand::Init:
case DecoderCommand::Shutdown:
case DecoderCommand::SaveState:
case DecoderCommand::LoadState:
response = request;
response.header.result = ResultStatus::Success;
return response;
case DecoderCommand::EncodeDecode:
response.header.codec = request.header.codec;
response.header.cmd = request.header.cmd;
response.header.result = ResultStatus::Success;
response.decode_aac_response.num_channels = 2; // Just assume stereo here
response.decode_aac_response.size = request.decode_aac_request.size;
response.decode_aac_response.num_samples = 1024; // Just assume 1024 here
return response;
default:
LOG_ERROR(Audio_DSP, "Got unknown binary request: {}",
static_cast<u16>(request.header.cmd));
return std::nullopt;
}
};
} // namespace AudioCore::HLE

View File

@ -135,21 +135,8 @@ enum_le<DecoderSampleRate> GetSampleRateEnum(u32 sample_rate);
class DecoderBase {
public:
virtual ~DecoderBase();
virtual std::optional<BinaryMessage> ProcessRequest(const BinaryMessage& request) = 0;
/// Return true if this Decoder can be loaded. Return false if the system cannot create the
/// decoder
virtual bool IsValid() const = 0;
};
class NullDecoder final : public DecoderBase {
public:
NullDecoder();
~NullDecoder() override;
std::optional<BinaryMessage> ProcessRequest(const BinaryMessage& request) override;
bool IsValid() const override {
return true;
}
virtual ~DecoderBase() = default;
virtual BinaryMessage ProcessRequest(const BinaryMessage& request) = 0;
};
} // namespace AudioCore::HLE

View File

@ -1,23 +0,0 @@
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "audio_core/hle/decoder.h"
namespace AudioCore::HLE {
class FAAD2Decoder final : public DecoderBase {
public:
explicit FAAD2Decoder(Memory::MemorySystem& memory);
~FAAD2Decoder() override;
std::optional<BinaryMessage> ProcessRequest(const BinaryMessage& request) override;
bool IsValid() const override;
private:
class Impl;
std::unique_ptr<Impl> impl;
};
} // namespace AudioCore::HLE

View File

@ -8,9 +8,9 @@
#include <boost/serialization/vector.hpp>
#include <boost/serialization/weak_ptr.hpp>
#include "audio_core/audio_types.h"
#include "audio_core/hle/aac_decoder.h"
#include "audio_core/hle/common.h"
#include "audio_core/hle/decoder.h"
#include "audio_core/hle/faad2_decoder.h"
#include "audio_core/hle/hle.h"
#include "audio_core/hle/mixers.h"
#include "audio_core/hle/shared_memory.h"
@ -24,16 +24,10 @@
#include "core/core.h"
#include "core/core_timing.h"
SERIALIZE_EXPORT_IMPL(AudioCore::DspHle)
using InterruptType = Service::DSP::InterruptType;
namespace AudioCore {
DspHle::DspHle()
: DspHle(Core::System::GetInstance(), Core::System::GetInstance().Memory(),
Core::System::GetInstance().CoreTiming()) {}
DspHle::DspHle(Core::System& system) : DspHle(system, system.Memory(), system.CoreTiming()) {}
template <class Archive>
@ -98,7 +92,7 @@ private:
Core::Timing& core_timing;
Core::TimingEventType* tick_event{};
std::unique_ptr<HLE::DecoderBase> decoder{};
std::unique_ptr<HLE::DecoderBase> aac_decoder{};
std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> interrupt_handler{};
@ -114,13 +108,6 @@ private:
friend class boost::serialization::access;
};
static std::vector<std::function<std::unique_ptr<HLE::DecoderBase>(Memory::MemorySystem&)>>
decoder_backends = {
[](Memory::MemorySystem& memory) -> std::unique_ptr<HLE::DecoderBase> {
return std::make_unique<HLE::FAAD2Decoder>(memory);
},
};
DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory, Core::Timing& timing)
: parent(parent_), core_timing(timing) {
dsp_memory.raw_memory.fill(0);
@ -129,19 +116,7 @@ DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory, Core::Timing&
source.SetMemory(memory);
}
for (auto& factory : decoder_backends) {
decoder = factory(memory);
if (decoder && decoder->IsValid()) {
break;
}
}
if (!decoder || !decoder->IsValid()) {
LOG_WARNING(Audio_DSP,
"Unable to load any decoders, this could cause missing audio in some games");
decoder = std::make_unique<HLE::NullDecoder>();
}
aac_decoder = std::make_unique<HLE::AACDecoder>(memory);
tick_event =
core_timing.RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) {
this->AudioTickCallback(cycles_late);
@ -291,12 +266,9 @@ void DspHle::Impl::PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) {
UNIMPLEMENTED();
return;
}
std::optional<HLE::BinaryMessage> response = decoder->ProcessRequest(request);
if (response) {
const HLE::BinaryMessage& value = *response;
pipe_data[static_cast<u32>(pipe_number)].resize(sizeof(value));
std::memcpy(pipe_data[static_cast<u32>(pipe_number)].data(), &value, sizeof(value));
}
const HLE::BinaryMessage response = aac_decoder->ProcessRequest(request);
pipe_data[static_cast<u32>(pipe_number)].resize(sizeof(response));
std::memcpy(pipe_data[static_cast<u32>(pipe_number)].data(), &response, sizeof(response));
interrupt_handler(InterruptType::Pipe, DspPipe::Binary);
break;

View File

@ -50,13 +50,9 @@ private:
friend struct Impl;
std::unique_ptr<Impl> impl;
DspHle();
template <class Archive>
void serialize(Archive& ar, const unsigned int);
friend class boost::serialization::access;
};
} // namespace AudioCore
BOOST_CLASS_EXPORT_KEY(AudioCore::DspHle)

View File

@ -24,8 +24,8 @@ namespace {
constexpr std::array input_details = {
#ifdef HAVE_CUBEB
InputDetails{InputType::Cubeb, "Real Device (Cubeb)", true,
[](std::string_view device_id) -> std::unique_ptr<Input> {
if (!Core::System::GetInstance().HasMicPermission()) {
[](Core::System& system, std::string_view device_id) -> std::unique_ptr<Input> {
if (!system.HasMicPermission()) {
LOG_WARNING(Audio,
"Microphone permission denied, falling back to null input.");
return std::make_unique<NullInput>();
@ -36,8 +36,8 @@ constexpr std::array input_details = {
#endif
#ifdef HAVE_OPENAL
InputDetails{InputType::OpenAL, "Real Device (OpenAL)", true,
[](std::string_view device_id) -> std::unique_ptr<Input> {
if (!Core::System::GetInstance().HasMicPermission()) {
[](Core::System& system, std::string_view device_id) -> std::unique_ptr<Input> {
if (!system.HasMicPermission()) {
LOG_WARNING(Audio,
"Microphone permission denied, falling back to null input.");
return std::make_unique<NullInput>();
@ -47,12 +47,12 @@ constexpr std::array input_details = {
&ListOpenALInputDevices},
#endif
InputDetails{InputType::Static, "Static Noise", false,
[](std::string_view device_id) -> std::unique_ptr<Input> {
[](Core::System& system, std::string_view device_id) -> std::unique_ptr<Input> {
return std::make_unique<StaticInput>();
},
[] { return std::vector<std::string>{"Static Noise"}; }},
InputDetails{InputType::Null, "None", false,
[](std::string_view device_id) -> std::unique_ptr<Input> {
[](Core::System& system, std::string_view device_id) -> std::unique_ptr<Input> {
return std::make_unique<NullInput>();
},
[] { return std::vector<std::string>{"None"}; }},

View File

@ -10,6 +10,10 @@
#include <vector>
#include "common/common_types.h"
namespace Core {
class System;
}
namespace AudioCore {
class Input;
@ -23,7 +27,7 @@ enum class InputType : u32 {
};
struct InputDetails {
using FactoryFn = std::unique_ptr<Input> (*)(std::string_view device_id);
using FactoryFn = std::unique_ptr<Input> (*)(Core::System& system, std::string_view device_id);
using ListDevicesFn = std::vector<std::string> (*)();
/// Type of this input.

View File

@ -148,7 +148,7 @@ ALsizei OpenALSink::Impl::Callback(void* impl_, void* buffer, ALsizei buffer_siz
return 0;
}
const size_t num_frames = buffer_size_in_bytes / (2 * sizeof(s16));
const std::size_t num_frames = buffer_size_in_bytes / (2 * sizeof(s16));
impl->cb(reinterpret_cast<s16*>(buffer), num_frames);
return buffer_size_in_bytes;

View File

@ -83,7 +83,7 @@ void SDL2Sink::Impl::Callback(void* impl_, u8* buffer, int buffer_size_in_bytes)
if (!impl || !impl->cb)
return;
const size_t num_frames = buffer_size_in_bytes / (2 * sizeof(s16));
const std::size_t num_frames = buffer_size_in_bytes / (2 * sizeof(s16));
impl->cb(reinterpret_cast<s16*>(buffer), num_frames);
}

View File

@ -36,6 +36,7 @@
#include "core/telemetry_session.h"
#include "input_common/main.h"
#include "network/network.h"
#include "video_core/gpu.h"
#include "video_core/renderer_base.h"
#ifdef __unix__
@ -438,9 +439,10 @@ int main(int argc, char** argv) {
movie.StartRecording(movie_record, movie_record_author);
}
if (!dump_video.empty() && DynamicLibrary::FFmpeg::LoadFFmpeg()) {
auto& renderer = system.GPU().Renderer();
const auto layout{
Layout::FrameLayoutFromResolutionScale(system.Renderer().GetResolutionScaleFactor())};
auto dumper = std::make_shared<VideoDumper::FFmpegBackend>();
Layout::FrameLayoutFromResolutionScale(renderer.GetResolutionScaleFactor())};
auto dumper = std::make_shared<VideoDumper::FFmpegBackend>(renderer);
if (dumper->StartDumping(dump_video, layout)) {
system.RegisterVideoDumper(dumper);
}
@ -458,7 +460,7 @@ int main(int argc, char** argv) {
});
std::atomic_bool stop_run;
system.Renderer().Rasterizer()->LoadDiskResources(
system.GPU().Renderer().Rasterizer()->LoadDiskResources(
stop_run, [](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
LOG_DEBUG(Frontend, "Loading stage {} progress {} {}", static_cast<u32>(stage), value,
total);

View File

@ -146,6 +146,7 @@ void Config::ReadValues() {
ReadSetting("Renderer", Settings::values.frame_limit);
ReadSetting("Renderer", Settings::values.use_vsync_new);
ReadSetting("Renderer", Settings::values.texture_filter);
ReadSetting("Renderer", Settings::values.texture_sampling);
ReadSetting("Renderer", Settings::values.mono_render_option);
ReadSetting("Renderer", Settings::values.render_3d);
@ -224,6 +225,8 @@ void Config::ReadValues() {
std::chrono::system_clock::from_time_t(std::mktime(&t)).time_since_epoch())
.count();
}
ReadSetting("System", Settings::values.init_ticks_type);
ReadSetting("System", Settings::values.init_ticks_override);
ReadSetting("System", Settings::values.plugin_loader_enabled);
ReadSetting("System", Settings::values.allow_plugin_loader);
@ -233,7 +236,7 @@ void Config::ReadValues() {
std::string offset_string =
sdl2_config->GetString("System", "init_time_offset", default_init_time_offset);
size_t sep_index = offset_string.find(' ');
std::size_t sep_index = offset_string.find(' ');
if (sep_index == std::string::npos) {
LOG_ERROR(Config, "Failed to parse init_time_offset. Using 0 00:00:00");

View File

@ -307,6 +307,14 @@ init_clock =
# Note: 3DS can only handle times later then Jan 1 2000
init_time =
# The system ticks count to use when citra starts
# 0: Random (default), 1: Fixed
init_ticks_type =
# Tick count to use when init_ticks_type is set to Fixed.
# Defaults to 0.
init_ticks_override =
[Camera]
# Which camera engine to use for the right outer camera
# blank (default): a dummy camera that always returns black image

View File

@ -11,8 +11,9 @@
#include "citra/emu_window/emu_window_sdl2_gl.h"
#include "common/scm_rev.h"
#include "common/settings.h"
#include "core/core.h"
#include "video_core/gpu.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
class SDLGLContext : public Frontend::GraphicsContext {
public:
@ -159,7 +160,7 @@ void EmuWindow_SDL2_GL::Present() {
SDL_GL_MakeCurrent(render_window, window_context);
SDL_GL_SetSwapInterval(1);
while (IsOpen()) {
VideoCore::g_renderer->TryPresent(100, is_secondary);
system.GPU().Renderer().TryPresent(100, is_secondary);
SDL_GL_SwapWindow(render_window);
}
SDL_GL_MakeCurrent(render_window, nullptr);

View File

@ -13,6 +13,7 @@
#include "common/settings.h"
#include "core/core.h"
#include "core/frontend/emu_window.h"
#include "video_core/gpu.h"
#include "video_core/renderer_software/renderer_software.h"
class DummyContext : public Frontend::GraphicsContext {};
@ -94,7 +95,7 @@ void EmuWindow_SDL2_SW::Present() {
}
SDL_Surface* EmuWindow_SDL2_SW::LoadFramebuffer(VideoCore::ScreenId screen_id) {
const auto& renderer = static_cast<SwRenderer::RendererSoftware&>(system.Renderer());
const auto& renderer = static_cast<SwRenderer::RendererSoftware&>(system.GPU().Renderer());
const auto& info = renderer.Screen(screen_id);
const int width = static_cast<int>(info.width);
const int height = static_cast<int>(info.height);

View File

@ -22,9 +22,9 @@
#include "input_common/main.h"
#include "input_common/motion_emu.h"
#include "video_core/custom_textures/custom_tex_manager.h"
#include "video_core/gpu.h"
#include "video_core/renderer_base.h"
#include "video_core/renderer_software/renderer_software.h"
#include "video_core/video_core.h"
#ifdef HAS_OPENGL
#include <glad/glad.h>
@ -73,7 +73,7 @@ void EmuThread::run() {
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
system.Renderer().Rasterizer()->LoadDiskResources(
system.GPU().Renderer().Rasterizer()->LoadDiskResources(
stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
emit LoadProgress(stage, value, total);
});
@ -284,9 +284,7 @@ public:
}
context->MakeCurrent();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
if (VideoCore::g_renderer) {
VideoCore::g_renderer->TryPresent(100, is_secondary);
}
system.GPU().Renderer().TryPresent(100, is_secondary);
context->SwapBuffers();
glFinish();
}
@ -367,7 +365,7 @@ struct SoftwareRenderWidget : public RenderWidget {
}
QImage LoadFramebuffer(VideoCore::ScreenId screen_id) {
const auto& renderer = static_cast<SwRenderer::RendererSoftware&>(system.Renderer());
const auto& renderer = static_cast<SwRenderer::RendererSoftware&>(system.GPU().Renderer());
const auto& info = renderer.Screen(screen_id);
const int width = static_cast<int>(info.width);
const int height = static_cast<int>(info.height);
@ -678,13 +676,14 @@ void GRenderWindow::ReleaseRenderTarget() {
}
void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) {
auto& renderer = system.GPU().Renderer();
if (res_scale == 0) {
res_scale = system.Renderer().GetResolutionScaleFactor();
res_scale = renderer.GetResolutionScaleFactor();
}
const auto layout{Layout::FrameLayoutFromResolutionScale(res_scale, is_secondary)};
screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32);
system.Renderer().RequestScreenshot(
renderer.RequestScreenshot(
screenshot_image.bits(),
[this, screenshot_path](bool invert_y) {
const std::string std_screenshot_path = screenshot_path.toStdString();

View File

@ -54,8 +54,11 @@ const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config:
// This must be in alphabetical order according to action name as it must have the same order as
// UISetting::values.shortcuts, which is alphabetically ordered.
// clang-format off
const std::array<UISettings::Shortcut, 28> Config::default_hotkeys {{
{QStringLiteral("Advance Frame"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::ApplicationShortcut}},
const std::array<UISettings::Shortcut, 30> Config::default_hotkeys {{
{QStringLiteral("Advance Frame"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::ApplicationShortcut}},
{QStringLiteral("Audio Mute/Unmute"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), Qt::WindowShortcut}},
{QStringLiteral("Audio Volume Down"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WindowShortcut}},
{QStringLiteral("Audio Volume Up"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WindowShortcut}},
{QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::WidgetWithChildrenShortcut}},
{QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), Qt::WindowShortcut}},
{QStringLiteral("Decrease 3D Factor"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+-"), Qt::ApplicationShortcut}},
@ -68,7 +71,6 @@ const std::array<UISettings::Shortcut, 28> Config::default_hotkeys {{
{QStringLiteral("Load Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F2"), Qt::WidgetWithChildrenShortcut}},
{QStringLiteral("Load File"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), Qt::WidgetWithChildrenShortcut}},
{QStringLiteral("Load from Newest Slot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+V"), Qt::WindowShortcut}},
{QStringLiteral("Mute Audio"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), Qt::WindowShortcut}},
{QStringLiteral("Remove Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F3"), Qt::ApplicationShortcut}},
{QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}},
{QStringLiteral("Rotate Screens Upright"), QStringLiteral("Main Window"), {QStringLiteral("F8"), Qt::WindowShortcut}},
@ -645,6 +647,7 @@ void Config::ReadRendererValues() {
ReadGlobalSetting(Settings::values.bg_blue);
ReadGlobalSetting(Settings::values.texture_filter);
ReadGlobalSetting(Settings::values.texture_sampling);
if (global) {
ReadBasicSetting(Settings::values.use_shader_jit);
@ -684,6 +687,8 @@ void Config::ReadSystemValues() {
ReadBasicSetting(Settings::values.init_clock);
ReadBasicSetting(Settings::values.init_time);
ReadBasicSetting(Settings::values.init_time_offset);
ReadBasicSetting(Settings::values.init_ticks_type);
ReadBasicSetting(Settings::values.init_ticks_override);
ReadBasicSetting(Settings::values.plugin_loader_enabled);
ReadBasicSetting(Settings::values.allow_plugin_loader);
}
@ -763,6 +768,7 @@ void Config::ReadUIValues() {
ReadBasicSetting(UISettings::values.callout_flags);
ReadBasicSetting(UISettings::values.show_console);
ReadBasicSetting(UISettings::values.pause_when_in_background);
ReadBasicSetting(UISettings::values.mute_when_in_background);
ReadBasicSetting(UISettings::values.hide_mouse);
}
@ -1130,6 +1136,7 @@ void Config::SaveRendererValues() {
WriteGlobalSetting(Settings::values.bg_blue);
WriteGlobalSetting(Settings::values.texture_filter);
WriteGlobalSetting(Settings::values.texture_sampling);
if (global) {
WriteSetting(QStringLiteral("use_shader_jit"), Settings::values.use_shader_jit.GetValue(),
@ -1169,6 +1176,8 @@ void Config::SaveSystemValues() {
WriteBasicSetting(Settings::values.init_clock);
WriteBasicSetting(Settings::values.init_time);
WriteBasicSetting(Settings::values.init_time_offset);
WriteBasicSetting(Settings::values.init_ticks_type);
WriteBasicSetting(Settings::values.init_ticks_override);
WriteBasicSetting(Settings::values.plugin_loader_enabled);
WriteBasicSetting(Settings::values.allow_plugin_loader);
}
@ -1231,6 +1240,7 @@ void Config::SaveUIValues() {
WriteBasicSetting(UISettings::values.callout_flags);
WriteBasicSetting(UISettings::values.show_console);
WriteBasicSetting(UISettings::values.pause_when_in_background);
WriteBasicSetting(UISettings::values.mute_when_in_background);
WriteBasicSetting(UISettings::values.hide_mouse);
}

View File

@ -26,7 +26,7 @@ public:
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs;
static const std::array<UISettings::Shortcut, 28> default_hotkeys;
static const std::array<UISettings::Shortcut, 30> default_hotkeys;
private:
void Initialize(const std::string& config_name);

View File

@ -11,8 +11,10 @@
#include "core/cheats/gateway_cheat.h"
#include "ui_configure_cheats.h"
ConfigureCheats::ConfigureCheats(Core::System& system, u64 title_id_, QWidget* parent)
: QWidget(parent), ui(std::make_unique<Ui::ConfigureCheats>()), title_id{title_id_} {
ConfigureCheats::ConfigureCheats(Cheats::CheatEngine& cheat_engine_, u64 title_id_, QWidget* parent)
: QWidget(parent),
ui(std::make_unique<Ui::ConfigureCheats>()), cheat_engine{cheat_engine_}, title_id{
title_id_} {
// Setup gui control settings
ui->setupUi(this);
ui->tableCheats->setColumnWidth(0, 30);
@ -34,15 +36,14 @@ ConfigureCheats::ConfigureCheats(Core::System& system, u64 title_id_, QWidget* p
[this] { SaveCheat(ui->tableCheats->currentRow()); });
connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureCheats::OnDeleteCheat);
cheat_engine = std::make_unique<Cheats::CheatEngine>(title_id, system);
cheat_engine.LoadCheatFile(title_id);
LoadCheats();
}
ConfigureCheats::~ConfigureCheats() = default;
void ConfigureCheats::LoadCheats() {
cheats = cheat_engine->GetCheats();
cheats = cheat_engine.GetCheats();
const int cheats_count = static_cast<int>(cheats.size());
ui->tableCheats->setRowCount(cheats_count);
@ -106,12 +107,12 @@ bool ConfigureCheats::SaveCheat(int row) {
ui->textNotes->toPlainText().toStdString());
if (newly_created) {
cheat_engine->AddCheat(cheat);
cheat_engine.AddCheat(std::move(cheat));
newly_created = false;
} else {
cheat_engine->UpdateCheat(row, cheat);
cheat_engine.UpdateCheat(row, std::move(cheat));
}
cheat_engine->SaveCheatFile();
cheat_engine.SaveCheatFile(title_id);
int previous_row = ui->tableCheats->currentRow();
int previous_col = ui->tableCheats->currentColumn();
@ -161,7 +162,7 @@ void ConfigureCheats::OnCheckChanged(int state) {
const QCheckBox* checkbox = qobject_cast<QCheckBox*>(sender());
int row = static_cast<int>(checkbox->property("row").toInt());
cheats[row]->SetEnabled(state);
cheat_engine->SaveCheatFile();
cheat_engine.SaveCheatFile(title_id);
}
void ConfigureCheats::OnTextEdited() {
@ -173,8 +174,8 @@ void ConfigureCheats::OnDeleteCheat() {
if (newly_created) {
newly_created = false;
} else {
cheat_engine->RemoveCheat(ui->tableCheats->currentRow());
cheat_engine->SaveCheatFile();
cheat_engine.RemoveCheat(ui->tableCheats->currentRow());
cheat_engine.SaveCheatFile(title_id);
}
LoadCheats();

View File

@ -5,6 +5,7 @@
#pragma once
#include <memory>
#include <span>
#include <QWidget>
#include "common/common_types.h"
@ -25,7 +26,8 @@ class ConfigureCheats : public QWidget {
Q_OBJECT
public:
explicit ConfigureCheats(Core::System& system, u64 title_id, QWidget* parent = nullptr);
explicit ConfigureCheats(Cheats::CheatEngine& cheat_engine, u64 title_id_,
QWidget* parent = nullptr);
~ConfigureCheats();
bool ApplyConfiguration();
@ -58,9 +60,9 @@ private slots:
private:
std::unique_ptr<Ui::ConfigureCheats> ui;
std::vector<std::shared_ptr<Cheats::CheatBase>> cheats;
Cheats::CheatEngine& cheat_engine;
std::span<const std::shared_ptr<Cheats::CheatBase>> cheats;
bool edited = false, newly_created = false;
int last_row = -1, last_col = -1;
u64 title_id;
std::unique_ptr<Cheats::CheatEngine> cheat_engine;
};

View File

@ -74,6 +74,8 @@ void ConfigureGeneral::SetConfiguration() {
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue());
ui->toggle_background_pause->setChecked(
UISettings::values.pause_when_in_background.GetValue());
ui->toggle_background_mute->setChecked(
UISettings::values.mute_when_in_background.GetValue());
ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
ui->toggle_update_check->setChecked(
@ -174,6 +176,7 @@ void ConfigureGeneral::ApplyConfiguration() {
if (Settings::IsConfiguringGlobal()) {
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked();
UISettings::values.mute_when_in_background = ui->toggle_background_mute->isChecked();
UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
UISettings::values.check_for_update_on_start = ui->toggle_update_check->isChecked();

View File

@ -36,6 +36,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_background_mute">
<property name="text">
<string>Mute audio when in background</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_hide_mouse">
<property name="text">

View File

@ -20,7 +20,6 @@ ConfigureGraphics::ConfigureGraphics(std::span<const QString> physical_devices,
ui->physical_device_combo->addItem(name);
}
ui->toggle_vsync_new->setEnabled(!is_powered_on);
ui->graphics_api_combo->setEnabled(!is_powered_on);
ui->physical_device_combo->setEnabled(!is_powered_on);
ui->toggle_async_shaders->setEnabled(!is_powered_on);

View File

@ -38,7 +38,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const QString
graphics_tab = std::make_unique<ConfigureGraphics>(physical_devices, is_powered_on, this);
system_tab = std::make_unique<ConfigureSystem>(system, this);
debug_tab = std::make_unique<ConfigureDebug>(is_powered_on, this);
cheat_tab = std::make_unique<ConfigureCheats>(system, title_id, this);
cheat_tab = std::make_unique<ConfigureCheats>(system.CheatEngine(), title_id, this);
ui->setupUi(this);

View File

@ -230,6 +230,8 @@ ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
&ConfigureSystem::UpdateBirthdayComboBox);
connect(ui->combo_init_clock, qOverload<int>(&QComboBox::currentIndexChanged), this,
&ConfigureSystem::UpdateInitTime);
connect(ui->combo_init_ticks_type, qOverload<int>(&QComboBox::currentIndexChanged), this,
&ConfigureSystem::UpdateInitTicks);
connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
&ConfigureSystem::RefreshConsoleID);
connect(ui->button_start_download, &QPushButton::clicked, this,
@ -293,6 +295,11 @@ void ConfigureSystem::SetConfiguration() {
QTime time = QTime::fromMSecsSinceStartOfDay(static_cast<int>(time_offset * 1000));
ui->edit_init_time_offset_time->setTime(time);
ui->combo_init_ticks_type->setCurrentIndex(
static_cast<u8>(Settings::values.init_ticks_type.GetValue()));
ui->edit_init_ticks_value->setText(
QString::number(Settings::values.init_ticks_override.GetValue()));
cfg = Service::CFG::GetModule(system);
ReadSystemSettings();
@ -413,6 +420,11 @@ void ConfigureSystem::ApplyConfiguration() {
static_cast<Settings::InitClock>(ui->combo_init_clock->currentIndex());
Settings::values.init_time = ui->edit_init_time->dateTime().toSecsSinceEpoch();
Settings::values.init_ticks_type =
static_cast<Settings::InitTicks>(ui->combo_init_ticks_type->currentIndex());
Settings::values.init_ticks_override =
static_cast<s64>(ui->edit_init_ticks_value->text().toLongLong());
s64 time_offset_time = ui->edit_init_time_offset_time->time().msecsSinceStartOfDay() / 1000;
s64 time_offset_days = ui->edit_init_time_offset_days->value() * 86400;
@ -462,6 +474,7 @@ void ConfigureSystem::ConfigureTime() {
SetConfiguration();
UpdateInitTime(ui->combo_init_clock->currentIndex());
UpdateInitTicks(ui->combo_init_ticks_type->currentIndex());
}
void ConfigureSystem::UpdateInitTime(int init_clock) {
@ -477,6 +490,15 @@ void ConfigureSystem::UpdateInitTime(int init_clock) {
ui->edit_init_time_offset_time->setVisible(!is_fixed_time && is_global);
}
void ConfigureSystem::UpdateInitTicks(int init_ticks_type) {
const bool is_global = Settings::IsConfiguringGlobal();
const bool is_fixed =
static_cast<Settings::InitTicks>(init_ticks_type) == Settings::InitTicks::Fixed;
ui->label_init_ticks_value->setVisible(is_fixed && is_global);
ui->edit_init_ticks_value->setVisible(is_fixed && is_global);
}
void ConfigureSystem::RefreshConsoleID() {
QMessageBox::StandardButton reply;
QString warning_text = tr("This will replace your current virtual 3DS with a new one. "
@ -512,6 +534,8 @@ void ConfigureSystem::SetupPerGameUI() {
ui->label_birthday->setVisible(false);
ui->label_init_clock->setVisible(false);
ui->label_init_time->setVisible(false);
ui->label_init_ticks_type->setVisible(false);
ui->label_init_ticks_value->setVisible(false);
ui->label_console_id->setVisible(false);
ui->label_sound->setVisible(false);
ui->label_language->setVisible(false);
@ -522,12 +546,14 @@ void ConfigureSystem::SetupPerGameUI() {
ui->combo_birthday->setVisible(false);
ui->combo_birthmonth->setVisible(false);
ui->combo_init_clock->setVisible(false);
ui->combo_init_ticks_type->setVisible(false);
ui->combo_sound->setVisible(false);
ui->combo_language->setVisible(false);
ui->combo_country->setVisible(false);
ui->label_init_time_offset->setVisible(false);
ui->edit_init_time_offset_days->setVisible(false);
ui->edit_init_time_offset_time->setVisible(false);
ui->edit_init_ticks_value->setVisible(false);
ui->toggle_system_setup->setVisible(false);
ui->button_regenerate_console_id->setVisible(false);
// Apps can change the state of the plugin loader, so plugins load

View File

@ -43,6 +43,7 @@ private:
void UpdateBirthdayComboBox(int birthmonth_index);
void UpdateInitTime(int init_clock);
void UpdateInitTicks(int init_ticks_type);
void RefreshConsoleID();
void SetupPerGameUI();

View File

@ -304,34 +304,75 @@
</layout>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_init_ticks_type">
<property name="text">
<string>Initial System Ticks</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QComboBox" name="combo_init_ticks_type">
<item>
<property name="text">
<string>Random</string>
</property>
</item>
<item>
<property name="text">
<string>Fixed</string>
</property>
</item>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_init_ticks_value">
<property name="text">
<string>Initial System Ticks Override</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLineEdit" name="edit_init_ticks_value">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maxLength">
<number>20</number>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_play_coins">
<property name="text">
<string>Play Coins:</string>
</property>
</widget>
</item>
<item row="9" column="1">
<item row="11" column="1">
<widget class="QSpinBox" name="spinBox_play_coins">
<property name="maximum">
<number>300</number>
</property>
</widget>
</item>
<item row="10" column="1">
<item row="12" column="1">
<widget class="QCheckBox" name="toggle_system_setup">
<property name="text">
<string>Run System Setup when Home Menu is launched</string>
</property>
</widget>
</item>
<item row="11" column="0">
<item row="13" column="0">
<widget class="QLabel" name="label_console_id">
<property name="text">
<string>Console ID:</string>
</property>
</widget>
</item>
<item row="11" column="1">
<item row="13" column="1">
<widget class="QPushButton" name="button_regenerate_console_id">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@ -347,35 +388,35 @@
</property>
</widget>
</item>
<item row="12" column="0">
<item row="14" column="0">
<widget class="QLabel" name="label_plugin_loader">
<property name="text">
<string>3GX Plugin Loader:</string>
</property>
</widget>
</item>
<item row="12" column="1">
<item row="14" column="1">
<widget class="QCheckBox" name="plugin_loader">
<property name="text">
<string>Enable 3GX plugin loader</string>
</property>
</widget>
</item>
<item row="13" column="1">
<item row="15" column="1">
<widget class="QCheckBox" name="allow_plugin_loader">
<property name="text">
<string>Allow games to change plugin loader state</string>
</property>
</widget>
</item>
<item row="14" column="0">
<item row="16" column="0">
<widget class="QLabel" name="label_nus_download">
<property name="text">
<string>Download System Files from Nitendo servers</string>
</property>
</widget>
</item>
<item row="14" column="1">
<item row="16" column="1">
<widget class="QWidget" name="body_nus_download">
<layout class="QHBoxLayout" name="horizontalLayout_nus_download">
<item>

View File

@ -5,8 +5,8 @@
#include <QListView>
#include "citra_qt/debugger/graphics/graphics.h"
#include "citra_qt/util/util.h"
extern GraphicsDebugger g_debugger;
#include "core/core.h"
#include "video_core/gpu.h"
GPUCommandStreamItemModel::GPUCommandStreamItemModel(QObject* parent)
: QAbstractListModel(parent), command_count(0) {
@ -19,19 +19,19 @@ int GPUCommandStreamItemModel::rowCount([[maybe_unused]] const QModelIndex& pare
}
QVariant GPUCommandStreamItemModel::data(const QModelIndex& index, int role) const {
if (!index.isValid())
if (!index.isValid() || !GetDebugger())
return QVariant();
int command_index = index.row();
const Service::GSP::Command& command = GetDebugger()->ReadGXCommandHistory(command_index);
if (role == Qt::DisplayRole) {
std::map<Service::GSP::CommandId, const char*> command_names = {
{Service::GSP::CommandId::REQUEST_DMA, "REQUEST_DMA"},
{Service::GSP::CommandId::SUBMIT_GPU_CMDLIST, "SUBMIT_GPU_CMDLIST"},
{Service::GSP::CommandId::SET_MEMORY_FILL, "SET_MEMORY_FILL"},
{Service::GSP::CommandId::SET_DISPLAY_TRANSFER, "SET_DISPLAY_TRANSFER"},
{Service::GSP::CommandId::SET_TEXTURE_COPY, "SET_TEXTURE_COPY"},
{Service::GSP::CommandId::CACHE_FLUSH, "CACHE_FLUSH"},
{Service::GSP::CommandId::RequestDma, "REQUEST_DMA"},
{Service::GSP::CommandId::SubmitCmdList, "SUBMIT_GPU_CMDLIST"},
{Service::GSP::CommandId::MemoryFill, "SET_MEMORY_FILL"},
{Service::GSP::CommandId::DisplayTransfer, "SET_DISPLAY_TRANSFER"},
{Service::GSP::CommandId::TextureCopy, "SET_TEXTURE_COPY"},
{Service::GSP::CommandId::CacheFlush, "CACHE_FLUSH"},
};
const u32* command_data = reinterpret_cast<const u32*>(&command);
QString str = QStringLiteral("%1 %2 %3 %4 %5 %6 %7 %8 %9")
@ -63,8 +63,8 @@ void GPUCommandStreamItemModel::OnGXCommandFinishedInternal(int total_command_co
emit dataChanged(index(prev_command_count, 0), index(total_command_count - 1, 0));
}
GPUCommandStreamWidget::GPUCommandStreamWidget(QWidget* parent)
: QDockWidget(tr("Graphics Debugger"), parent), model(this) {
GPUCommandStreamWidget::GPUCommandStreamWidget(Core::System& system_, QWidget* parent)
: QDockWidget(tr("Graphics Debugger"), parent), system{system_}, model(this) {
setObjectName(QStringLiteral("GraphicsDebugger"));
auto* command_list = new QListView;
@ -74,12 +74,26 @@ GPUCommandStreamWidget::GPUCommandStreamWidget(QWidget* parent)
setWidget(command_list);
}
void GPUCommandStreamWidget::Register() {
auto& debugger = system.GPU().Debugger();
debugger.RegisterObserver(&model);
}
void GPUCommandStreamWidget::Unregister() {
auto& debugger = system.GPU().Debugger();
debugger.UnregisterObserver(&model);
}
void GPUCommandStreamWidget::showEvent(QShowEvent* event) {
g_debugger.RegisterObserver(&model);
if (system.IsPoweredOn()) {
Register();
}
QDockWidget::showEvent(event);
}
void GPUCommandStreamWidget::hideEvent(QHideEvent* event) {
g_debugger.UnregisterObserver(&model);
if (system.IsPoweredOn()) {
Unregister();
}
QDockWidget::hideEvent(event);
}

View File

@ -8,8 +8,12 @@
#include <QDockWidget>
#include "video_core/gpu_debugger.h"
namespace Core {
class System;
}
class GPUCommandStreamItemModel : public QAbstractListModel,
public GraphicsDebugger::DebuggerObserver {
public VideoCore::GraphicsDebugger::DebuggerObserver {
Q_OBJECT
public:
@ -35,12 +39,16 @@ class GPUCommandStreamWidget : public QDockWidget {
Q_OBJECT
public:
GPUCommandStreamWidget(QWidget* parent = nullptr);
GPUCommandStreamWidget(Core::System& system, QWidget* parent = nullptr);
void Register();
void Unregister();
protected:
void showEvent(QShowEvent* event) override;
void hideEvent(QHideEvent* event) override;
private:
Core::System& system;
GPUCommandStreamItemModel model;
};

View File

@ -18,7 +18,8 @@ BreakPointObserverDock::BreakPointObserverDock(std::shared_ptr<Pica::DebugContex
&BreakPointObserverDock::OnBreakPointHit, Qt::BlockingQueuedConnection);
}
void BreakPointObserverDock::OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) {
void BreakPointObserverDock::OnPicaBreakPointHit(Pica::DebugContext::Event event,
const void* data) {
emit BreakPointHit(event, data);
}

View File

@ -20,14 +20,14 @@ public:
BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context, const QString& title,
QWidget* parent = nullptr);
void OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) override;
void OnPicaBreakPointHit(Pica::DebugContext::Event event, const void* data) override;
void OnPicaResume() override;
signals:
void Resumed();
void BreakPointHit(Pica::DebugContext::Event event, void* data);
void BreakPointHit(Pica::DebugContext::Event event, const void* data);
private:
virtual void OnBreakPointHit(Pica::DebugContext::Event event, void* data) = 0;
virtual void OnBreakPointHit(Pica::DebugContext::Event event, const void* data) = 0;
virtual void OnResumed() = 0;
};

View File

@ -191,12 +191,12 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(
setWidget(main_widget);
}
void GraphicsBreakPointsWidget::OnPicaBreakPointHit(Event event, void* data) {
void GraphicsBreakPointsWidget::OnPicaBreakPointHit(Event event, const void* data) {
// Process in GUI thread
emit BreakPointHit(event, data);
}
void GraphicsBreakPointsWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) {
void GraphicsBreakPointsWidget::OnBreakPointHit(Pica::DebugContext::Event event, const void* data) {
status_text->setText(tr("Emulation halted at breakpoint"));
resume_button->setEnabled(true);
}

View File

@ -23,16 +23,16 @@ public:
explicit GraphicsBreakPointsWidget(std::shared_ptr<Pica::DebugContext> debug_context,
QWidget* parent = nullptr);
void OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) override;
void OnPicaBreakPointHit(Pica::DebugContext::Event event, const void* data) override;
void OnPicaResume() override;
signals:
void Resumed();
void BreakPointHit(Pica::DebugContext::Event event, void* data);
void BreakPointHit(Pica::DebugContext::Event event, const void* data);
void BreakPointsChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
private:
void OnBreakPointHit(Pica::DebugContext::Event event, void* data);
void OnBreakPointHit(Pica::DebugContext::Event event, const void* data);
void OnItemDoubleClicked(const QModelIndex&);
void OnResumeRequested();
void OnResumed();

View File

@ -19,8 +19,8 @@
#include "core/core.h"
#include "core/memory.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/pica_state.h"
#include "video_core/regs.h"
#include "video_core/gpu.h"
#include "video_core/pica/pica_core.h"
#include "video_core/texture/texture_decode.h"
namespace {
@ -73,7 +73,7 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const {
if (role == Qt::DisplayRole) {
switch (index.column()) {
case 0:
return QString::fromLatin1(Pica::Regs::GetRegisterName(write.cmd_id));
return QString::fromLatin1(Pica::RegsInternal::GetRegisterName(write.cmd_id));
case 1:
return QStringLiteral("%1").arg(write.cmd_id, 3, 16, QLatin1Char('0'));
case 2:
@ -119,8 +119,7 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&
}
#define COMMAND_IN_RANGE(cmd_id, reg_name) \
(cmd_id >= PICA_REG_INDEX(reg_name) && \
cmd_id < PICA_REG_INDEX(reg_name) + sizeof(decltype(Pica::g_state.regs.reg_name)) / 4)
(cmd_id >= PICA_REG_INDEX(reg_name) && cmd_id <= PICA_REG_INDEX(reg_name))
void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
const unsigned int command_id =
@ -147,13 +146,13 @@ void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
QWidget* new_info_widget = nullptr;
const unsigned int command_id =
const u32 command_id =
list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt();
if (COMMAND_IN_RANGE(command_id, texturing.texture0) ||
COMMAND_IN_RANGE(command_id, texturing.texture1) ||
COMMAND_IN_RANGE(command_id, texturing.texture2)) {
unsigned texture_index;
u32 texture_index;
if (COMMAND_IN_RANGE(command_id, texturing.texture0)) {
texture_index = 0;
} else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) {
@ -162,7 +161,8 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
texture_index = 2;
}
const auto texture = Pica::g_state.regs.texturing.GetTextures()[texture_index];
auto& pica = system.GPU().PicaCore();
const auto texture = pica.regs.internal.texturing.GetTextures()[texture_index];
const auto config = texture.config;
const auto format = texture.format;

View File

@ -15,10 +15,10 @@
#include "citra_qt/debugger/graphics/graphics_surface.h"
#include "citra_qt/util/spinbox.h"
#include "common/color.h"
#include "core/core.h"
#include "core/memory.h"
#include "video_core/pica_state.h"
#include "video_core/regs_framebuffer.h"
#include "video_core/regs_texturing.h"
#include "video_core/gpu.h"
#include "video_core/pica/pica_core.h"
#include "video_core/texture/texture_decode.h"
#include "video_core/utils.h"
@ -49,10 +49,10 @@ void SurfacePicture::mouseMoveEvent(QMouseEvent* event) {
mousePressEvent(event);
}
GraphicsSurfaceWidget::GraphicsSurfaceWidget(Memory::MemorySystem& memory_,
GraphicsSurfaceWidget::GraphicsSurfaceWidget(Core::System& system_,
std::shared_ptr<Pica::DebugContext> debug_context,
QWidget* parent)
: BreakPointObserverDock(debug_context, tr("Pica Surface Viewer"), parent), memory{memory_},
: BreakPointObserverDock(debug_context, tr("Pica Surface Viewer"), parent), system{system_},
surface_source(Source::ColorBuffer) {
setObjectName(QStringLiteral("PicaSurface"));
@ -214,7 +214,7 @@ GraphicsSurfaceWidget::GraphicsSurfaceWidget(Memory::MemorySystem& memory_,
}
}
void GraphicsSurfaceWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) {
void GraphicsSurfaceWidget::OnBreakPointHit(Pica::DebugContext::Event event, const void* data) {
emit Update();
widget()->setEnabled(true);
}
@ -289,7 +289,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
return;
}
const u8* buffer = memory.GetPhysicalPointer(surface_address);
const u8* buffer = system.Memory().GetPhysicalPointer(surface_address);
if (!buffer) {
surface_info_label->setText(tr("(unable to access pixel data)"));
surface_info_label->setAlignment(Qt::AlignCenter);
@ -410,13 +410,13 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
void GraphicsSurfaceWidget::OnUpdate() {
QPixmap pixmap;
const auto& regs = system.GPU().PicaCore().regs.internal;
switch (surface_source) {
case Source::ColorBuffer: {
// TODO: Store a reference to the registers in the debug context instead of accessing them
// directly...
const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer;
const auto& framebuffer = regs.framebuffer.framebuffer;
surface_address = framebuffer.GetColorBufferPhysicalAddress();
surface_width = framebuffer.GetWidth();
surface_height = framebuffer.GetHeight();
@ -451,8 +451,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
}
case Source::DepthBuffer: {
const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer;
const auto& framebuffer = regs.framebuffer.framebuffer;
surface_address = framebuffer.GetDepthBufferPhysicalAddress();
surface_width = framebuffer.GetWidth();
surface_height = framebuffer.GetHeight();
@ -479,8 +478,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
}
case Source::StencilBuffer: {
const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer;
const auto& framebuffer = regs.framebuffer.framebuffer;
surface_address = framebuffer.GetDepthBufferPhysicalAddress();
surface_width = framebuffer.GetWidth();
surface_height = framebuffer.GetHeight();
@ -513,7 +511,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
break;
}
const auto texture = Pica::g_state.regs.texturing.GetTextures()[texture_index];
const auto texture = regs.texturing.GetTextures()[texture_index];
auto info = Pica::Texture::TextureInfo::FromPicaRegister(texture.config, texture.format);
surface_address = info.physical_address;
@ -545,7 +543,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
// TODO: Implement a good way to visualize alpha components!
QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32);
const u8* buffer = memory.GetPhysicalPointer(surface_address);
const u8* buffer = system.Memory().GetPhysicalPointer(surface_address);
if (!buffer) {
surface_picture_label->hide();
@ -681,7 +679,7 @@ void GraphicsSurfaceWidget::SaveSurface() {
tr("Failed to save surface data to file '%1'").arg(filename));
}
} else if (selected_filter == bin_filter) {
const u8* const buffer = memory.GetPhysicalPointer(surface_address);
const u8* const buffer = system.Memory().GetPhysicalPointer(surface_address);
ASSERT_MSG(buffer, "Memory not accessible");
QFile file{filename};

View File

@ -14,8 +14,8 @@ class CSpinBox;
class GraphicsSurfaceWidget;
namespace Memory {
class MemorySystem;
namespace Core {
class System;
}
class SurfacePicture : public QLabel {
@ -76,7 +76,7 @@ class GraphicsSurfaceWidget : public BreakPointObserverDock {
static unsigned int NibblesPerPixel(Format format);
public:
explicit GraphicsSurfaceWidget(Memory::MemorySystem& memory,
explicit GraphicsSurfaceWidget(Core::System& system,
std::shared_ptr<Pica::DebugContext> debug_context,
QWidget* parent = nullptr);
void Pick(int x, int y);
@ -95,12 +95,12 @@ signals:
void Update();
private:
void OnBreakPointHit(Pica::DebugContext::Event event, void* data) override;
void OnBreakPointHit(Pica::DebugContext::Event event, const void* data) override;
void OnResumed() override;
void SaveSurface();
Memory::MemorySystem& memory;
Core::System& system;
QComboBox* surface_source_list;
CSpinBox* surface_address_control;
QSpinBox* surface_width_control;

View File

@ -14,14 +14,15 @@
#include <nihstro/float24.h>
#include "citra_qt/debugger/graphics/graphics_tracing.h"
#include "common/common_types.h"
#include "core/hw/gpu.h"
#include "core/hw/lcd.h"
#include "core/core.h"
#include "core/tracer/recorder.h"
#include "video_core/pica_state.h"
#include "video_core/gpu.h"
#include "video_core/pica/pica_core.h"
GraphicsTracingWidget::GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context,
GraphicsTracingWidget::GraphicsTracingWidget(Core::System& system_,
std::shared_ptr<Pica::DebugContext> debug_context,
QWidget* parent)
: BreakPointObserverDock(debug_context, tr("CiTrace Recorder"), parent) {
: BreakPointObserverDock(debug_context, tr("CiTrace Recorder"), parent), system{system_} {
setObjectName(QStringLiteral("CiTracing"));
@ -61,45 +62,46 @@ void GraphicsTracingWidget::StartRecording() {
if (!context)
return;
auto shader_binary = Pica::g_state.vs.program_code;
auto swizzle_data = Pica::g_state.vs.swizzle_data;
auto& pica = system.GPU().PicaCore();
auto shader_binary = pica.vs_setup.program_code;
auto swizzle_data = pica.vs_setup.swizzle_data;
// Encode floating point numbers to 24-bit values
// TODO: Drop this explicit conversion once we store float24 values bit-correctly internally.
std::array<u32, 4 * 16> default_attributes;
for (unsigned i = 0; i < 16; ++i) {
for (unsigned comp = 0; comp < 3; ++comp) {
default_attributes[4 * i + comp] = nihstro::to_float24(
Pica::g_state.input_default_attributes.attr[i][comp].ToFloat32());
for (u32 i = 0; i < 16; ++i) {
for (u32 comp = 0; comp < 3; ++comp) {
default_attributes[4 * i + comp] =
nihstro::to_float24(pica.input_default_attributes[i][comp].ToFloat32());
}
}
std::array<u32, 4 * 96> vs_float_uniforms;
for (unsigned i = 0; i < 96; ++i)
for (unsigned comp = 0; comp < 3; ++comp)
for (u32 i = 0; i < 96; ++i) {
for (u32 comp = 0; comp < 3; ++comp) {
vs_float_uniforms[4 * i + comp] =
nihstro::to_float24(Pica::g_state.vs.uniforms.f[i][comp].ToFloat32());
nihstro::to_float24(pica.vs_setup.uniforms.f[i][comp].ToFloat32());
}
}
CiTrace::Recorder::InitialState state;
std::copy_n((u32*)&GPU::g_regs, sizeof(GPU::g_regs) / sizeof(u32),
std::back_inserter(state.gpu_registers));
std::copy_n((u32*)&LCD::g_regs, sizeof(LCD::g_regs) / sizeof(u32),
std::back_inserter(state.lcd_registers));
std::copy_n((u32*)&Pica::g_state.regs, sizeof(Pica::g_state.regs) / sizeof(u32),
std::back_inserter(state.pica_registers));
std::copy(default_attributes.begin(), default_attributes.end(),
std::back_inserter(state.default_attributes));
std::copy(shader_binary.begin(), shader_binary.end(),
std::back_inserter(state.vs_program_binary));
std::copy(swizzle_data.begin(), swizzle_data.end(), std::back_inserter(state.vs_swizzle_data));
std::copy(vs_float_uniforms.begin(), vs_float_uniforms.end(),
std::back_inserter(state.vs_float_uniforms));
// boost::copy(TODO: Not implemented, std::back_inserter(state.gs_program_binary));
// boost::copy(TODO: Not implemented, std::back_inserter(state.gs_swizzle_data));
// boost::copy(TODO: Not implemented, std::back_inserter(state.gs_float_uniforms));
auto recorder = new CiTrace::Recorder(state);
context->recorder = std::shared_ptr<CiTrace::Recorder>(recorder);
const auto copy = [&](std::vector<u32>& dest, auto& data) {
dest.resize(sizeof(data));
std::memcpy(dest.data(), std::addressof(data), sizeof(data));
};
copy(state.pica_registers, pica.regs);
copy(state.lcd_registers, pica.regs_lcd);
copy(state.default_attributes, default_attributes);
copy(state.vs_program_binary, shader_binary);
copy(state.vs_swizzle_data, swizzle_data);
copy(state.vs_float_uniforms, vs_float_uniforms);
// copy(TODO: Not implemented, std::back_inserter(state.gs_program_binary));
// copy(TODO: Not implemented, std::back_inserter(state.gs_swizzle_data));
// copy(TODO: Not implemented, std::back_inserter(state.gs_float_uniforms));
context->recorder = std::make_shared<CiTrace::Recorder>(state);
emit SetStartTracingButtonEnabled(false);
emit SetStopTracingButtonEnabled(true);
@ -139,7 +141,7 @@ void GraphicsTracingWidget::AbortRecording() {
emit SetStartTracingButtonEnabled(true);
}
void GraphicsTracingWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) {
void GraphicsTracingWidget::OnBreakPointHit(Pica::DebugContext::Event event, const void* data) {
widget()->setEnabled(true);
}

View File

@ -6,13 +6,18 @@
#include "citra_qt/debugger/graphics/graphics_breakpoint_observer.h"
namespace Core {
class System;
}
class EmuThread;
class GraphicsTracingWidget : public BreakPointObserverDock {
Q_OBJECT
public:
explicit GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context,
explicit GraphicsTracingWidget(Core::System& system,
std::shared_ptr<Pica::DebugContext> debug_context,
QWidget* parent = nullptr);
void OnEmulationStarting(EmuThread* emu_thread);
@ -23,11 +28,14 @@ private slots:
void StopRecording();
void AbortRecording();
void OnBreakPointHit(Pica::DebugContext::Event event, void* data) override;
void OnBreakPointHit(Pica::DebugContext::Event event, const void* data) override;
void OnResumed() override;
signals:
void SetStartTracingButtonEnabled(bool enable);
void SetStopTracingButtonEnabled(bool enable);
void SetAbortTracingButtonEnabled(bool enable);
private:
Core::System& system;
};

View File

@ -16,9 +16,9 @@
#include <QTreeView>
#include "citra_qt/debugger/graphics/graphics_vertex_shader.h"
#include "citra_qt/util/util.h"
#include "video_core/pica_state.h"
#include "video_core/shader/debug_data.h"
#include "video_core/shader/shader.h"
#include "core/core.h"
#include "video_core/gpu.h"
#include "video_core/pica/pica_core.h"
#include "video_core/shader/shader_interpreter.h"
using nihstro::Instruction;
@ -352,16 +352,14 @@ void GraphicsVertexShaderWidget::DumpShader() {
return;
}
auto& setup = Pica::g_state.vs;
auto& config = Pica::g_state.regs.vs;
Pica::DebugUtils::DumpShader(filename.toStdString(), config, setup,
Pica::g_state.regs.rasterizer.vs_output_attributes);
auto& pica = system.GPU().PicaCore();
Pica::DebugUtils::DumpShader(filename.toStdString(), pica.regs.internal.vs, pica.vs_setup,
pica.regs.internal.rasterizer.vs_output_attributes);
}
GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(
std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent)
: BreakPointObserverDock(debug_context, tr("Pica Vertex Shader"), parent) {
Core::System& system_, std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent)
: BreakPointObserverDock(debug_context, tr("Pica Vertex Shader"), parent), system{system_} {
setObjectName(QStringLiteral("PicaVertexShader"));
// Clear input vertex data so that it contains valid float values in case a debug shader
@ -472,7 +470,8 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(
widget()->setEnabled(false);
}
void GraphicsVertexShaderWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) {
void GraphicsVertexShaderWidget::OnBreakPointHit(Pica::DebugContext::Event event,
const void* data) {
if (event == Pica::DebugContext::Event::VertexShaderInvocation) {
Reload(true, data);
} else {
@ -482,7 +481,7 @@ void GraphicsVertexShaderWidget::OnBreakPointHit(Pica::DebugContext::Event event
widget()->setEnabled(true);
}
void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_data) {
void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, const void* vertex_data) {
model->beginResetModel();
if (replace_vertex_data) {
@ -491,7 +490,7 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
for (unsigned attr = 0; attr < 16; ++attr) {
for (unsigned comp = 0; comp < 4; ++comp) {
input_data[4 * attr + comp]->setText(
QStringLiteral("%1").arg(input_vertex.attr[attr][comp].ToFloat32()));
QStringLiteral("%1").arg(input_vertex[attr][comp].ToFloat32()));
}
}
breakpoint_warning->hide();
@ -508,28 +507,27 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
// Reload shader code
info.Clear();
auto& shader_setup = Pica::g_state.vs;
auto& shader_config = Pica::g_state.regs.vs;
for (auto instr : shader_setup.program_code)
auto& pica = system.GPU().PicaCore();
for (auto instr : pica.vs_setup.program_code)
info.code.push_back({instr});
int num_attributes = shader_config.max_input_attribute_index + 1;
int num_attributes = pica.regs.internal.vs.max_input_attribute_index + 1;
for (auto pattern : shader_setup.swizzle_data) {
for (auto pattern : pica.vs_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;
u32 entry_point = pica.regs.internal.vs.main_offset;
info.labels.insert({entry_point, "main"});
// Generate debug information
Pica::Shader::InterpreterEngine shader_engine;
shader_engine.SetupBatch(shader_setup, entry_point);
debug_data = shader_engine.ProduceDebugInfo(shader_setup, input_vertex, shader_config);
shader_engine.SetupBatch(pica.vs_setup, entry_point);
debug_data = shader_engine.ProduceDebugInfo(pica.vs_setup, input_vertex, pica.regs.internal.vs);
// Reload widget state
for (int attr = 0; attr < num_attributes; ++attr) {
unsigned source_attr = shader_config.GetRegisterForAttribute(attr);
unsigned source_attr = pica.regs.internal.vs.GetRegisterForAttribute(attr);
input_data_mapping[attr]->setText(QStringLiteral("-> v%1").arg(source_attr));
input_data_container[attr]->setVisible(true);
}
@ -551,7 +549,7 @@ void GraphicsVertexShaderWidget::OnResumed() {
void GraphicsVertexShaderWidget::OnInputAttributeChanged(int index) {
const f32 value = input_data[index]->text().toFloat();
input_vertex.attr[index / 4][index % 4] = Pica::f24::FromFloat32(value);
input_vertex[index / 4][index % 4] = Pica::f24::FromFloat32(value);
// Re-execute shader with updated value
Reload();
}

View File

@ -8,8 +8,12 @@
#include <QTreeView>
#include <nihstro/parser_shbin.h>
#include "citra_qt/debugger/graphics/graphics_breakpoint_observer.h"
#include "video_core/pica/output_vertex.h"
#include "video_core/shader/debug_data.h"
#include "video_core/shader/shader.h"
namespace Core {
class System;
}
class QLabel;
class QSpinBox;
@ -40,11 +44,12 @@ class GraphicsVertexShaderWidget : public BreakPointObserverDock {
using Event = Pica::DebugContext::Event;
public:
GraphicsVertexShaderWidget(std::shared_ptr<Pica::DebugContext> debug_context,
GraphicsVertexShaderWidget(Core::System& system,
std::shared_ptr<Pica::DebugContext> debug_context,
QWidget* parent = nullptr);
private slots:
void OnBreakPointHit(Pica::DebugContext::Event event, void* data) override;
void OnBreakPointHit(Pica::DebugContext::Event event, const void* data) override;
void OnResumed() override;
void OnInputAttributeChanged(int index);
@ -60,9 +65,10 @@ private slots:
* specify that no valid vertex data can be retrieved currently. Only used if
* replace_vertex_data is true.
*/
void Reload(bool replace_vertex_data = false, void* vertex_data = nullptr);
void Reload(bool replace_vertex_data = false, const void* vertex_data = nullptr);
private:
Core::System& system;
QLabel* instruction_description;
QTreeView* binary_list;
GraphicsVertexShaderModel* model;
@ -83,7 +89,7 @@ private:
nihstro::ShaderInfo info;
Pica::Shader::DebugData<true> debug_data;
Pica::Shader::AttributeBuffer input_vertex;
Pica::AttributeBuffer input_vertex;
friend class GraphicsVertexShaderModel;
};

View File

@ -49,7 +49,7 @@ QString IPCRecorderWidget::GetStatusStr(const IPCDebugger::RequestRecord& record
case IPCDebugger::RequestStatus::Handling:
return tr("Handling");
case IPCDebugger::RequestStatus::Handled:
if (record.translated_reply_cmdbuf[1] == RESULT_SUCCESS.raw) {
if (record.translated_reply_cmdbuf[1] == ResultSuccess.raw) {
return tr("Success");
}
return tr("Error");
@ -88,7 +88,7 @@ void IPCRecorderWidget::OnEntryUpdated(IPCDebugger::RequestRecord record) {
if (record.status == IPCDebugger::RequestStatus::HLEUnimplemented ||
(record.status == IPCDebugger::RequestStatus::Handled &&
record.translated_reply_cmdbuf[1] != RESULT_SUCCESS.raw)) { // Unimplemented / Error
record.translated_reply_cmdbuf[1] != ResultSuccess.raw)) { // Unimplemented / Error
auto item = ui->main->invisibleRootItem()->child(row_id);
for (int column = 0; column < item->columnCount(); ++column) {

View File

@ -74,7 +74,6 @@
#include "common/logging/backend.h"
#include "common/logging/log.h"
#include "common/memory_detect.h"
#include "common/microprofile.h"
#include "common/scm_rev.h"
#include "common/scope_exit.h"
#if CITRA_ARCH(x86_64)
@ -96,8 +95,8 @@
#include "input_common/main.h"
#include "network/network_settings.h"
#include "ui_main.h"
#include "video_core/gpu.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
#ifdef __APPLE__
#include "common/apple_authorization.h"
@ -230,6 +229,7 @@ GMainWindow::GMainWindow(Core::System& system_)
SetDefaultUIGeometry();
RestoreUIState();
ConnectAppEvents();
ConnectMenuEvents();
ConnectWidgetEvents();
@ -420,6 +420,38 @@ void GMainWindow::InitializeWidgets() {
statusBar()->insertPermanentWidget(0, graphics_api_button);
volume_popup = new QWidget(this);
volume_popup->setWindowFlags(Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint | Qt::Popup);
volume_popup->setLayout(new QVBoxLayout());
volume_popup->setMinimumWidth(200);
volume_slider = new QSlider(Qt::Horizontal);
volume_slider->setObjectName(QStringLiteral("volume_slider"));
volume_slider->setMaximum(100);
volume_slider->setPageStep(5);
connect(volume_slider, &QSlider::valueChanged, this, [this](int percentage) {
Settings::values.audio_muted = false;
const auto value = static_cast<float>(percentage) / volume_slider->maximum();
Settings::values.volume.SetValue(value);
UpdateVolumeUI();
});
volume_popup->layout()->addWidget(volume_slider);
volume_button = new QPushButton();
volume_button->setObjectName(QStringLiteral("TogglableStatusBarButton"));
volume_button->setFocusPolicy(Qt::NoFocus);
volume_button->setCheckable(true);
UpdateVolumeUI();
connect(volume_button, &QPushButton::clicked, this, [&] {
UpdateVolumeUI();
volume_popup->setVisible(!volume_popup->isVisible());
QRect rect = volume_button->geometry();
QPoint bottomLeft = statusBar()->mapToGlobal(rect.topLeft());
bottomLeft.setY(bottomLeft.y() - volume_popup->geometry().height());
volume_popup->setGeometry(QRect(bottomLeft, QSize(rect.width(), rect.height())));
});
statusBar()->insertPermanentWidget(1, volume_button);
statusBar()->addPermanentWidget(multiplayer_state->GetStatusText());
statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon());
@ -458,7 +490,7 @@ void GMainWindow::InitializeDebugWidgets() {
connect(this, &GMainWindow::EmulationStopping, registersWidget,
&RegistersWidget::OnEmulationStopping);
graphicsWidget = new GPUCommandStreamWidget(this);
graphicsWidget = new GPUCommandStreamWidget(system, this);
addDockWidget(Qt::RightDockWidgetArea, graphicsWidget);
graphicsWidget->hide();
debug_menu->addAction(graphicsWidget->toggleViewAction());
@ -473,12 +505,13 @@ void GMainWindow::InitializeDebugWidgets() {
graphicsBreakpointsWidget->hide();
debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction());
graphicsVertexShaderWidget = new GraphicsVertexShaderWidget(Pica::g_debug_context, this);
graphicsVertexShaderWidget =
new GraphicsVertexShaderWidget(system, Pica::g_debug_context, this);
addDockWidget(Qt::RightDockWidgetArea, graphicsVertexShaderWidget);
graphicsVertexShaderWidget->hide();
debug_menu->addAction(graphicsVertexShaderWidget->toggleViewAction());
graphicsTracingWidget = new GraphicsTracingWidget(Pica::g_debug_context, this);
graphicsTracingWidget = new GraphicsTracingWidget(system, Pica::g_debug_context, this);
addDockWidget(Qt::RightDockWidgetArea, graphicsTracingWidget);
graphicsTracingWidget->hide();
debug_menu->addAction(graphicsTracingWidget->toggleViewAction());
@ -671,8 +704,10 @@ void GMainWindow::InitializeHotkeys() {
}
UpdateStatusBar();
});
connect_shortcut(QStringLiteral("Mute Audio"),
[] { Settings::values.audio_muted = !Settings::values.audio_muted; });
connect_shortcut(QStringLiteral("Audio Mute/Unmute"), &GMainWindow::OnMute);
connect_shortcut(QStringLiteral("Audio Volume Down"), &GMainWindow::OnDecreaseVolume);
connect_shortcut(QStringLiteral("Audio Volume Up"), &GMainWindow::OnIncreaseVolume);
// We use "static" here in order to avoid capturing by lambda due to a MSVC bug, which makes the
// variable hold a garbage value after this function exits
@ -743,22 +778,49 @@ void GMainWindow::RestoreUIState() {
}
void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
if (!UISettings::values.pause_when_in_background) {
return;
}
if (state != Qt::ApplicationHidden && state != Qt::ApplicationInactive &&
state != Qt::ApplicationActive) {
LOG_DEBUG(Frontend, "ApplicationState unusual flag: {} ", state);
}
if (ui->action_Pause->isEnabled() &&
(state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
auto_paused = true;
OnPauseGame();
} else if (emulation_running && !emu_thread->IsRunning() && auto_paused &&
state == Qt::ApplicationActive) {
auto_paused = false;
OnStartGame();
if (!emulation_running) {
return;
}
if (UISettings::values.pause_when_in_background) {
if (emu_thread->IsRunning() &&
(state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
auto_paused = true;
OnPauseGame();
} else if (!emu_thread->IsRunning() && auto_paused && state == Qt::ApplicationActive) {
auto_paused = false;
OnStartGame();
}
}
if (UISettings::values.mute_when_in_background) {
if (!Settings::values.audio_muted &&
(state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
Settings::values.audio_muted = true;
auto_muted = true;
} else if (auto_muted && state == Qt::ApplicationActive) {
Settings::values.audio_muted = false;
auto_muted = false;
}
UpdateVolumeUI();
}
}
bool GApplicationEventFilter::eventFilter(QObject* object, QEvent* event) {
if (event->type() == QEvent::FileOpen) {
emit FileOpen(static_cast<QFileOpenEvent*>(event));
return true;
}
return false;
}
void GMainWindow::ConnectAppEvents() {
const auto filter = new GApplicationEventFilter();
QGuiApplication::instance()->installEventFilter(filter);
connect(filter, &GApplicationEventFilter::FileOpen, this, &GMainWindow::OnFileOpen);
}
void GMainWindow::ConnectWidgetEvents() {
@ -1237,6 +1299,11 @@ void GMainWindow::BootGame(const QString& filename) {
video_dumping_path.clear();
}
// Register debug widgets
if (graphicsWidget->isVisible()) {
graphicsWidget->Register();
}
// Create and start the emulation thread
emu_thread = std::make_unique<EmuThread>(system, *render_window);
emit EmulationStarting(emu_thread.get());
@ -1315,6 +1382,11 @@ void GMainWindow::ShutdownGame() {
// TODO(bunnei): This function is not thread safe, but it's being used as if it were
Pica::g_debug_context->ClearBreakpoints();
// Unregister debug widgets
if (graphicsWidget->isVisible()) {
graphicsWidget->Unregister();
}
// Frame advancing must be cancelled in order to release the emu thread from waiting
system.frame_limiter.SetFrameAdvancing(false);
@ -1848,7 +1920,7 @@ void GMainWindow::OnStartGame() {
#endif
UpdateSaveStates();
UpdateAPIIndicator();
UpdateStatusButtons();
}
void GMainWindow::OnRestartGame() {
@ -1885,7 +1957,7 @@ void GMainWindow::OnStopGame() {
ShutdownGame();
graphics_api_button->setEnabled(true);
Settings::RestoreGlobalState(false);
UpdateAPIIndicator();
UpdateStatusButtons();
}
void GMainWindow::OnLoadComplete() {
@ -2126,7 +2198,7 @@ void GMainWindow::OnConfigure() {
}
UpdateSecondaryWindowVisibility();
UpdateBootHomeMenuState();
UpdateAPIIndicator();
UpdateStatusButtons();
} else {
Settings::values.input_profiles = old_input_profiles;
Settings::values.touch_from_button_maps = old_touch_from_button_maps;
@ -2214,7 +2286,7 @@ void GMainWindow::OnToggleFilterBar() {
void GMainWindow::OnCreateGraphicsSurfaceViewer() {
auto graphicsSurfaceViewerWidget =
new GraphicsSurfaceWidget(system.Memory(), Pica::g_debug_context, this);
new GraphicsSurfaceWidget(system, Pica::g_debug_context, this);
addDockWidget(Qt::RightDockWidgetArea, graphicsSurfaceViewerWidget);
// TODO: Maybe graphicsSurfaceViewerWidget->setFloating(true);
graphicsSurfaceViewerWidget->show();
@ -2434,10 +2506,10 @@ void GMainWindow::OnStartVideoDumping() {
}
void GMainWindow::StartVideoDumping(const QString& path) {
Layout::FramebufferLayout layout{
Layout::FrameLayoutFromResolutionScale(VideoCore::g_renderer->GetResolutionScaleFactor())};
auto& renderer = system.GPU().Renderer();
const auto layout{Layout::FrameLayoutFromResolutionScale(renderer.GetResolutionScaleFactor())};
auto dumper = std::make_shared<VideoDumper::FFmpegBackend>();
auto dumper = std::make_shared<VideoDumper::FFmpegBackend>(renderer);
if (dumper->StartDumping(path.toStdString(), layout)) {
system.RegisterVideoDumper(dumper);
} else {
@ -2556,6 +2628,57 @@ void GMainWindow::ShowMouseCursor() {
}
}
void GMainWindow::OnMute() {
Settings::values.audio_muted = !Settings::values.audio_muted;
UpdateVolumeUI();
}
void GMainWindow::OnDecreaseVolume() {
Settings::values.audio_muted = false;
const auto current_volume =
static_cast<s32>(Settings::values.volume.GetValue() * volume_slider->maximum());
int step = 5;
if (current_volume <= 30) {
step = 2;
}
if (current_volume <= 6) {
step = 1;
}
const auto value =
static_cast<float>(std::max(current_volume - step, 0)) / volume_slider->maximum();
Settings::values.volume.SetValue(value);
UpdateVolumeUI();
}
void GMainWindow::OnIncreaseVolume() {
Settings::values.audio_muted = false;
const auto current_volume =
static_cast<s32>(Settings::values.volume.GetValue() * volume_slider->maximum());
int step = 5;
if (current_volume < 30) {
step = 2;
}
if (current_volume < 6) {
step = 1;
}
const auto value = static_cast<float>(current_volume + step) / volume_slider->maximum();
Settings::values.volume.SetValue(value);
UpdateVolumeUI();
}
void GMainWindow::UpdateVolumeUI() {
const auto volume_value =
static_cast<int>(Settings::values.volume.GetValue() * volume_slider->maximum());
volume_slider->setValue(volume_value);
if (Settings::values.audio_muted) {
volume_button->setChecked(false);
volume_button->setText(tr("VOLUME: MUTE"));
} else {
volume_button->setChecked(true);
volume_button->setText(tr("VOLUME: %1%", "Volume percentage (e.g. 50%)").arg(volume_value));
}
}
void GMainWindow::UpdateAPIIndicator(bool update) {
static std::array graphics_apis = {QStringLiteral("SOFTWARE"), QStringLiteral("OPENGL"),
QStringLiteral("VULKAN")};
@ -2576,6 +2699,11 @@ void GMainWindow::UpdateAPIIndicator(bool update) {
graphics_api_button->setStyleSheet(style_sheet);
}
void GMainWindow::UpdateStatusButtons() {
UpdateAPIIndicator();
UpdateVolumeUI();
}
void GMainWindow::OnMouseActivity() {
ShowMouseCursor();
}
@ -2742,6 +2870,10 @@ bool GMainWindow::DropAction(QDropEvent* event) {
return true;
}
void GMainWindow::OnFileOpen(const QFileOpenEvent* event) {
BootGame(event->file());
}
void GMainWindow::dropEvent(QDropEvent* event) {
DropAction(event);
}
@ -2873,6 +3005,8 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const QString& file_nam
if (!is_powered_on) {
config->Save();
}
UpdateStatusButtons();
}
void GMainWindow::OnMoviePlaybackCompleted() {

View File

@ -41,6 +41,7 @@ class LoadingScreen;
class MicroProfileDialog;
class MultiplayerState;
class ProfilerWidget;
class QFileOpenEvent;
template <typename>
class QFutureWatcher;
class QLabel;
@ -96,6 +97,8 @@ public:
bool DropAction(QDropEvent* event);
void AcceptDropEvent(QDropEvent* event);
void OnFileOpen(const QFileOpenEvent* event);
void UninstallTitles(
const std::vector<std::tuple<Service::FS::MediaType, u64, QString>>& titles);
@ -137,6 +140,7 @@ private:
void SyncMenuUISettings();
void RestoreUIState();
void ConnectAppEvents();
void ConnectWidgetEvents();
void ConnectMenuEvents();
void UpdateMenuState();
@ -263,6 +267,10 @@ private slots:
void OnLanguageChanged(const QString& locale);
void OnMouseActivity();
void OnDecreaseVolume();
void OnIncreaseVolume();
void OnMute();
private:
Q_INVOKABLE void OnMoviePlaybackCompleted();
void UpdateStatusBar();
@ -275,7 +283,9 @@ private:
void HideMouseCursor();
void ShowMouseCursor();
void OpenPerGameConfiguration(u64 title_id, const QString& file_name);
void UpdateVolumeUI();
void UpdateAPIIndicator(bool update = false);
void UpdateStatusButtons();
#ifdef __unix__
void SetGamemodeEnabled(bool state);
#endif
@ -297,6 +307,9 @@ private:
QLabel* game_fps_label = nullptr;
QLabel* emu_frametime_label = nullptr;
QPushButton* graphics_api_button = nullptr;
QPushButton* volume_button = nullptr;
QWidget* volume_popup = nullptr;
QSlider* volume_slider = nullptr;
QTimer status_bar_update_timer;
bool message_label_used_for_movie = false;
@ -312,6 +325,7 @@ private:
QString game_path;
bool auto_paused = false;
bool auto_muted = false;
QTimer mouse_hide_timer;
// Movie
@ -382,5 +396,15 @@ protected:
void mouseReleaseEvent(QMouseEvent* event) override;
};
class GApplicationEventFilter : public QObject {
Q_OBJECT
signals:
void FileOpen(const QFileOpenEvent* event);
protected:
bool eventFilter(QObject* object, QEvent* event) override;
};
Q_DECLARE_METATYPE(std::size_t);
Q_DECLARE_METATYPE(Service::AM::InstallStatus);

View File

@ -25,7 +25,7 @@ bool QtImageInterface::DecodePNG(std::vector<u8>& dst, u32& width, u32& height,
image = image.convertToFormat(QImage::Format_RGBA8888);
// Write RGBA8 to vector
const size_t image_size = width * height * 4;
const std::size_t image_size = width * height * 4;
dst.resize(image_size);
std::memcpy(dst.data(), image.constBits(), image_size);

View File

@ -80,6 +80,7 @@ struct Values {
Settings::Setting<bool> save_state_warning{true, "saveStateWarning"};
Settings::Setting<bool> first_start{true, "firstStart"};
Settings::Setting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
Settings::Setting<bool> mute_when_in_background{false, "muteWhenInBackground"};
Settings::Setting<bool> hide_mouse{false, "hideInactiveMouse"};
bool updater_found;

View File

@ -37,16 +37,14 @@ add_custom_command(OUTPUT scm_rev.cpp
"${VIDEO_CORE}/shader/generator/spv_fs_shader_gen.h"
"${VIDEO_CORE}/shader/shader.cpp"
"${VIDEO_CORE}/shader/shader.h"
"${VIDEO_CORE}/pica.cpp"
"${VIDEO_CORE}/pica.h"
"${VIDEO_CORE}/regs_framebuffer.h"
"${VIDEO_CORE}/regs_lighting.h"
"${VIDEO_CORE}/regs_pipeline.h"
"${VIDEO_CORE}/regs_rasterizer.h"
"${VIDEO_CORE}/regs_shader.h"
"${VIDEO_CORE}/regs_texturing.h"
"${VIDEO_CORE}/regs.cpp"
"${VIDEO_CORE}/regs.h"
"${VIDEO_CORE}/pica/regs_framebuffer.h"
"${VIDEO_CORE}/pica/regs_lighting.h"
"${VIDEO_CORE}/pica/regs_pipeline.h"
"${VIDEO_CORE}/pica/regs_rasterizer.h"
"${VIDEO_CORE}/pica/regs_shader.h"
"${VIDEO_CORE}/pica/regs_texturing.h"
"${VIDEO_CORE}/pica/regs_internal.cpp"
"${VIDEO_CORE}/pica/regs_internal.h"
# and also check that the scm_rev files haven't changed
"${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in"
"${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.h"

View File

@ -30,7 +30,7 @@ namespace Common {
#ifdef __APPLE__
static std::string GetCPUString() {
char buf[128];
size_t buf_len = sizeof(buf);
std::size_t buf_len = sizeof(buf);
if (sysctlbyname("machdep.cpu.brand_string", &buf, &buf_len, NULL, 0) == -1) {
return "Unknown";
}

View File

@ -63,15 +63,15 @@ struct ABIFrameInfo {
};
inline ABIFrameInfo ABI_CalculateFrameSize(std::bitset<64> regs, std::size_t frame_size) {
const size_t gprs_count = (regs & ABI_ALL_GPRS).count();
const size_t fprs_count = (regs & ABI_ALL_FPRS).count();
const std::size_t gprs_count = (regs & ABI_ALL_GPRS).count();
const std::size_t fprs_count = (regs & ABI_ALL_FPRS).count();
const size_t gprs_size = (gprs_count + 1) / 2 * 16;
const size_t fprs_size = fprs_count * 16;
const std::size_t gprs_size = (gprs_count + 1) / 2 * 16;
const std::size_t fprs_size = fprs_count * 16;
size_t total_size = 0;
std::size_t total_size = 0;
total_size += gprs_size;
const size_t fprs_base_subtraction = total_size;
const std::size_t fprs_base_subtraction = total_size;
total_size += fprs_size;
total_size += frame_size;
@ -100,11 +100,11 @@ inline void ABI_PushRegisters(oaknut::CodeGenerator& code, std::bitset<64> regs,
}
if (!gprs.empty()) {
for (size_t i = 0; i < gprs.size() - 1; i += 2) {
for (std::size_t i = 0; i < gprs.size() - 1; i += 2) {
code.STP(gprs[i], gprs[i + 1], SP, i * sizeof(u64));
}
if (gprs.size() % 2 == 1) {
const size_t i = gprs.size() - 1;
const std::size_t i = gprs.size() - 1;
code.STR(gprs[i], SP, i * sizeof(u64));
}
}
@ -121,11 +121,11 @@ inline void ABI_PushRegisters(oaknut::CodeGenerator& code, std::bitset<64> regs,
}
if (!fprs.empty()) {
for (size_t i = 0; i < fprs.size() - 1; i += 2) {
for (std::size_t i = 0; i < fprs.size() - 1; i += 2) {
code.STP(fprs[i], fprs[i + 1], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
}
if (fprs.size() % 2 == 1) {
const size_t i = fprs.size() - 1;
const std::size_t i = fprs.size() - 1;
code.STR(fprs[i], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
}
}
@ -159,11 +159,11 @@ inline void ABI_PopRegisters(oaknut::CodeGenerator& code, std::bitset<64> regs,
}
if (!gprs.empty()) {
for (size_t i = 0; i < gprs.size() - 1; i += 2) {
for (std::size_t i = 0; i < gprs.size() - 1; i += 2) {
code.LDP(gprs[i], gprs[i + 1], SP, i * sizeof(u64));
}
if (gprs.size() % 2 == 1) {
const size_t i = gprs.size() - 1;
const std::size_t i = gprs.size() - 1;
code.LDR(gprs[i], SP, i * sizeof(u64));
}
}
@ -180,11 +180,11 @@ inline void ABI_PopRegisters(oaknut::CodeGenerator& code, std::bitset<64> regs,
}
if (!fprs.empty()) {
for (size_t i = 0; i < fprs.size() - 1; i += 2) {
for (std::size_t i = 0; i < fprs.size() - 1; i += 2) {
code.LDP(fprs[i], fprs[i + 1], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
}
if (fprs.size() % 2 == 1) {
const size_t i = fprs.size() - 1;
const std::size_t i = fprs.size() - 1;
code.LDR(fprs[i], SP, frame_info.fprs_offset + i * (sizeof(u64) * 2));
}
}

View File

@ -16,10 +16,10 @@
namespace Common {
namespace detail {
constexpr size_t DefaultCapacity = 0x1000;
constexpr std::size_t DefaultCapacity = 0x1000;
} // namespace detail
template <typename T, size_t Capacity = detail::DefaultCapacity>
template <typename T, std::size_t Capacity = detail::DefaultCapacity>
class SPSCQueue {
static_assert((Capacity & (Capacity - 1)) == 0, "Capacity must be a power of two.");
@ -74,7 +74,7 @@ private:
template <PushMode Mode, typename... Args>
bool Emplace(Args&&... args) {
const size_t write_index = m_write_index.load(std::memory_order::relaxed);
const std::size_t write_index = m_write_index.load(std::memory_order::relaxed);
if constexpr (Mode == PushMode::Try) {
// Check if we have free slots to write to.
@ -92,7 +92,7 @@ private:
}
// Determine the position to write to.
const size_t pos = write_index % Capacity;
const std::size_t pos = write_index % Capacity;
// Emplace into the queue.
new (std::addressof(m_data[pos])) T(std::forward<Args>(args)...);
@ -109,7 +109,7 @@ private:
template <PopMode Mode>
bool Pop(T& t, [[maybe_unused]] std::stop_token stop_token = {}) {
const size_t read_index = m_read_index.load(std::memory_order::relaxed);
const std::size_t read_index = m_read_index.load(std::memory_order::relaxed);
if constexpr (Mode == PopMode::Try) {
// Check if the queue is empty.
@ -136,7 +136,7 @@ private:
}
// Determine the position to read from.
const size_t pos = read_index % Capacity;
const std::size_t pos = read_index % Capacity;
// Pop the data off the queue, moving it.
t = std::move(m_data[pos]);
@ -162,7 +162,7 @@ private:
std::mutex consumer_cv_mutex;
};
template <typename T, size_t Capacity = detail::DefaultCapacity>
template <typename T, std::size_t Capacity = detail::DefaultCapacity>
class MPSCQueue {
public:
template <typename... Args>
@ -202,7 +202,7 @@ private:
std::mutex write_mutex;
};
template <typename T, size_t Capacity = detail::DefaultCapacity>
template <typename T, std::size_t Capacity = detail::DefaultCapacity>
class MPMCQueue {
public:
template <typename... Args>

View File

@ -40,11 +40,9 @@
#define WORDS_BIGENDIAN 1
#endif
using namespace std;
typedef uint8_t uint8;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef std::uint8_t uint8;
typedef std::uint32_t uint32;
typedef std::uint64_t uint64;
namespace Common {
@ -152,19 +150,19 @@ static uint64 HashLen17to32(const char* s, std::size_t len) {
// Return a 16-byte hash for 48 bytes. Quick and dirty.
// Callers do best to use "random-looking" values for a and b.
static pair<uint64, uint64> WeakHashLen32WithSeeds(uint64 w, uint64 x, uint64 y, uint64 z, uint64 a,
uint64 b) {
static std::pair<uint64, uint64> WeakHashLen32WithSeeds(uint64 w, uint64 x, uint64 y, uint64 z,
uint64 a, uint64 b) {
a += w;
b = Rotate(b + a + z, 21);
uint64 c = a;
a += x;
a += y;
b += Rotate(a, 44);
return make_pair(a + z, b + c);
return std::make_pair(a + z, b + c);
}
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
static pair<uint64, uint64> WeakHashLen32WithSeeds(const char* s, uint64 a, uint64 b) {
static std::pair<uint64, uint64> WeakHashLen32WithSeeds(const char* s, uint64 a, uint64 b) {
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a,
b);
}
@ -207,8 +205,8 @@ uint64 CityHash64(const char* s, std::size_t len) {
uint64 x = Fetch64(s + len - 40);
uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
std::pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
std::pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
x = x * k1 + Fetch64(s);
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
@ -276,7 +274,7 @@ uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed) {
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
// v, w, x, y, and z.
pair<uint64, uint64> v, w;
std::pair<uint64, uint64> v, w;
uint64 x = Uint128Low64(seed);
uint64 y = Uint128High64(seed);
uint64 z = len * k1;

View File

@ -38,7 +38,7 @@ bool DynamicLibrary::Load(std::string_view filename) {
if (!handle) {
DWORD error_message_id = GetLastError();
LPSTR message_buffer = nullptr;
size_t size =
std::size_t size =
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, error_message_id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),

View File

@ -1159,7 +1159,7 @@ std::size_t IOFile::ReadImpl(void* data, std::size_t length, std::size_t data_si
}
#ifdef _WIN32
static std::size_t pread(int fd, void* buf, size_t count, uint64_t offset) {
static std::size_t pread(int fd, void* buf, std::size_t count, uint64_t offset) {
long unsigned int read_bytes = 0;
OVERLAPPED overlapped = {0};
HANDLE file = reinterpret_cast<HANDLE>(_get_osfhandle(fd));

View File

@ -37,7 +37,7 @@ static inline u64 ComputeStructHash64(const T& data) noexcept {
* Combines the seed parameter with the provided hash, producing a new unique hash
* Implementation from: http://boost.sourceforge.net/doc/html/boost/hash_combine.html
*/
inline u64 HashCombine(const u64 seed, const u64 hash) {
[[nodiscard]] inline u64 HashCombine(const u64 seed, const u64 hash) {
return seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}

View File

@ -110,8 +110,10 @@ public:
return std::span{cptr, std::min(size, csize)};
}
std::span<const u8> GetReadBytes(std::size_t size) const {
return std::span{cptr, std::min(size, csize)};
template <typename T>
std::span<const T> GetReadBytes(std::size_t size) const {
const auto* cptr_t = reinterpret_cast<T*>(cptr);
return std::span{cptr_t, std::min(size, csize) / sizeof(T)};
}
std::size_t GetSize() const {

View File

@ -39,7 +39,7 @@ void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred&& pred) {
namespace std {
namespace polyfill {
using stop_state_callback = size_t;
using stop_state_callback = std::size_t;
class stop_state {
public:

View File

@ -28,6 +28,11 @@ enum class InitClock : u32 {
FixedTime = 1,
};
enum class InitTicks : u32 {
Random = 0,
Fixed = 1,
};
enum class LayoutOption : u32 {
Default,
SingleScreen,
@ -437,6 +442,8 @@ struct Values {
Setting<InitClock> init_clock{InitClock::SystemTime, "init_clock"};
Setting<u64> init_time{946681277ULL, "init_time"};
Setting<s64> init_time_offset{0, "init_time_offset"};
Setting<InitTicks> init_ticks_type{InitTicks::Random, "init_ticks_type"};
Setting<s64> init_ticks_override{0, "init_ticks_override"};
Setting<bool> plugin_loader_enabled{false, "plugin_loader"};
Setting<bool> allow_plugin_loader{true, "allow_plugin_loader"};

View File

@ -31,9 +31,9 @@ template <class T>
class SlotVector {
public:
~SlotVector() noexcept {
size_t index = 0;
std::size_t index = 0;
for (u64 bits : stored_bitset) {
for (size_t bit = 0; bits; ++bit, bits >>= 1) {
for (std::size_t bit = 0; bits; ++bit, bits >>= 1) {
if ((bits & 1) != 0) {
values[index + bit].object.~T();
}
@ -81,7 +81,7 @@ public:
ResetStorageBit(id.index);
}
size_t size() const noexcept {
std::size_t size() const noexcept {
return values_capacity - free_list.size();
}
@ -126,12 +126,12 @@ private:
return free_index;
}
void Reserve(size_t new_capacity) noexcept {
void Reserve(std::size_t new_capacity) noexcept {
Entry* const new_values = new Entry[new_capacity];
size_t index = 0;
std::size_t index = 0;
for (u64 bits : stored_bitset) {
for (size_t bit = 0; bits; ++bit, bits >>= 1) {
const size_t i = index + bit;
for (std::size_t bit = 0; bits; ++bit, bits >>= 1) {
const std::size_t i = index + bit;
if ((bits & 1) == 0) {
continue;
}
@ -144,7 +144,7 @@ private:
stored_bitset.resize((new_capacity + 63) / 64);
const size_t old_free_size = free_list.size();
const std::size_t old_free_size = free_list.size();
free_list.resize(old_free_size + (new_capacity - values_capacity));
std::iota(free_list.begin() + old_free_size, free_list.end(),
static_cast<u32>(values_capacity));
@ -155,7 +155,7 @@ private:
}
Entry* values = nullptr;
size_t values_capacity = 0;
std::size_t values_capacity = 0;
std::vector<u64> stored_bitset;
std::vector<u32> free_list;
@ -165,7 +165,7 @@ private:
template <>
struct std::hash<Common::SlotId> {
size_t operator()(const Common::SlotId& id) const noexcept {
std::size_t operator()(const Common::SlotId& id) const noexcept {
return std::hash<u32>{}(id.index);
}
};

View File

@ -23,23 +23,23 @@ namespace Common {
// a cache which evicts the least recently used item when it is full
// the cache elements are statically allocated.
template <class Key, class Value, size_t Size>
template <class Key, class Value, std::size_t Size>
class StaticLRUCache {
public:
using key_type = Key;
using value_type = Value;
using list_type = std::list<std::pair<Key, size_t>>;
using list_type = std::list<std::pair<Key, std::size_t>>;
using array_type = std::array<Value, Size>;
StaticLRUCache() = default;
~StaticLRUCache() = default;
size_t size() const {
std::size_t size() const {
return m_list.size();
}
constexpr size_t capacity() const {
constexpr std::size_t capacity() const {
return m_array.size();
}
@ -59,7 +59,7 @@ public:
// lookup value in the cache
auto i = find(key);
if (i == m_list.cend()) {
size_t next_index = size();
std::size_t next_index = size();
// insert item into the cache, but first check if it is full
if (next_index >= capacity()) {
// cache is full, evict the least recently used item
@ -97,10 +97,10 @@ private:
[&key](const auto& el) { return el.first == key; });
}
size_t evict() {
std::size_t evict() {
// evict item from the end of most recently used list
typename list_type::iterator i = --m_list.end();
size_t evicted_index = i->second;
std::size_t evicted_index = i->second;
m_list.erase(i);
return evicted_index;
}

View File

@ -9,7 +9,7 @@
namespace Common {
template <size_t N>
template <std::size_t N>
struct StringLiteral {
constexpr StringLiteral(const char (&str)[N]) {
std::copy_n(str, N, value);

View File

@ -101,7 +101,7 @@ void SetCurrentThreadName(const char* name) {
#elif defined(__linux__)
// Linux limits thread names to 15 characters and will outright reject any
// attempt to set a longer name with ERANGE.
std::string truncated(name, std::min(strlen(name), static_cast<size_t>(15)));
std::string truncated(name, std::min(strlen(name), static_cast<std::size_t>(15)));
if (int e = pthread_setname_np(pthread_self(), truncated.c_str())) {
errno = e;
LOG_ERROR(Common, "Failed to set thread name to '{}': {}", truncated, GetLastErrorMsg());

View File

@ -25,7 +25,7 @@ class StatefulThreadWorker {
static constexpr bool with_state = !std::is_same_v<StateType, void>;
struct DummyCallable {
int operator()(size_t) const noexcept {
int operator()(std::size_t) const noexcept {
return 0;
}
};
@ -33,12 +33,13 @@ class StatefulThreadWorker {
using Task =
std::conditional_t<with_state, UniqueFunction<void, StateType*>, UniqueFunction<void>>;
using StateMaker =
std::conditional_t<with_state, std::function<StateType(size_t)>, DummyCallable>;
std::conditional_t<with_state, std::function<StateType(std::size_t)>, DummyCallable>;
public:
explicit StatefulThreadWorker(size_t num_workers, std::string_view name, StateMaker func = {})
explicit StatefulThreadWorker(std::size_t num_workers, std::string_view name,
StateMaker func = {})
: workers_queued{num_workers}, thread_name{name} {
const auto lambda = [this, func](std::stop_token stop_token, size_t index) {
const auto lambda = [this, func](std::stop_token stop_token, std::size_t index) {
Common::SetCurrentThreadName(thread_name.data());
{
[[maybe_unused]] std::conditional_t<with_state, StateType, int> state{func(index)};
@ -69,7 +70,7 @@ public:
wait_condition.notify_all();
};
threads.reserve(num_workers);
for (size_t i = 0; i < num_workers; ++i) {
for (std::size_t i = 0; i < num_workers; ++i) {
threads.emplace_back(lambda, i);
}
}
@ -110,10 +111,10 @@ private:
std::mutex queue_mutex;
std::condition_variable_any condition;
std::condition_variable wait_condition;
std::atomic<size_t> work_scheduled{};
std::atomic<size_t> work_done{};
std::atomic<size_t> workers_stopped{};
std::atomic<size_t> workers_queued{};
std::atomic<std::size_t> work_scheduled{};
std::atomic<std::size_t> work_done{};
std::atomic<std::size_t> workers_stopped{};
std::atomic<std::size_t> workers_queued{};
std::string_view thread_name;
std::vector<std::jthread> threads;
};

View File

@ -299,8 +299,10 @@ add_library(citra_core STATIC
hle/service/fs/fs_user.h
hle/service/gsp/gsp.cpp
hle/service/gsp/gsp.h
hle/service/gsp/gsp_command.h
hle/service/gsp/gsp_gpu.cpp
hle/service/gsp/gsp_gpu.h
hle/service/gsp/gsp_interrupt.h
hle/service/gsp/gsp_lcd.cpp
hle/service/gsp/gsp_lcd.h
hle/service/hid/hid.cpp
@ -433,12 +435,6 @@ add_library(citra_core STATIC
hw/aes/ccm.h
hw/aes/key.cpp
hw/aes/key.h
hw/gpu.cpp
hw/gpu.h
hw/hw.cpp
hw/hw.h
hw/lcd.cpp
hw/lcd.h
hw/rsa/rsa.cpp
hw/rsa/rsa.h
hw/y2r.cpp

View File

@ -13,8 +13,8 @@ namespace {
template <Common::StringLiteral haystack, Common::StringLiteral needle>
constexpr u32 GetMatchingBitsFromStringLiteral() {
u32 result = 0;
for (size_t i = 0; i < haystack.strlen; i++) {
for (size_t a = 0; a < needle.strlen; a++) {
for (std::size_t i = 0; i < haystack.strlen; i++) {
for (std::size_t a = 0; a < needle.strlen; a++) {
if (haystack.value[i] == needle.value[a]) {
result |= 1 << (haystack.strlen - 1 - i);
}

View File

@ -10,8 +10,6 @@
#include "core/cheats/gateway_cheat.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/process.h"
#include "core/hw/gpu.h"
namespace Cheats {
@ -19,11 +17,11 @@ namespace Cheats {
// we use the same value
constexpr u64 run_interval_ticks = 50'000'000;
CheatEngine::CheatEngine(u64 title_id_, Core::System& system_)
: system(system_), title_id{title_id_} {
LoadCheatFile();
CheatEngine::CheatEngine(Core::System& system_) : system{system_} {}
CheatEngine::~CheatEngine() {
if (system.IsPoweredOn()) {
Connect();
system.CoreTiming().UnscheduleEvent(event, 0);
}
}
@ -34,24 +32,18 @@ void CheatEngine::Connect() {
system.CoreTiming().ScheduleEvent(run_interval_ticks, event);
}
CheatEngine::~CheatEngine() {
if (system.IsPoweredOn()) {
system.CoreTiming().UnscheduleEvent(event, 0);
}
}
std::vector<std::shared_ptr<CheatBase>> CheatEngine::GetCheats() const {
std::shared_lock<std::shared_mutex> lock(cheats_list_mutex);
std::span<const std::shared_ptr<CheatBase>> CheatEngine::GetCheats() const {
std::shared_lock lock{cheats_list_mutex};
return cheats_list;
}
void CheatEngine::AddCheat(const std::shared_ptr<CheatBase>& cheat) {
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
cheats_list.push_back(cheat);
void CheatEngine::AddCheat(std::shared_ptr<CheatBase>&& cheat) {
std::unique_lock lock{cheats_list_mutex};
cheats_list.push_back(std::move(cheat));
}
void CheatEngine::RemoveCheat(std::size_t index) {
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
std::unique_lock lock{cheats_list_mutex};
if (index < 0 || index >= cheats_list.size()) {
LOG_ERROR(Core_Cheats, "Invalid index {}", index);
return;
@ -59,16 +51,16 @@ void CheatEngine::RemoveCheat(std::size_t index) {
cheats_list.erase(cheats_list.begin() + index);
}
void CheatEngine::UpdateCheat(std::size_t index, const std::shared_ptr<CheatBase>& new_cheat) {
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
void CheatEngine::UpdateCheat(std::size_t index, std::shared_ptr<CheatBase>&& new_cheat) {
std::unique_lock lock{cheats_list_mutex};
if (index < 0 || index >= cheats_list.size()) {
LOG_ERROR(Core_Cheats, "Invalid index {}", index);
return;
}
cheats_list[index] = new_cheat;
cheats_list[index] = std::move(new_cheat);
}
void CheatEngine::SaveCheatFile() const {
void CheatEngine::SaveCheatFile(u64 title_id) const {
const std::string cheat_dir = FileUtil::GetUserPath(FileUtil::UserPath::CheatsDir);
const std::string filepath = fmt::format("{}{:016X}.txt", cheat_dir, title_id);
@ -83,7 +75,14 @@ void CheatEngine::SaveCheatFile() const {
}
}
void CheatEngine::LoadCheatFile() {
void CheatEngine::LoadCheatFile(u64 title_id) {
{
std::unique_lock lock{cheats_list_mutex};
if (loaded_title_id.has_value() && loaded_title_id == title_id) {
return;
}
}
const std::string cheat_dir = FileUtil::GetUserPath(FileUtil::UserPath::CheatsDir);
const std::string filepath = fmt::format("{}{:016X}.txt", cheat_dir, title_id);
@ -91,20 +90,22 @@ void CheatEngine::LoadCheatFile() {
FileUtil::CreateDir(cheat_dir);
}
if (!FileUtil::Exists(filepath))
if (!FileUtil::Exists(filepath)) {
return;
}
auto gateway_cheats = GatewayCheat::LoadFile(filepath);
{
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
std::move(gateway_cheats.begin(), gateway_cheats.end(), std::back_inserter(cheats_list));
std::unique_lock lock{cheats_list_mutex};
loaded_title_id = title_id;
cheats_list = std::move(gateway_cheats);
}
}
void CheatEngine::RunCallback([[maybe_unused]] std::uintptr_t user_data, s64 cycles_late) {
{
std::shared_lock<std::shared_mutex> lock(cheats_list_mutex);
for (auto& cheat : cheats_list) {
std::shared_lock lock{cheats_list_mutex};
for (const auto& cheat : cheats_list) {
if (cheat->IsEnabled()) {
cheat->Execute(system);
}

View File

@ -5,7 +5,9 @@
#pragma once
#include <memory>
#include <optional>
#include <shared_mutex>
#include <span>
#include <vector>
#include "common/common_types.h"
@ -24,22 +26,39 @@ class CheatBase;
class CheatEngine {
public:
explicit CheatEngine(u64 title_id_, Core::System& system);
explicit CheatEngine(Core::System& system);
~CheatEngine();
/// Registers the cheat execution callback.
void Connect();
std::vector<std::shared_ptr<CheatBase>> GetCheats() const;
void AddCheat(const std::shared_ptr<CheatBase>& cheat);
/// Returns a span of the currently active cheats.
std::span<const std::shared_ptr<CheatBase>> GetCheats() const;
/// Adds a cheat to the cheat engine.
void AddCheat(std::shared_ptr<CheatBase>&& cheat);
/// Removes a cheat at the specified index in the cheats list.
void RemoveCheat(std::size_t index);
void UpdateCheat(std::size_t index, const std::shared_ptr<CheatBase>& new_cheat);
void SaveCheatFile() const;
/// Updates a cheat at the specified index in the cheats list.
void UpdateCheat(std::size_t index, std::shared_ptr<CheatBase>&& new_cheat);
/// Loads the cheat file from disk for the specified title id.
void LoadCheatFile(u64 title_id);
/// Saves currently active cheats to file for the specified title id.
void SaveCheatFile(u64 title_id) const;
private:
void LoadCheatFile();
/// The cheat execution callback.
void RunCallback(std::uintptr_t user_data, s64 cycles_late);
private:
Core::System& system;
Core::TimingEventType* event;
std::optional<u64> loaded_title_id;
std::vector<std::shared_ptr<CheatBase>> cheats_list;
mutable std::shared_mutex cheats_list_mutex;
Core::TimingEventType* event;
Core::System& system;
u64 title_id;
};
} // namespace Cheats

View File

@ -472,8 +472,8 @@ std::string GatewayCheat::ToString() const {
return result;
}
std::vector<std::unique_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string& filepath) {
std::vector<std::unique_ptr<CheatBase>> cheats;
std::vector<std::shared_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string& filepath) {
std::vector<std::shared_ptr<CheatBase>> cheats;
boost::iostreams::stream<boost::iostreams::file_descriptor_source> file;
FileUtil::OpenFStream<std::ios_base::in>(file, filepath);
@ -493,7 +493,7 @@ std::vector<std::unique_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string
line = Common::StripSpaces(line); // remove spaces at front and end
if (line.length() >= 2 && line.front() == '[') {
if (!cheat_lines.empty()) {
cheats.push_back(std::make_unique<GatewayCheat>(name, cheat_lines, comments));
cheats.push_back(std::make_shared<GatewayCheat>(name, cheat_lines, comments));
cheats.back()->SetEnabled(enabled);
enabled = false;
}
@ -511,7 +511,7 @@ std::vector<std::unique_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string
}
}
if (!cheat_lines.empty()) {
cheats.push_back(std::make_unique<GatewayCheat>(name, cheat_lines, comments));
cheats.push_back(std::make_shared<GatewayCheat>(name, cheat_lines, comments));
cheats.back()->SetEnabled(enabled);
}
return cheats;

View File

@ -77,7 +77,7 @@ public:
/// (there might be multiple lines of those hex numbers)
/// Comment lines start with a '*'
/// This function will pares the file for such structures
static std::vector<std::unique_ptr<CheatBase>> LoadFile(const std::string& filepath);
static std::vector<std::shared_ptr<CheatBase>> LoadFile(const std::string& filepath);
private:
std::atomic<bool> enabled = false;

View File

@ -35,14 +35,13 @@
#include "core/hle/service/cam/cam.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/gsp/gsp.h"
#include "core/hle/service/gsp/gsp_gpu.h"
#include "core/hle/service/ir/ir_rst.h"
#include "core/hle/service/mic/mic_u.h"
#include "core/hle/service/plgldr/plgldr.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "core/hw/gpu.h"
#include "core/hw/hw.h"
#include "core/hw/lcd.h"
#include "core/hw/aes/key.h"
#include "core/loader/loader.h"
#include "core/movie.h"
#ifdef ENABLE_SCRIPTING
@ -51,8 +50,8 @@
#include "core/telemetry_session.h"
#include "network/network.h"
#include "video_core/custom_textures/custom_tex_manager.h"
#include "video_core/gpu.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
namespace Core {
@ -73,7 +72,7 @@ Core::Timing& Global() {
return System::GetInstance().CoreTiming();
}
System::System() : movie{*this} {}
System::System() : movie{*this}, cheat_engine{*this} {}
System::~System() = default;
@ -235,7 +234,6 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
GDBStub::SetCpuStepFlag(false);
}
HW::Update();
Reschedule();
return status;
@ -298,6 +296,20 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
return init_result;
}
// Restore any parameters that should be carried through a reset.
if (restore_deliver_arg.has_value()) {
if (auto apt = Service::APT::GetModule(*this)) {
apt->GetAppletManager()->SetDeliverArg(restore_deliver_arg);
}
restore_deliver_arg.reset();
}
if (restore_plugin_context.has_value()) {
if (auto plg_ldr = Service::PLGLDR::GetService(*this)) {
plg_ldr->SetPluginLoaderContext(restore_plugin_context.value());
}
restore_plugin_context.reset();
}
telemetry_session->AddInitialInfo(*app_loader);
std::shared_ptr<Kernel::Process> process;
const Loader::ResultStatus load_result{app_loader->Load(process)};
@ -322,7 +334,10 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})",
static_cast<u32>(load_result));
}
cheat_engine = std::make_unique<Cheats::CheatEngine>(title_id, *this);
cheat_engine.LoadCheatFile(title_id);
cheat_engine.Connect();
perf_stats = std::make_unique<PerfStats>(title_id);
if (Settings::values.dump_textures) {
@ -378,7 +393,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
memory = std::make_unique<Memory::MemorySystem>(*this);
timing = std::make_unique<Timing>(num_cores, Settings::values.cpu_clock_percentage.GetValue());
timing = std::make_unique<Timing>(num_cores, Settings::values.cpu_clock_percentage.GetValue(),
movie.GetOverrideBaseTicks());
kernel = std::make_unique<Kernel::KernelSystem>(
*memory, *timing, [this] { PrepareReschedule(); }, memory_mode, num_cores, n3ds_hw_caps,
@ -433,7 +449,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
service_manager = std::make_unique<Service::SM::ServiceManager>(*this);
archive_manager = std::make_unique<Service::FS::ArchiveManager>(*this);
HW::Init(*memory);
HW::AES::InitKeys();
Service::Init(*this);
GDBStub::DeferStart();
@ -443,7 +459,16 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
custom_tex_manager = std::make_unique<VideoCore::CustomTexManager>(*this);
VideoCore::Init(emu_window, secondary_window, *this);
auto gsp = service_manager->GetService<Service::GSP::GSP_GPU>("gsp::Gpu");
gpu = std::make_unique<VideoCore::GPU>(*this, emu_window, secondary_window);
gpu->SetInterruptHandler(
[gsp](Service::GSP::InterruptId interrupt_id) { gsp->SignalInterrupt(interrupt_id); });
auto plg_ldr = Service::PLGLDR::GetService(*this);
if (plg_ldr) {
plg_ldr->SetEnabled(Settings::values.plugin_loader_enabled.GetValue());
plg_ldr->SetAllowGameChangeState(Settings::values.allow_plugin_loader.GetValue());
}
LOG_DEBUG(Core, "Initialized OK");
@ -452,8 +477,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
return ResultStatus::Success;
}
VideoCore::RendererBase& System::Renderer() {
return *VideoCore::g_renderer;
VideoCore::GPU& System::GPU() {
return *gpu;
}
Service::SM::ServiceManager& System::ServiceManager() {
@ -501,11 +526,11 @@ const Memory::MemorySystem& System::Memory() const {
}
Cheats::CheatEngine& System::CheatEngine() {
return *cheat_engine;
return cheat_engine;
}
const Cheats::CheatEngine& System::CheatEngine() const {
return *cheat_engine;
return cheat_engine;
}
void System::RegisterVideoDumper(std::shared_ptr<VideoDumper::Backend> dumper) {
@ -555,12 +580,10 @@ void System::Shutdown(bool is_deserializing) {
// Shutdown emulation session
is_powered_on = false;
VideoCore::Shutdown();
HW::Shutdown();
gpu.reset();
if (!is_deserializing) {
GDBStub::Shutdown();
perf_stats.reset();
cheat_engine.reset();
app_loader.reset();
}
custom_tex_manager.reset();
@ -599,10 +622,13 @@ void System::Reset() {
// reloading.
// TODO: Properly implement the reset
// Since the system is completely reinitialized, we'll have to store the deliver arg manually.
boost::optional<Service::APT::DeliverArg> deliver_arg;
// Save the APT deliver arg and plugin loader context across resets.
// This is needed as we don't currently support proper app jumping.
if (auto apt = Service::APT::GetModule(*this)) {
deliver_arg = apt->GetAppletManager()->ReceiveDeliverArg();
restore_deliver_arg = apt->GetAppletManager()->ReceiveDeliverArg();
}
if (auto plg_ldr = Service::PLGLDR::GetService(*this)) {
restore_plugin_context = plg_ldr->GetPluginLoaderContext();
}
Shutdown();
@ -615,29 +641,15 @@ void System::Reset() {
// Reload the system with the same setting
[[maybe_unused]] const System::ResultStatus result =
Load(*m_emu_window, m_filepath, m_secondary_window);
// Restore the deliver arg.
if (auto apt = Service::APT::GetModule(*this)) {
apt->GetAppletManager()->SetDeliverArg(std::move(deliver_arg));
}
}
void System::ApplySettings() {
GDBStub::SetServerPort(Settings::values.gdbstub_port.GetValue());
GDBStub::ToggleServer(Settings::values.use_gdbstub.GetValue());
VideoCore::g_shader_jit_enabled = Settings::values.use_shader_jit.GetValue();
VideoCore::g_hw_shader_enabled = Settings::values.use_hw_shader.GetValue();
VideoCore::g_hw_shader_accurate_mul = Settings::values.shaders_accurate_mul.GetValue();
#ifndef ANDROID
if (VideoCore::g_renderer) {
VideoCore::g_renderer->UpdateCurrentFramebufferLayout();
}
#endif
if (VideoCore::g_renderer) {
auto& settings = VideoCore::g_renderer->Settings();
if (gpu) {
gpu->Renderer().UpdateCurrentFramebufferLayout();
auto& settings = gpu->Renderer().Settings();
settings.bg_color_update_requested = true;
settings.shader_update_requested = true;
}
@ -673,9 +685,11 @@ void System::ApplySettings() {
Service::MIC::ReloadMic(*this);
}
Service::PLGLDR::PLG_LDR::SetEnabled(Settings::values.plugin_loader_enabled.GetValue());
Service::PLGLDR::PLG_LDR::SetAllowGameChangeState(
Settings::values.allow_plugin_loader.GetValue());
auto plg_ldr = Service::PLGLDR::GetService(*this);
if (plg_ldr) {
plg_ldr->SetEnabled(Settings::values.plugin_loader_enabled.GetValue());
plg_ldr->SetAllowGameChangeState(Settings::values.allow_plugin_loader.GetValue());
}
}
template <class Archive>
@ -699,17 +713,15 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
*m_emu_window, m_secondary_window, *memory_mode.first, *n3ds_hw_caps.first, num_cores);
}
// flush on save, don't flush on load
bool should_flush = !Archive::is_loading::value;
Memory::RasterizerClearAll(should_flush);
// Flush on save, don't flush on load
const bool should_flush = !Archive::is_loading::value;
gpu->ClearAll(should_flush);
ar&* timing.get();
for (u32 i = 0; i < num_cores; i++) {
ar&* cpu_cores[i].get();
}
ar&* service_manager.get();
ar&* archive_manager.get();
ar& GPU::g_regs;
ar& LCD::g_regs;
// NOTE: DSP doesn't like being destroyed and recreated. So instead we do an inline
// serialization; this means that the DSP Settings need to match for loading to work.
@ -722,16 +734,21 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
ar&* memory.get();
ar&* kernel.get();
VideoCore::serialize(ar, file_version);
ar&* gpu.get();
ar& movie;
// This needs to be set from somewhere - might as well be here!
if (Archive::is_loading::value) {
timing->UnlockEventQueue();
Service::GSP::SetGlobalModule(*this);
memory->SetDSP(*dsp_core);
cheat_engine->Connect();
VideoCore::g_renderer->Sync();
cheat_engine.Connect();
gpu->Sync();
// Re-register gpu callback, because gsp service changed after service_manager got
// serialized
auto gsp = service_manager->GetService<Service::GSP::GSP_GPU>("gsp::Gpu");
gpu->SetInterruptHandler(
[gsp](Service::GSP::InterruptId interrupt_id) { gsp->SignalInterrupt(interrupt_id); });
}
}

View File

@ -8,9 +8,13 @@
#include <memory>
#include <mutex>
#include <string>
#include <boost/optional.hpp>
#include <boost/serialization/version.hpp>
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
#include "core/cheats/cheats.h"
#include "core/hle/service/apt/applet_manager.h"
#include "core/hle/service/plgldr/plgldr.h"
#include "core/movie.h"
#include "core/perf_stats.h"
@ -48,19 +52,19 @@ struct New3dsHwCapabilities;
enum class MemoryMode : u8;
} // namespace Kernel
namespace Cheats {
class CheatEngine;
}
namespace VideoDumper {
class Backend;
}
namespace VideoCore {
class CustomTexManager;
class RendererBase;
class GPU;
} // namespace VideoCore
namespace Pica {
class DebugContext;
}
namespace Loader {
class AppLoader;
}
@ -217,7 +221,7 @@ public:
return *dsp_core;
}
[[nodiscard]] VideoCore::RendererBase& Renderer();
[[nodiscard]] VideoCore::GPU& GPU();
/**
* Gets a reference to the service manager.
@ -384,6 +388,8 @@ private:
/// Telemetry session for this emulation session
std::unique_ptr<Core::TelemetrySession> telemetry_session;
std::unique_ptr<VideoCore::GPU> gpu;
/// Service manager
std::unique_ptr<Service::SM::ServiceManager> service_manager;
@ -395,7 +401,7 @@ private:
Core::Movie movie;
/// Cheats manager
std::unique_ptr<Cheats::CheatEngine> cheat_engine;
Cheats::CheatEngine cheat_engine;
/// Video dumper backend
std::shared_ptr<VideoDumper::Backend> video_dumper;
@ -441,6 +447,9 @@ private:
std::function<bool()> mic_permission_func;
bool mic_permission_granted = false;
boost::optional<Service::APT::DeliverArg> restore_deliver_arg;
boost::optional<Service::PLGLDR::PLG_LDR::PluginLoaderContext> restore_plugin_context;
friend class boost::serialization::access;
template <typename Archive>
void serialize(Archive& ar, const unsigned int file_version);

View File

@ -3,9 +3,11 @@
// Refer to the license.txt file included.
#include <algorithm>
#include <random>
#include <tuple>
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/core_timing.h"
namespace Core {
@ -19,15 +21,28 @@ bool Timing::Event::operator<(const Timing::Event& right) const {
return std::tie(time, fifo_order) < std::tie(right.time, right.fifo_order);
}
Timing::Timing(std::size_t num_cores, u32 cpu_clock_percentage) {
Timing::Timing(std::size_t num_cores, u32 cpu_clock_percentage, s64 override_base_ticks) {
// Generate non-zero base tick count to simulate time the system ran before launching the game.
// This accounts for games that rely on the system tick to seed randomness.
const auto base_ticks = override_base_ticks >= 0 ? override_base_ticks : GenerateBaseTicks();
timers.resize(num_cores);
for (std::size_t i = 0; i < num_cores; ++i) {
timers[i] = std::make_shared<Timer>();
timers[i] = std::make_shared<Timer>(base_ticks);
}
UpdateClockSpeed(cpu_clock_percentage);
current_timer = timers[0].get();
}
s64 Timing::GenerateBaseTicks() {
if (Settings::values.init_ticks_type.GetValue() == Settings::InitTicks::Fixed) {
return Settings::values.init_ticks_override.GetValue();
}
// Bounded to 32 bits to make sure we don't generate too high of a counter and risk overflowing.
std::mt19937 random_gen(std::random_device{}());
return random_gen();
}
void Timing::UpdateClockSpeed(u32 cpu_clock_percentage) {
for (auto& timer : timers) {
timer->cpu_clock_scale = 100.0 / cpu_clock_percentage;
@ -146,7 +161,7 @@ std::shared_ptr<Timing::Timer> Timing::GetTimer(std::size_t cpu_id) {
return timers[cpu_id];
}
Timing::Timer::Timer() = default;
Timing::Timer::Timer(s64 base_ticks) : executed_ticks(base_ticks) {}
Timing::Timer::~Timer() {
MoveEvents();

View File

@ -37,6 +37,10 @@
constexpr u64 BASE_CLOCK_RATE_ARM11 = 268111856;
constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE_ARM11;
/// Refresh rate defined by ratio of ARM11 frequency to ARM11 ticks per frame
/// (268,111,856) / (4,481,136) = 59.83122493939037Hz
constexpr double SCREEN_REFRESH_RATE = BASE_CLOCK_RATE_ARM11 / static_cast<double>(4481136ull);
constexpr s64 msToCycles(int ms) {
// since ms is int there is no way to overflow
return BASE_CLOCK_RATE_ARM11 * static_cast<s64>(ms) / 1000;
@ -181,7 +185,7 @@ public:
class Timer {
public:
Timer();
Timer(s64 base_ticks = 0);
~Timer();
s64 GetMaxSliceLength() const;
@ -245,7 +249,7 @@ public:
friend class boost::serialization::access;
};
explicit Timing(std::size_t num_cores, u32 cpu_clock_percentage);
explicit Timing(std::size_t num_cores, u32 cpu_clock_percentage, s64 override_base_ticks = -1);
~Timing(){};
@ -286,6 +290,9 @@ public:
event_queue_locked = false;
}
/// Generates a random tick count to seed the system tick timer with.
static s64 GenerateBaseTicks();
private:
// unordered_map stores each element separately as a linked list node so pointers to
// elements remain stable regardless of rehashes/resizing.

View File

@ -11,10 +11,10 @@
#include "common/scope_exit.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "core/core_timing.h"
#include "core/dumping/ffmpeg_backend.h"
#include "core/hw/gpu.h"
#include "video_core/gpu.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
using namespace DynamicLibrary;
@ -381,7 +381,7 @@ bool FFmpegVideoStream::InitFilters() {
}
// Configure buffer source
static constexpr AVRational src_time_base{static_cast<int>(GPU::frame_ticks),
static constexpr AVRational src_time_base{static_cast<int>(VideoCore::FRAME_TICKS),
static_cast<int>(BASE_CLOCK_RATE_ARM11)};
const std::string in_args =
fmt::format("video_size={}x{}:pix_fmt={}:time_base={}/{}:pixel_aspect=1", layout.width,
@ -732,7 +732,7 @@ void FFmpegMuxer::WriteTrailer() {
FFmpeg::av_write_trailer(format_context.get());
}
FFmpegBackend::FFmpegBackend() = default;
FFmpegBackend::FFmpegBackend(VideoCore::RendererBase& renderer_) : renderer{renderer_} {}
FFmpegBackend::~FFmpegBackend() {
ASSERT_MSG(!IsDumping(), "Dumping must be stopped first");
@ -796,7 +796,7 @@ bool FFmpegBackend::StartDumping(const std::string& path, const Layout::Framebuf
}
});
VideoCore::g_renderer->PrepareVideoDumping();
renderer.PrepareVideoDumping();
is_dumping = true;
return true;
@ -829,7 +829,7 @@ void FFmpegBackend::AddAudioSample(const std::array<s16, 2>& sample) {
void FFmpegBackend::StopDumping() {
is_dumping = false;
VideoCore::g_renderer->CleanupVideoDumping();
renderer.CleanupVideoDumping();
// Flush the video processing queue
AddVideoFrame(VideoFrame());
@ -1073,7 +1073,7 @@ std::vector<FormatInfo> ListFormats() {
continue;
}
out.push_back({current->name, ToStdString(current->long_name), std::move(extensions),
out.push_back({current->name, ToStdString(current->long_name), extensions,
std::move(supported_video_codecs), std::move(supported_audio_codecs),
GetOptionList(current->priv_class, true)});
}

View File

@ -18,6 +18,10 @@
#include "common/threadsafe_queue.h"
#include "core/dumping/backend.h"
namespace VideoCore {
class RendererBase;
}
namespace VideoDumper {
using VariableAudioFrame = std::vector<s16>;
@ -181,7 +185,7 @@ private:
*/
class FFmpegBackend : public Backend {
public:
FFmpegBackend();
FFmpegBackend(VideoCore::RendererBase& renderer);
~FFmpegBackend() override;
bool StartDumping(const std::string& path, const Layout::FramebufferLayout& layout) override;
void AddVideoFrame(VideoFrame frame) override;
@ -194,6 +198,7 @@ public:
private:
void EndDumping();
VideoCore::RendererBase& renderer;
std::atomic_bool is_dumping = false; ///< Whether the backend is currently dumping
FFmpegMuxer ffmpeg{};

View File

@ -127,7 +127,7 @@ public:
* @param path Path relative to the archive
* @return Result of the operation
*/
virtual ResultCode DeleteFile(const Path& path) const = 0;
virtual Result DeleteFile(const Path& path) const = 0;
/**
* Rename a File specified by its path
@ -135,21 +135,21 @@ public:
* @param dest_path Destination path relative to the archive
* @return Result of the operation
*/
virtual ResultCode RenameFile(const Path& src_path, const Path& dest_path) const = 0;
virtual Result RenameFile(const Path& src_path, const Path& dest_path) const = 0;
/**
* Delete a directory specified by its path
* @param path Path relative to the archive
* @return Result of the operation
*/
virtual ResultCode DeleteDirectory(const Path& path) const = 0;
virtual Result DeleteDirectory(const Path& path) const = 0;
/**
* Delete a directory specified by its path and anything under it
* @param path Path relative to the archive
* @return Result of the operation
*/
virtual ResultCode DeleteDirectoryRecursively(const Path& path) const = 0;
virtual Result DeleteDirectoryRecursively(const Path& path) const = 0;
/**
* Create a file specified by its path
@ -157,14 +157,14 @@ public:
* @param size The size of the new file, filled with zeroes
* @return Result of the operation
*/
virtual ResultCode CreateFile(const Path& path, u64 size) const = 0;
virtual Result CreateFile(const Path& path, u64 size) const = 0;
/**
* Create a directory specified by its path
* @param path Path relative to the archive
* @return Result of the operation
*/
virtual ResultCode CreateDirectory(const Path& path) const = 0;
virtual Result CreateDirectory(const Path& path) const = 0;
/**
* Rename a Directory specified by its path
@ -172,7 +172,7 @@ public:
* @param dest_path Destination path relative to the archive
* @return Result of the operation
*/
virtual ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const = 0;
virtual Result RenameDirectory(const Path& src_path, const Path& dest_path) const = 0;
/**
* Open a directory specified by its path
@ -229,10 +229,10 @@ public:
* @param path Path to the archive
* @param format_info Format information for the new archive
* @param program_id the program ID of the client that requests the operation
* @return ResultCode of the operation, 0 on success
* @return Result of the operation, 0 on success
*/
virtual ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
u64 program_id) = 0;
virtual Result Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
u64 program_id) = 0;
/**
* Retrieves the format info about the archive with the specified path

View File

@ -40,7 +40,7 @@ public:
ResultVal<std::size_t> Write(u64 offset, std::size_t length, bool flush,
const u8* buffer) override {
if (offset > size) {
return ERR_WRITE_BEYOND_END;
return ResultWriteBeyondEnd;
} else if (offset == size) {
return 0ULL;
}
@ -108,17 +108,17 @@ public:
if (!path_parser.IsValid()) {
LOG_ERROR(Service_FS, "Invalid path {}", path.DebugStr());
return ERROR_INVALID_PATH;
return ResultInvalidPath;
}
if (mode.hex == 0) {
LOG_ERROR(Service_FS, "Empty open mode");
return ERROR_UNSUPPORTED_OPEN_FLAGS;
return ResultUnsupportedOpenFlags;
}
if (mode.create_flag) {
LOG_ERROR(Service_FS, "Create flag is not supported");
return ERROR_UNSUPPORTED_OPEN_FLAGS;
return ResultUnsupportedOpenFlags;
}
const auto full_path = path_parser.BuildHostPath(mount_point);
@ -126,17 +126,17 @@ public:
switch (path_parser.GetHostStatus(mount_point)) {
case PathParser::InvalidMountPoint:
LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point {}", mount_point);
return ERROR_FILE_NOT_FOUND;
return ResultFileNotFound;
case PathParser::PathNotFound:
LOG_ERROR(Service_FS, "Path not found {}", full_path);
return ERROR_PATH_NOT_FOUND;
return ResultPathNotFound;
case PathParser::FileInPath:
case PathParser::DirectoryFound:
LOG_ERROR(Service_FS, "Unexpected file or directory in {}", full_path);
return ERROR_UNEXPECTED_FILE_OR_DIRECTORY;
return ResultUnexpectedFileOrDirectory;
case PathParser::NotFound:
LOG_ERROR(Service_FS, "{} not found", full_path);
return ERROR_FILE_NOT_FOUND;
return ResultFileNotFound;
case PathParser::FileFound:
break; // Expected 'success' case
}
@ -144,7 +144,7 @@ public:
FileUtil::IOFile file(full_path, "r+b");
if (!file.IsOpen()) {
LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening {}", full_path);
return ERROR_FILE_NOT_FOUND;
return ResultFileNotFound;
}
Mode rwmode;
@ -155,10 +155,10 @@ public:
std::move(delay_generator));
}
ResultCode CreateFile(const Path& path, u64 size) const override {
Result CreateFile(const Path& path, u64 size) const override {
if (size == 0) {
LOG_ERROR(Service_FS, "Zero-size file is not supported");
return ERROR_UNSUPPORTED_OPEN_FLAGS;
return ResultUnsupportedOpenFlags;
}
return SaveDataArchive::CreateFile(path, size);
}
@ -250,18 +250,18 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(cons
// TODO(Subv): Verify the archive behavior of SharedExtSaveData compared to ExtSaveData.
// ExtSaveData seems to return FS_NotFound (120) when the archive doesn't exist.
if (type != ExtSaveDataType::Shared) {
return ERR_NOT_FOUND_INVALID_STATE;
return ResultNotFoundInvalidState;
} else {
return ERR_NOT_FORMATTED;
return ResultNotFormatted;
}
}
std::unique_ptr<DelayGenerator> delay_generator = std::make_unique<ExtSaveDataDelayGenerator>();
return std::make_unique<ExtSaveDataArchive>(fullpath, std::move(delay_generator));
}
ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path,
const FileSys::ArchiveFormatInfo& format_info,
u64 program_id) {
Result ArchiveFactory_ExtSaveData::Format(const Path& path,
const FileSys::ArchiveFormatInfo& format_info,
u64 program_id) {
auto corrected_path = GetCorrectedPath(path);
// These folders are always created with the ExtSaveData
@ -276,11 +276,11 @@ ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path,
if (!file.IsOpen()) {
// TODO(Subv): Find the correct error code
return RESULT_UNKNOWN;
return ResultUnknown;
}
file.WriteBytes(&format_info, sizeof(format_info));
return RESULT_SUCCESS;
return ResultSuccess;
}
ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Path& path,
@ -291,7 +291,7 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Pat
if (!file.IsOpen()) {
LOG_ERROR(Service_FS, "Could not open metadata information for archive");
// TODO(Subv): Verify error code
return ERR_NOT_FORMATTED;
return ResultNotFormatted;
}
ArchiveFormatInfo info = {};

Some files were not shown because too many files have changed in this diff Show More