diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/frontend/emu_window.h | 39 | ||||
-rw-r--r-- | src/core/hle/kernel/thread.cpp | 5 | ||||
-rw-r--r-- | src/core/hle/kernel/thread.h | 6 | ||||
-rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.cpp | 15 | ||||
-rw-r--r-- | src/core/hle/service/ldr/ldr.cpp | 150 | ||||
-rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.cpp | 16 | ||||
-rw-r--r-- | src/core/settings.h | 1 |
7 files changed, 133 insertions, 99 deletions
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index d0bcb4660..70a522556 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -13,6 +13,23 @@ namespace Core::Frontend { /** + * Represents a graphics context that can be used for background computation or drawing. If the + * graphics backend doesn't require the context, then the implementation of these methods can be + * stubs + */ +class GraphicsContext { +public: + /// Makes the graphics context current for the caller thread + virtual void MakeCurrent() = 0; + + /// Releases (dunno if this is the "right" word) the context from the caller thread + virtual void DoneCurrent() = 0; + + /// Swap buffers to display the next frame + virtual void SwapBuffers() = 0; +}; + +/** * Abstraction class used to provide an interface between emulation code and the frontend * (e.g. SDL, QGLWidget, GLFW, etc...). * @@ -30,7 +47,7 @@ namespace Core::Frontend { * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please * re-read the upper points again and think about it if you don't see this. */ -class EmuWindow { +class EmuWindow : public GraphicsContext { public: /// Data structure to store emuwindow configuration struct WindowConfig { @@ -40,17 +57,21 @@ public: std::pair<unsigned, unsigned> min_client_area_size; }; - /// Swap buffers to display the next frame - virtual void SwapBuffers() = 0; - /// Polls window events virtual void PollEvents() = 0; - /// Makes the graphics context current for the caller thread - virtual void MakeCurrent() = 0; - - /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread - virtual void DoneCurrent() = 0; + /** + * Returns a GraphicsContext that the frontend provides that is shared with the emu window. This + * context can be used from other threads for background graphics computation. If the frontend + * is using a graphics backend that doesn't need anything specific to run on a different thread, + * then it can use a stubbed implemenation for GraphicsContext. + * + * If the return value is null, then the core should assume that the frontend cannot provide a + * Shared Context + */ + virtual std::unique_ptr<GraphicsContext> CreateSharedContext() const { + return nullptr; + } /** * Signal that a touch pressed event has occurred (e.g. mouse click pressed) diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 1b891f632..ca52267b2 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -220,11 +220,6 @@ void Thread::SetPriority(u32 priority) { UpdatePriority(); } -void Thread::BoostPriority(u32 priority) { - scheduler->SetThreadPriority(this, priority); - current_priority = priority; -} - void Thread::SetWaitSynchronizationResult(ResultCode result) { context.cpu_registers[0] = result.raw; } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 83c83e45a..32026d7f0 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -136,12 +136,6 @@ public: */ void SetPriority(u32 priority); - /** - * Temporarily boosts the thread's priority until the next time it is scheduled - * @param priority The new priority - */ - void BoostPriority(u32 priority); - /// Adds a thread to the list of threads that are waiting for a lock held by this thread. void AddMutexWaiter(SharedPtr<Thread> thread); diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 657baddb8..0249b6992 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -115,11 +115,12 @@ private: void Read(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const u64 unk = rp.Pop<u64>(); + const u64 option = rp.Pop<u64>(); const s64 offset = rp.Pop<s64>(); const s64 length = rp.Pop<s64>(); - LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); + LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, + length); // Error checking if (length < 0) { @@ -148,11 +149,12 @@ private: void Write(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const u64 unk = rp.Pop<u64>(); + const u64 option = rp.Pop<u64>(); const s64 offset = rp.Pop<s64>(); const s64 length = rp.Pop<s64>(); - LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); + LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, + length); // Error checking if (length < 0) { @@ -250,10 +252,7 @@ private: u64 next_entry_index = 0; void Read(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 unk = rp.Pop<u64>(); - - LOG_DEBUG(Service_FS, "called, unk=0x{:X}", unk); + LOG_DEBUG(Service_FS, "called."); // Calculate how many entries we can fit in the output buffer const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry); diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index d65693fc7..609102f2c 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -93,12 +93,18 @@ public: } void LoadNrr(Kernel::HLERequestContext& ctx) { + struct Parameters { + u64_le process_id; + u64_le nrr_address; + u64_le nrr_size; + }; + IPC::RequestParser rp{ctx}; - rp.Skip(2, false); - const VAddr nrr_addr{rp.Pop<VAddr>()}; - const u64 nrr_size{rp.Pop<u64>()}; - LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}, nrr_size={:016X}", nrr_addr, - nrr_size); + const auto [process_id, nrr_address, nrr_size] = rp.PopRaw<Parameters>(); + + LOG_DEBUG(Service_LDR, + "called with process_id={:016X}, nrr_address={:016X}, nrr_size={:016X}", + process_id, nrr_address, nrr_size); if (!initialized) { LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); @@ -116,24 +122,26 @@ public: } // NRR Address does not fall on 0x1000 byte boundary - if (!Common::Is4KBAligned(nrr_addr)) { - LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr); + if (!Common::Is4KBAligned(nrr_address)) { + LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", + nrr_address); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERROR_INVALID_ALIGNMENT); return; } // NRR Size is zero or causes overflow - if (nrr_addr + nrr_size <= nrr_addr || nrr_size == 0 || !Common::Is4KBAligned(nrr_size)) { + if (nrr_address + nrr_size <= nrr_address || nrr_size == 0 || + !Common::Is4KBAligned(nrr_size)) { LOG_ERROR(Service_LDR, "NRR Size is invalid! (nrr_address={:016X}, nrr_size={:016X})", - nrr_addr, nrr_size); + nrr_address, nrr_size); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERROR_INVALID_SIZE); return; } // Read NRR data from memory std::vector<u8> nrr_data(nrr_size); - Memory::ReadBlock(nrr_addr, nrr_data.data(), nrr_size); + Memory::ReadBlock(nrr_address, nrr_data.data(), nrr_size); NRRHeader header; std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader)); @@ -174,7 +182,7 @@ public: hashes.emplace_back(hash); } - nrr.insert_or_assign(nrr_addr, std::move(hashes)); + nrr.insert_or_assign(nrr_address, std::move(hashes)); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -188,23 +196,30 @@ public: return; } + struct Parameters { + u64_le process_id; + u64_le nrr_address; + }; + IPC::RequestParser rp{ctx}; - rp.Skip(2, false); - const auto nrr_addr{rp.Pop<VAddr>()}; - LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}", nrr_addr); + const auto [process_id, nrr_address] = rp.PopRaw<Parameters>(); + + LOG_DEBUG(Service_LDR, "called with process_id={:016X}, nrr_addr={:016X}", process_id, + nrr_address); - if (!Common::Is4KBAligned(nrr_addr)) { - LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr); + if (!Common::Is4KBAligned(nrr_address)) { + LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", + nrr_address); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERROR_INVALID_ALIGNMENT); return; } - const auto iter = nrr.find(nrr_addr); + const auto iter = nrr.find(nrr_address); if (iter == nrr.end()) { LOG_ERROR(Service_LDR, "Attempting to unload NRR which has not been loaded! (addr={:016X})", - nrr_addr); + nrr_address); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERROR_INVALID_NRR_ADDRESS); return; @@ -216,16 +231,22 @@ public: } void LoadNro(Kernel::HLERequestContext& ctx) { + struct Parameters { + u64_le process_id; + u64_le image_address; + u64_le image_size; + u64_le bss_address; + u64_le bss_size; + }; + IPC::RequestParser rp{ctx}; - rp.Skip(2, false); - const VAddr nro_addr{rp.Pop<VAddr>()}; - const u64 nro_size{rp.Pop<u64>()}; - const VAddr bss_addr{rp.Pop<VAddr>()}; - const u64 bss_size{rp.Pop<u64>()}; - LOG_DEBUG( - Service_LDR, - "called with nro_addr={:016X}, nro_size={:016X}, bss_addr={:016X}, bss_size={:016X}", - nro_addr, nro_size, bss_addr, bss_size); + const auto [process_id, nro_address, nro_size, bss_address, bss_size] = + rp.PopRaw<Parameters>(); + + LOG_DEBUG(Service_LDR, + "called with pid={:016X}, nro_addr={:016X}, nro_size={:016X}, bss_addr={:016X}, " + "bss_size={:016X}", + process_id, nro_address, nro_size, bss_address, bss_size); if (!initialized) { LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); @@ -243,8 +264,9 @@ public: } // NRO Address does not fall on 0x1000 byte boundary - if (!Common::Is4KBAligned(nro_addr)) { - LOG_ERROR(Service_LDR, "NRO Address has invalid alignment (actual {:016X})!", nro_addr); + if (!Common::Is4KBAligned(nro_address)) { + LOG_ERROR(Service_LDR, "NRO Address has invalid alignment (actual {:016X})!", + nro_address); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERROR_INVALID_ALIGNMENT); return; @@ -252,15 +274,15 @@ public: // NRO Size or BSS Size is zero or causes overflow const auto nro_size_valid = - nro_size != 0 && nro_addr + nro_size > nro_addr && Common::Is4KBAligned(nro_size); - const auto bss_size_valid = - nro_size + bss_size >= nro_size && (bss_size == 0 || bss_addr + bss_size > bss_addr); + nro_size != 0 && nro_address + nro_size > nro_address && Common::Is4KBAligned(nro_size); + const auto bss_size_valid = nro_size + bss_size >= nro_size && + (bss_size == 0 || bss_address + bss_size > bss_address); if (!nro_size_valid || !bss_size_valid) { LOG_ERROR(Service_LDR, "NRO Size or BSS Size is invalid! (nro_address={:016X}, nro_size={:016X}, " "bss_address={:016X}, bss_size={:016X})", - nro_addr, nro_size, bss_addr, bss_size); + nro_address, nro_size, bss_address, bss_size); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERROR_INVALID_SIZE); return; @@ -268,7 +290,7 @@ public: // Read NRO data from memory std::vector<u8> nro_data(nro_size); - Memory::ReadBlock(nro_addr, nro_data.data(), nro_size); + Memory::ReadBlock(nro_address, nro_data.data(), nro_size); SHA256Hash hash{}; mbedtls_sha256(nro_data.data(), nro_data.size(), hash.data(), 0); @@ -318,17 +340,18 @@ public: return; } - ASSERT(vm_manager - .MirrorMemory(*map_address, nro_addr, nro_size, Kernel::MemoryState::ModuleCode) - .IsSuccess()); - ASSERT(vm_manager.UnmapRange(nro_addr, nro_size).IsSuccess()); + ASSERT( + vm_manager + .MirrorMemory(*map_address, nro_address, nro_size, Kernel::MemoryState::ModuleCode) + .IsSuccess()); + ASSERT(vm_manager.UnmapRange(nro_address, nro_size).IsSuccess()); if (bss_size > 0) { ASSERT(vm_manager - .MirrorMemory(*map_address + nro_size, bss_addr, bss_size, + .MirrorMemory(*map_address + nro_size, bss_address, bss_size, Kernel::MemoryState::ModuleCode) .IsSuccess()); - ASSERT(vm_manager.UnmapRange(bss_addr, bss_size).IsSuccess()); + ASSERT(vm_manager.UnmapRange(bss_address, bss_size).IsSuccess()); } vm_manager.ReprotectRange(*map_address, header.text_size, @@ -348,13 +371,6 @@ public: } void UnloadNro(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - rp.Skip(2, false); - const VAddr mapped_addr{rp.PopRaw<VAddr>()}; - const VAddr heap_addr{rp.PopRaw<VAddr>()}; - LOG_DEBUG(Service_LDR, "called with mapped_addr={:016X}, heap_addr={:016X}", mapped_addr, - heap_addr); - if (!initialized) { LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); IPC::ResponseBuilder rb{ctx, 2}; @@ -362,22 +378,30 @@ public: return; } - if (!Common::Is4KBAligned(mapped_addr) || !Common::Is4KBAligned(heap_addr)) { - LOG_ERROR(Service_LDR, - "NRO/BSS Address has invalid alignment (actual nro_addr={:016X}, " - "bss_addr={:016X})!", - mapped_addr, heap_addr); + struct Parameters { + u64_le process_id; + u64_le nro_address; + }; + + IPC::RequestParser rp{ctx}; + const auto [process_id, nro_address] = rp.PopRaw<Parameters>(); + LOG_DEBUG(Service_LDR, "called with process_id={:016X}, nro_address=0x{:016X}", process_id, + nro_address); + + if (!Common::Is4KBAligned(nro_address)) { + LOG_ERROR(Service_LDR, "NRO address has invalid alignment (nro_address=0x{:016X})", + nro_address); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERROR_INVALID_ALIGNMENT); return; } - const auto iter = nro.find(mapped_addr); + const auto iter = nro.find(nro_address); if (iter == nro.end()) { LOG_ERROR(Service_LDR, - "The NRO attempting to unmap was not mapped or has an invalid address " - "(actual {:016X})!", - mapped_addr); + "The NRO attempting to be unmapped was not mapped or has an invalid address " + "(nro_address=0x{:016X})!", + nro_address); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERROR_INVALID_NRO_ADDRESS); return; @@ -386,10 +410,7 @@ public: auto& vm_manager = Core::CurrentProcess()->VMManager(); const auto& nro_size = iter->second.size; - ASSERT(vm_manager - .MirrorMemory(heap_addr, mapped_addr, nro_size, Kernel::MemoryState::ModuleCode) - .IsSuccess()); - ASSERT(vm_manager.UnmapRange(mapped_addr, nro_size).IsSuccess()); + ASSERT(vm_manager.UnmapRange(nro_address, nro_size).IsSuccess()); Core::System::GetInstance().InvalidateCpuInstructionCaches(); @@ -459,11 +480,10 @@ private: std::map<VAddr, NROInfo> nro; std::map<VAddr, std::vector<SHA256Hash>> nrr; - bool IsValidNROHash(const SHA256Hash& hash) { - return std::any_of( - nrr.begin(), nrr.end(), [&hash](const std::pair<VAddr, std::vector<SHA256Hash>>& p) { - return std::find(p.second.begin(), p.second.end(), hash) != p.second.end(); - }); + bool IsValidNROHash(const SHA256Hash& hash) const { + return std::any_of(nrr.begin(), nrr.end(), [&hash](const auto& p) { + return std::find(p.second.begin(), p.second.end(), hash) != p.second.end(); + }); } static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) { diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index c7f5bbf28..3c5c53e24 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -21,12 +21,13 @@ #include "core/hle/service/vi/display/vi_display.h" #include "core/hle/service/vi/layer/vi_layer.h" #include "core/perf_stats.h" +#include "core/settings.h" #include "video_core/renderer_base.h" namespace Service::NVFlinger { -constexpr std::size_t SCREEN_REFRESH_RATE = 60; -constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); +constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60); +constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 30); NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_timing} { displays.emplace_back(0, "Default"); @@ -36,13 +37,15 @@ NVFlinger::NVFlinger(Core::Timing::CoreTiming& core_timing) : core_timing{core_t displays.emplace_back(4, "Null"); // Schedule the screen composition events - composition_event = - core_timing.RegisterEvent("ScreenComposition", [this](u64 userdata, s64 cycles_late) { + const auto ticks = Settings::values.force_30fps_mode ? frame_ticks_30fps : frame_ticks; + + composition_event = core_timing.RegisterEvent( + "ScreenComposition", [this, ticks](u64 userdata, s64 cycles_late) { Compose(); - this->core_timing.ScheduleEvent(frame_ticks - cycles_late, composition_event); + this->core_timing.ScheduleEvent(ticks - cycles_late, composition_event); }); - core_timing.ScheduleEvent(frame_ticks, composition_event); + core_timing.ScheduleEvent(ticks, composition_event); } NVFlinger::~NVFlinger() { @@ -62,6 +65,7 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { const auto itr = std::find_if(displays.begin(), displays.end(), [&](const VI::Display& display) { return display.GetName() == name; }); + if (itr == displays.end()) { return {}; } diff --git a/src/core/settings.h b/src/core/settings.h index d543eb32f..b84390745 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -393,6 +393,7 @@ struct Values { bool use_disk_shader_cache; bool use_accurate_gpu_emulation; bool use_asynchronous_gpu_emulation; + bool force_30fps_mode; float bg_red; float bg_green; |