diff options
Diffstat (limited to '')
28 files changed, 886 insertions, 253 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b31a0328c..66497a386 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -131,8 +131,6 @@ add_library(core STATIC frontend/framebuffer_layout.cpp frontend/framebuffer_layout.h frontend/input.h - frontend/scope_acquire_context.cpp - frontend/scope_acquire_context.h gdbstub/gdbstub.cpp gdbstub/gdbstub.h hardware_interrupt_manager.cpp @@ -287,6 +285,18 @@ add_library(core STATIC hle/service/btm/btm.h hle/service/caps/caps.cpp hle/service/caps/caps.h + hle/service/caps/caps_a.cpp + hle/service/caps/caps_a.h + hle/service/caps/caps_c.cpp + hle/service/caps/caps_c.h + hle/service/caps/caps_u.cpp + hle/service/caps/caps_u.h + hle/service/caps/caps_sc.cpp + hle/service/caps/caps_sc.h + hle/service/caps/caps_ss.cpp + hle/service/caps/caps_ss.h + hle/service/caps/caps_su.cpp + hle/service/caps/caps_su.h hle/service/erpt/erpt.cpp hle/service/erpt/erpt.h hle/service/es/es.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index d1bc9340d..3bd90d79f 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -24,7 +24,6 @@ #include "core/file_sys/sdmc_factory.h" #include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_real.h" -#include "core/frontend/scope_acquire_context.h" #include "core/gdbstub/gdbstub.h" #include "core/hardware_interrupt_manager.h" #include "core/hle/kernel/client_port.h" @@ -168,13 +167,12 @@ struct System::Impl { Service::Init(service_manager, system); GDBStub::DeferStart(); - renderer = VideoCore::CreateRenderer(emu_window, system); - if (!renderer->Init()) { + interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system); + gpu_core = VideoCore::CreateGPU(emu_window, system); + if (!gpu_core) { return ResultStatus::ErrorVideoCore; } - interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system); - gpu_core = VideoCore::CreateGPU(system); - renderer->Rasterizer().SetupDirtyFlags(); + gpu_core->Renderer().Rasterizer().SetupDirtyFlags(); is_powered_on = true; exit_lock = false; @@ -186,8 +184,6 @@ struct System::Impl { ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath) { - Core::Frontend::ScopeAcquireContext acquire_context{emu_window}; - app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); if (!app_loader) { LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); @@ -216,10 +212,6 @@ struct System::Impl { AddGlueRegistrationForProcess(*app_loader, *main_process); kernel.MakeCurrentProcess(main_process.get()); - // Main process has been loaded and been made current. - // Begin GPU and CPU execution. - gpu_core->Start(); - // Initialize cheat engine if (cheat_engine) { cheat_engine->Initialize(); @@ -277,7 +269,6 @@ struct System::Impl { } // Shutdown emulation session - renderer.reset(); GDBStub::Shutdown(); Service::Shutdown(); service_manager.reset(); @@ -353,7 +344,6 @@ struct System::Impl { Service::FileSystem::FileSystemController fs_controller; /// AppLoader used to load the current executing application std::unique_ptr<Loader::AppLoader> app_loader; - std::unique_ptr<VideoCore::RendererBase> renderer; std::unique_ptr<Tegra::GPU> gpu_core; std::unique_ptr<Hardware::InterruptManager> interrupt_manager; Memory::Memory memory; @@ -536,11 +526,11 @@ const Core::Hardware::InterruptManager& System::InterruptManager() const { } VideoCore::RendererBase& System::Renderer() { - return *impl->renderer; + return impl->gpu_core->Renderer(); } const VideoCore::RendererBase& System::Renderer() const { - return *impl->renderer; + return impl->gpu_core->Renderer(); } Kernel::KernelCore& System::Kernel() { diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp index c909d1ce4..120032134 100644 --- a/src/core/file_sys/romfs.cpp +++ b/src/core/file_sys/romfs.cpp @@ -5,6 +5,7 @@ #include <memory> #include "common/common_types.h" +#include "common/string_util.h" #include "common/swap.h" #include "core/file_sys/fsmitm_romfsbuild.h" #include "core/file_sys/romfs.h" @@ -126,7 +127,7 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) { return out->GetSubdirectories().front(); while (out->GetSubdirectories().size() == 1 && out->GetFiles().empty()) { - if (out->GetSubdirectories().front()->GetName() == "data" && + if (Common::ToLower(out->GetSubdirectories().front()->GetName()) == "data" && type == RomFSExtractionType::Truncated) break; out = out->GetSubdirectories().front(); diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 5eb87fb63..13aa14934 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -12,20 +12,49 @@ namespace Core::Frontend { +/// Information for the Graphics Backends signifying what type of screen pointer is in +/// WindowInformation +enum class WindowSystemType { + Headless, + Windows, + X11, + Wayland, +}; + /** - * 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 + * Represents a drawing context that supports graphics operations. */ class GraphicsContext { public: virtual ~GraphicsContext(); + /// Inform the driver to swap the front/back buffers and present the current image + virtual void SwapBuffers() {} + /// Makes the graphics context current for the caller thread - virtual void MakeCurrent() = 0; + virtual void MakeCurrent() {} /// Releases (dunno if this is the "right" word) the context from the caller thread - virtual void DoneCurrent() = 0; + virtual void DoneCurrent() {} + + class Scoped { + public: + explicit Scoped(GraphicsContext& context_) : context(context_) { + context.MakeCurrent(); + } + ~Scoped() { + context.DoneCurrent(); + } + + private: + GraphicsContext& context; + }; + + /// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value + /// ends + Scoped Acquire() { + return Scoped{*this}; + } }; /** @@ -46,7 +75,7 @@ public: * - 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 : public GraphicsContext { +class EmuWindow { public: /// Data structure to store emuwindow configuration struct WindowConfig { @@ -56,29 +85,34 @@ public: std::pair<unsigned, unsigned> min_client_area_size; }; + /// Data describing host window system information + struct WindowSystemInfo { + // Window system type. Determines which GL context or Vulkan WSI is used. + WindowSystemType type = WindowSystemType::Headless; + + // Connection to a display server. This is used on X11 and Wayland platforms. + void* display_connection = nullptr; + + // Render surface. This is a pointer to the native window handle, which depends + // on the platform. e.g. HWND for Windows, Window for X11. If the surface is + // set to nullptr, the video backend will run in headless mode. + void* render_surface = nullptr; + + // Scale of the render surface. For hidpi systems, this will be >1. + float render_surface_scale = 1.0f; + }; + /// Polls window events virtual void PollEvents() = 0; /** - * 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 + * Returns a GraphicsContext that the frontend provides to be used for rendering. */ - virtual std::unique_ptr<GraphicsContext> CreateSharedContext() const { - return nullptr; - } + virtual std::unique_ptr<GraphicsContext> CreateSharedContext() const = 0; /// Returns if window is shown (not minimized) virtual bool IsShown() const = 0; - /// Retrieves Vulkan specific handlers from the window - virtual void RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance, - void* surface) const = 0; - /** * Signal that a touch pressed event has occurred (e.g. mouse click pressed) * @param framebuffer_x Framebuffer x-coordinate that was pressed @@ -116,6 +150,13 @@ public: } /** + * Returns system information about the drawing area. + */ + const WindowSystemInfo& GetWindowInfo() const { + return window_info; + } + + /** * Gets the framebuffer layout (width, height, and screen regions) * @note This method is thread-safe */ @@ -130,7 +171,7 @@ public: void UpdateCurrentFramebufferLayout(unsigned width, unsigned height); protected: - EmuWindow(); + explicit EmuWindow(); virtual ~EmuWindow(); /** @@ -167,6 +208,8 @@ protected: client_area_height = size.second; } + WindowSystemInfo window_info; + private: /** * Handler called when the minimal client area was requested to be changed via SetConfig. diff --git a/src/core/frontend/scope_acquire_context.cpp b/src/core/frontend/scope_acquire_context.cpp deleted file mode 100644 index 878c3157c..000000000 --- a/src/core/frontend/scope_acquire_context.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/frontend/emu_window.h" -#include "core/frontend/scope_acquire_context.h" - -namespace Core::Frontend { - -ScopeAcquireContext::ScopeAcquireContext(Core::Frontend::GraphicsContext& context) - : context{context} { - context.MakeCurrent(); -} -ScopeAcquireContext::~ScopeAcquireContext() { - context.DoneCurrent(); -} - -} // namespace Core::Frontend diff --git a/src/core/frontend/scope_acquire_context.h b/src/core/frontend/scope_acquire_context.h deleted file mode 100644 index 7a65c0623..000000000 --- a/src/core/frontend/scope_acquire_context.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_types.h" - -namespace Core::Frontend { - -class GraphicsContext; - -/// Helper class to acquire/release window context within a given scope -class ScopeAcquireContext : NonCopyable { -public: - explicit ScopeAcquireContext(Core::Frontend::GraphicsContext& context); - ~ScopeAcquireContext(); - -private: - Core::Frontend::GraphicsContext& context; -}; - -} // namespace Core::Frontend diff --git a/src/core/hle/service/caps/caps.cpp b/src/core/hle/service/caps/caps.cpp index 907f464ab..26c8a7081 100644 --- a/src/core/hle/service/caps/caps.cpp +++ b/src/core/hle/service/caps/caps.cpp @@ -2,168 +2,24 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <memory> - #include "core/hle/service/caps/caps.h" +#include "core/hle/service/caps/caps_a.h" +#include "core/hle/service/caps/caps_c.h" +#include "core/hle/service/caps/caps_sc.h" +#include "core/hle/service/caps/caps_ss.h" +#include "core/hle/service/caps/caps_su.h" +#include "core/hle/service/caps/caps_u.h" #include "core/hle/service/service.h" -#include "core/hle/service/sm/sm.h" namespace Service::Capture { -class CAPS_A final : public ServiceFramework<CAPS_A> { -public: - explicit CAPS_A() : ServiceFramework{"caps:a"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "GetAlbumFileCount"}, - {1, nullptr, "GetAlbumFileList"}, - {2, nullptr, "LoadAlbumFile"}, - {3, nullptr, "DeleteAlbumFile"}, - {4, nullptr, "StorageCopyAlbumFile"}, - {5, nullptr, "IsAlbumMounted"}, - {6, nullptr, "GetAlbumUsage"}, - {7, nullptr, "GetAlbumFileSize"}, - {8, nullptr, "LoadAlbumFileThumbnail"}, - {9, nullptr, "LoadAlbumScreenShotImage"}, - {10, nullptr, "LoadAlbumScreenShotThumbnailImage"}, - {11, nullptr, "GetAlbumEntryFromApplicationAlbumEntry"}, - {12, nullptr, "Unknown12"}, - {13, nullptr, "Unknown13"}, - {14, nullptr, "Unknown14"}, - {15, nullptr, "Unknown15"}, - {16, nullptr, "Unknown16"}, - {17, nullptr, "Unknown17"}, - {18, nullptr, "Unknown18"}, - {202, nullptr, "SaveEditedScreenShot"}, - {301, nullptr, "GetLastThumbnail"}, - {401, nullptr, "GetAutoSavingStorage"}, - {501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"}, - {1001, nullptr, "Unknown1001"}, - {1002, nullptr, "Unknown1002"}, - {1003, nullptr, "Unknown1003"}, - {8001, nullptr, "ForceAlbumUnmounted"}, - {8002, nullptr, "ResetAlbumMountStatus"}, - {8011, nullptr, "RefreshAlbumCache"}, - {8012, nullptr, "GetAlbumCache"}, - {8013, nullptr, "Unknown8013"}, - {8021, nullptr, "GetAlbumEntryFromApplicationAlbumEntryAruid"}, - {10011, nullptr, "SetInternalErrorConversionEnabled"}, - {50000, nullptr, "Unknown50000"}, - {60002, nullptr, "Unknown60002"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class CAPS_C final : public ServiceFramework<CAPS_C> { -public: - explicit CAPS_C() : ServiceFramework{"caps:c"} { - // clang-format off - static const FunctionInfo functions[] = { - {33, nullptr, "Unknown33"}, - {2001, nullptr, "Unknown2001"}, - {2002, nullptr, "Unknown2002"}, - {2011, nullptr, "Unknown2011"}, - {2012, nullptr, "Unknown2012"}, - {2013, nullptr, "Unknown2013"}, - {2014, nullptr, "Unknown2014"}, - {2101, nullptr, "Unknown2101"}, - {2102, nullptr, "Unknown2102"}, - {2201, nullptr, "Unknown2201"}, - {2301, nullptr, "Unknown2301"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class CAPS_SC final : public ServiceFramework<CAPS_SC> { -public: - explicit CAPS_SC() : ServiceFramework{"caps:sc"} { - // clang-format off - static const FunctionInfo functions[] = { - {1, nullptr, "Unknown1"}, - {2, nullptr, "Unknown2"}, - {1001, nullptr, "Unknown3"}, - {1002, nullptr, "Unknown4"}, - {1003, nullptr, "Unknown5"}, - {1011, nullptr, "Unknown6"}, - {1012, nullptr, "Unknown7"}, - {1201, nullptr, "Unknown8"}, - {1202, nullptr, "Unknown9"}, - {1203, nullptr, "Unknown10"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class CAPS_SS final : public ServiceFramework<CAPS_SS> { -public: - explicit CAPS_SS() : ServiceFramework{"caps:ss"} { - // clang-format off - static const FunctionInfo functions[] = { - {201, nullptr, "Unknown1"}, - {202, nullptr, "Unknown2"}, - {203, nullptr, "Unknown3"}, - {204, nullptr, "Unknown4"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class CAPS_SU final : public ServiceFramework<CAPS_SU> { -public: - explicit CAPS_SU() : ServiceFramework{"caps:su"} { - // clang-format off - static const FunctionInfo functions[] = { - {201, nullptr, "SaveScreenShot"}, - {203, nullptr, "SaveScreenShotEx0"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - -class CAPS_U final : public ServiceFramework<CAPS_U> { -public: - explicit CAPS_U() : ServiceFramework{"caps:u"} { - // clang-format off - static const FunctionInfo functions[] = { - {32, nullptr, "SetShimLibraryVersion"}, - {102, nullptr, "GetAlbumFileListByAruid"}, - {103, nullptr, "DeleteAlbumFileByAruid"}, - {104, nullptr, "GetAlbumFileSizeByAruid"}, - {105, nullptr, "DeleteAlbumFileByAruidForDebug"}, - {110, nullptr, "LoadAlbumScreenShotImageByAruid"}, - {120, nullptr, "LoadAlbumScreenShotThumbnailImageByAruid"}, - {130, nullptr, "PrecheckToCreateContentsByAruid"}, - {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"}, - {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, - {142, nullptr, "GetAlbumFileList3AaeAruid"}, - {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, - {60002, nullptr, "OpenAccessorSessionForApplication"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - void InstallInterfaces(SM::ServiceManager& sm) { std::make_shared<CAPS_A>()->InstallAsService(sm); std::make_shared<CAPS_C>()->InstallAsService(sm); + std::make_shared<CAPS_U>()->InstallAsService(sm); std::make_shared<CAPS_SC>()->InstallAsService(sm); std::make_shared<CAPS_SS>()->InstallAsService(sm); std::make_shared<CAPS_SU>()->InstallAsService(sm); - std::make_shared<CAPS_U>()->InstallAsService(sm); } } // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps.h b/src/core/hle/service/caps/caps.h index 471185dfa..fc70a4c27 100644 --- a/src/core/hle/service/caps/caps.h +++ b/src/core/hle/service/caps/caps.h @@ -4,12 +4,83 @@ #pragma once +#include "core/hle/service/service.h" + namespace Service::SM { class ServiceManager; } namespace Service::Capture { +enum AlbumImageOrientation { + Orientation0 = 0, + Orientation1 = 1, + Orientation2 = 2, + Orientation3 = 3, +}; + +enum AlbumReportOption { + Disable = 0, + Enable = 1, +}; + +enum ContentType : u8 { + Screenshot = 0, + Movie = 1, + ExtraMovie = 3, +}; + +enum AlbumStorage : u8 { + NAND = 0, + SD = 1, +}; + +struct AlbumFileDateTime { + u16 year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; + u8 uid; +}; + +struct AlbumEntry { + u64 size; + u64 application_id; + AlbumFileDateTime datetime; + AlbumStorage storage; + ContentType content; + u8 padding[6]; +}; + +struct AlbumFileEntry { + u64 size; + u64 hash; + AlbumFileDateTime datetime; + AlbumStorage storage; + ContentType content; + u8 padding[5]; + u8 unknown; +}; + +struct ApplicationAlbumEntry { + u64 size; + u64 hash; + AlbumFileDateTime datetime; + AlbumStorage storage; + ContentType content; + u8 padding[5]; + u8 unknown; +}; + +struct ApplicationAlbumFileEntry { + ApplicationAlbumEntry entry; + AlbumFileDateTime datetime; + u64 unknown; +}; + +/// Registers all Capture services with the specified service manager. void InstallInterfaces(SM::ServiceManager& sm); } // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp new file mode 100644 index 000000000..88a3fdc05 --- /dev/null +++ b/src/core/hle/service/caps/caps_a.cpp @@ -0,0 +1,78 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/caps/caps_a.h" + +namespace Service::Capture { + +class IAlbumAccessorSession final : public ServiceFramework<IAlbumAccessorSession> { +public: + explicit IAlbumAccessorSession() : ServiceFramework{"IAlbumAccessorSession"} { + // clang-format off + static const FunctionInfo functions[] = { + {2001, nullptr, "OpenAlbumMovieReadStream"}, + {2002, nullptr, "CloseAlbumMovieReadStream"}, + {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"}, + {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"}, + {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"}, + {2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"}, + {2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"}, + {2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +CAPS_A::CAPS_A() : ServiceFramework("caps:a") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetAlbumFileCount"}, + {1, nullptr, "GetAlbumFileList"}, + {2, nullptr, "LoadAlbumFile"}, + {3, nullptr, "DeleteAlbumFile"}, + {4, nullptr, "StorageCopyAlbumFile"}, + {5, nullptr, "IsAlbumMounted"}, + {6, nullptr, "GetAlbumUsage"}, + {7, nullptr, "GetAlbumFileSize"}, + {8, nullptr, "LoadAlbumFileThumbnail"}, + {9, nullptr, "LoadAlbumScreenShotImage"}, + {10, nullptr, "LoadAlbumScreenShotThumbnailImage"}, + {11, nullptr, "GetAlbumEntryFromApplicationAlbumEntry"}, + {12, nullptr, "LoadAlbumScreenShotImageEx"}, + {13, nullptr, "LoadAlbumScreenShotThumbnailImageEx"}, + {14, nullptr, "LoadAlbumScreenShotImageEx0"}, + {15, nullptr, "GetAlbumUsage3"}, + {16, nullptr, "GetAlbumMountResult"}, + {17, nullptr, "GetAlbumUsage16"}, + {18, nullptr, "Unknown18"}, + {100, nullptr, "GetAlbumFileCountEx0"}, + {101, nullptr, "GetAlbumFileListEx0"}, + {202, nullptr, "SaveEditedScreenShot"}, + {301, nullptr, "GetLastThumbnail"}, + {302, nullptr, "GetLastOverlayMovieThumbnail"}, + {401, nullptr, "GetAutoSavingStorage"}, + {501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"}, + {1001, nullptr, "LoadAlbumScreenShotThumbnailImageEx0"}, + {1002, nullptr, "LoadAlbumScreenShotImageEx1"}, + {1003, nullptr, "LoadAlbumScreenShotThumbnailImageEx1"}, + {8001, nullptr, "ForceAlbumUnmounted"}, + {8002, nullptr, "ResetAlbumMountStatus"}, + {8011, nullptr, "RefreshAlbumCache"}, + {8012, nullptr, "GetAlbumCache"}, + {8013, nullptr, "GetAlbumCacheEx"}, + {8021, nullptr, "GetAlbumEntryFromApplicationAlbumEntryAruid"}, + {10011, nullptr, "SetInternalErrorConversionEnabled"}, + {50000, nullptr, "LoadMakerNoteInfoForDebug"}, + {60002, nullptr, "OpenAccessorSession"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +CAPS_A::~CAPS_A() = default; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_a.h b/src/core/hle/service/caps/caps_a.h new file mode 100644 index 000000000..8de832491 --- /dev/null +++ b/src/core/hle/service/caps/caps_a.h @@ -0,0 +1,21 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::Capture { + +class CAPS_A final : public ServiceFramework<CAPS_A> { +public: + explicit CAPS_A(); + ~CAPS_A() override; +}; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_c.cpp b/src/core/hle/service/caps/caps_c.cpp new file mode 100644 index 000000000..ea6452ffa --- /dev/null +++ b/src/core/hle/service/caps/caps_c.cpp @@ -0,0 +1,75 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/caps/caps_c.h" + +namespace Service::Capture { + +class IAlbumControlSession final : public ServiceFramework<IAlbumControlSession> { +public: + explicit IAlbumControlSession() : ServiceFramework{"IAlbumControlSession"} { + // clang-format off + static const FunctionInfo functions[] = { + {2001, nullptr, "OpenAlbumMovieReadStream"}, + {2002, nullptr, "CloseAlbumMovieReadStream"}, + {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"}, + {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"}, + {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"}, + {2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"}, + {2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"}, + {2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"}, + {2401, nullptr, "OpenAlbumMovieWriteStream"}, + {2402, nullptr, "FinishAlbumMovieWriteStream"}, + {2403, nullptr, "CommitAlbumMovieWriteStream"}, + {2404, nullptr, "DiscardAlbumMovieWriteStream"}, + {2405, nullptr, "DiscardAlbumMovieWriteStreamNoDelete"}, + {2406, nullptr, "CommitAlbumMovieWriteStreamEx"}, + {2411, nullptr, "StartAlbumMovieWriteStreamDataSection"}, + {2412, nullptr, "EndAlbumMovieWriteStreamDataSection"}, + {2413, nullptr, "StartAlbumMovieWriteStreamMetaSection"}, + {2414, nullptr, "EndAlbumMovieWriteStreamMetaSection"}, + {2421, nullptr, "ReadDataFromAlbumMovieWriteStream"}, + {2422, nullptr, "WriteDataToAlbumMovieWriteStream"}, + {2424, nullptr, "WriteMetaToAlbumMovieWriteStream"}, + {2431, nullptr, "GetAlbumMovieWriteStreamBrokenReason"}, + {2433, nullptr, "GetAlbumMovieWriteStreamDataSize"}, + {2434, nullptr, "SetAlbumMovieWriteStreamDataSize"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +CAPS_C::CAPS_C() : ServiceFramework("caps:c") { + // clang-format off + static const FunctionInfo functions[] = { + {1, nullptr, "CaptureRawImage"}, + {2, nullptr, "CaptureRawImageWithTimeout"}, + {33, nullptr, "Unknown33"}, + {1001, nullptr, "RequestTakingScreenShot"}, + {1002, nullptr, "RequestTakingScreenShotWithTimeout"}, + {1011, nullptr, "NotifyTakingScreenShotRefused"}, + {2001, nullptr, "NotifyAlbumStorageIsAvailable"}, + {2002, nullptr, "NotifyAlbumStorageIsUnavailable"}, + {2011, nullptr, "RegisterAppletResourceUserId"}, + {2012, nullptr, "UnregisterAppletResourceUserId"}, + {2013, nullptr, "GetApplicationIdFromAruid"}, + {2014, nullptr, "CheckApplicationIdRegistered"}, + {2101, nullptr, "GenerateCurrentAlbumFileId"}, + {2102, nullptr, "GenerateApplicationAlbumEntry"}, + {2201, nullptr, "SaveAlbumScreenShotFile"}, + {2202, nullptr, "SaveAlbumScreenShotFileEx"}, + {2301, nullptr, "SetOverlayScreenShotThumbnailData"}, + {2302, nullptr, "SetOverlayMovieThumbnailData"}, + {60001, nullptr, "OpenControlSession"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +CAPS_C::~CAPS_C() = default; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_c.h b/src/core/hle/service/caps/caps_c.h new file mode 100644 index 000000000..d07cdb441 --- /dev/null +++ b/src/core/hle/service/caps/caps_c.h @@ -0,0 +1,21 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::Capture { + +class CAPS_C final : public ServiceFramework<CAPS_C> { +public: + explicit CAPS_C(); + ~CAPS_C() override; +}; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_sc.cpp b/src/core/hle/service/caps/caps_sc.cpp new file mode 100644 index 000000000..d01a8a58e --- /dev/null +++ b/src/core/hle/service/caps/caps_sc.cpp @@ -0,0 +1,40 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/caps/caps_sc.h" + +namespace Service::Capture { + +CAPS_SC::CAPS_SC() : ServiceFramework("caps:sc") { + // clang-format off + static const FunctionInfo functions[] = { + {1, nullptr, "CaptureRawImage"}, + {2, nullptr, "CaptureRawImageWithTimeout"}, + {3, nullptr, "AttachSharedBuffer"}, + {5, nullptr, "CaptureRawImageToAttachedSharedBuffer"}, + {210, nullptr, "Unknown210"}, + {1001, nullptr, "RequestTakingScreenShot"}, + {1002, nullptr, "RequestTakingScreenShotWithTimeout"}, + {1003, nullptr, "RequestTakingScreenShotEx"}, + {1004, nullptr, "RequestTakingScreenShotEx1"}, + {1009, nullptr, "CancelTakingScreenShot"}, + {1010, nullptr, "SetTakingScreenShotCancelState"}, + {1011, nullptr, "NotifyTakingScreenShotRefused"}, + {1012, nullptr, "NotifyTakingScreenShotFailed"}, + {1101, nullptr, "SetupOverlayMovieThumbnail"}, + {1106, nullptr, "Unknown1106"}, + {1107, nullptr, "Unknown1107"}, + {1201, nullptr, "OpenRawScreenShotReadStream"}, + {1202, nullptr, "CloseRawScreenShotReadStream"}, + {1203, nullptr, "ReadRawScreenShotReadStream"}, + {1204, nullptr, "Unknown1204"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +CAPS_SC::~CAPS_SC() = default; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_sc.h b/src/core/hle/service/caps/caps_sc.h new file mode 100644 index 000000000..9ba372f7a --- /dev/null +++ b/src/core/hle/service/caps/caps_sc.h @@ -0,0 +1,21 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::Capture { + +class CAPS_SC final : public ServiceFramework<CAPS_SC> { +public: + explicit CAPS_SC(); + ~CAPS_SC() override; +}; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_ss.cpp b/src/core/hle/service/caps/caps_ss.cpp new file mode 100644 index 000000000..eaa3a7494 --- /dev/null +++ b/src/core/hle/service/caps/caps_ss.cpp @@ -0,0 +1,26 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/caps/caps_ss.h" + +namespace Service::Capture { + +CAPS_SS::CAPS_SS() : ServiceFramework("caps:ss") { + // clang-format off + static const FunctionInfo functions[] = { + {201, nullptr, "SaveScreenShot"}, + {202, nullptr, "SaveEditedScreenShot"}, + {203, nullptr, "SaveScreenShotEx0"}, + {204, nullptr, "SaveEditedScreenShotEx0"}, + {206, nullptr, "Unknown206"}, + {208, nullptr, "SaveScreenShotOfMovieEx1"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +CAPS_SS::~CAPS_SS() = default; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_ss.h b/src/core/hle/service/caps/caps_ss.h new file mode 100644 index 000000000..e258a6925 --- /dev/null +++ b/src/core/hle/service/caps/caps_ss.h @@ -0,0 +1,21 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::Capture { + +class CAPS_SS final : public ServiceFramework<CAPS_SS> { +public: + explicit CAPS_SS(); + ~CAPS_SS() override; +}; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp new file mode 100644 index 000000000..2b4c2d808 --- /dev/null +++ b/src/core/hle/service/caps/caps_su.cpp @@ -0,0 +1,22 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/caps/caps_su.h" + +namespace Service::Capture { + +CAPS_SU::CAPS_SU() : ServiceFramework("caps:su") { + // clang-format off + static const FunctionInfo functions[] = { + {201, nullptr, "SaveScreenShot"}, + {203, nullptr, "SaveScreenShotEx0"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +CAPS_SU::~CAPS_SU() = default; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_su.h b/src/core/hle/service/caps/caps_su.h new file mode 100644 index 000000000..cb11f7c9a --- /dev/null +++ b/src/core/hle/service/caps/caps_su.h @@ -0,0 +1,21 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::Capture { + +class CAPS_SU final : public ServiceFramework<CAPS_SU> { +public: + explicit CAPS_SU(); + ~CAPS_SU() override; +}; + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp new file mode 100644 index 000000000..78bab6ed8 --- /dev/null +++ b/src/core/hle/service/caps/caps_u.cpp @@ -0,0 +1,76 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/caps/caps.h" +#include "core/hle/service/caps/caps_u.h" + +namespace Service::Capture { + +class IAlbumAccessorApplicationSession final + : public ServiceFramework<IAlbumAccessorApplicationSession> { +public: + explicit IAlbumAccessorApplicationSession() + : ServiceFramework{"IAlbumAccessorApplicationSession"} { + // clang-format off + static const FunctionInfo functions[] = { + {2001, nullptr, "OpenAlbumMovieReadStream"}, + {2002, nullptr, "CloseAlbumMovieReadStream"}, + {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"}, + {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"}, + {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +CAPS_U::CAPS_U() : ServiceFramework("caps:u") { + // clang-format off + static const FunctionInfo functions[] = { + {31, nullptr, "GetShimLibraryVersion"}, + {32, nullptr, "SetShimLibraryVersion"}, + {102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"}, + {103, nullptr, "DeleteAlbumContentsFileForApplication"}, + {104, nullptr, "GetAlbumContentsFileSizeForApplication"}, + {105, nullptr, "DeleteAlbumFileByAruidForDebug"}, + {110, nullptr, "LoadAlbumContentsFileScreenShotImageForApplication"}, + {120, nullptr, "LoadAlbumContentsFileThumbnailImageForApplication"}, + {130, nullptr, "PrecheckToCreateContentsForApplication"}, + {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"}, + {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, + {142, nullptr, "GetAlbumFileList3AaeAruid"}, + {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, + {60002, nullptr, "OpenAccessorSessionForApplication"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +CAPS_U::~CAPS_U() = default; + +void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx) { + // Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an + // u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total + // output entries (which is copied to a s32 by official SW). + IPC::RequestParser rp{ctx}; + [[maybe_unused]] const auto application_album_file_entries = rp.PopRaw<std::array<u8, 0x30>>(); + const auto pid = rp.Pop<s32>(); + const auto content_type = rp.PopRaw<ContentType>(); + [[maybe_unused]] const auto start_datetime = rp.PopRaw<AlbumFileDateTime>(); + [[maybe_unused]] const auto end_datetime = rp.PopRaw<AlbumFileDateTime>(); + const auto applet_resource_user_id = rp.Pop<u64>(); + LOG_WARNING(Service_Capture, + "(STUBBED) called. pid={}, content_type={}, applet_resource_user_id={}", pid, + content_type, applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<s32>(0); +} + +} // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_u.h b/src/core/hle/service/caps/caps_u.h new file mode 100644 index 000000000..e6e0716ff --- /dev/null +++ b/src/core/hle/service/caps/caps_u.h @@ -0,0 +1,24 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Kernel { +class HLERequestContext; +} + +namespace Service::Capture { + +class CAPS_U final : public ServiceFramework<CAPS_U> { +public: + explicit CAPS_U(); + ~CAPS_U() override; + +private: + void GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx); +}; + +} // namespace Service::Capture diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 157aeec88..647943020 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -342,17 +342,27 @@ public: return; } - ASSERT( - vm_manager - .MirrorMemory(*map_address, nro_address, nro_size, Kernel::MemoryState::ModuleCode) - .IsSuccess()); + // Mark text and read-only region as ModuleCode + ASSERT(vm_manager + .MirrorMemory(*map_address, nro_address, header.text_size + header.ro_size, + Kernel::MemoryState::ModuleCode) + .IsSuccess()); + // Mark read/write region as ModuleCodeData, which is necessary if this region is used for + // TransferMemory (e.g. Final Fantasy VIII Remastered does this) + ASSERT(vm_manager + .MirrorMemory(*map_address + header.rw_offset, nro_address + header.rw_offset, + header.rw_size, Kernel::MemoryState::ModuleCodeData) + .IsSuccess()); + // Revoke permissions from the old memory region ASSERT(vm_manager.ReprotectRange(nro_address, nro_size, Kernel::VMAPermission::None) .IsSuccess()); if (bss_size > 0) { + // Mark BSS region as ModuleCodeData, which is necessary if this region is used for + // TransferMemory (e.g. Final Fantasy VIII Remastered does this) ASSERT(vm_manager .MirrorMemory(*map_address + nro_size, bss_address, bss_size, - Kernel::MemoryState::ModuleCode) + Kernel::MemoryState::ModuleCodeData) .IsSuccess()); ASSERT(vm_manager.ReprotectRange(bss_address, bss_size, Kernel::VMAPermission::None) .IsSuccess()); diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 32b6f4b27..9bcafa5fc 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp @@ -28,6 +28,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) buffer.slot = slot; buffer.igbp_buffer = igbp_buffer; buffer.status = Buffer::Status::Free; + free_buffers.push_back(slot); queue.emplace_back(buffer); buffer_wait_event.writable->Signal(); @@ -35,16 +36,37 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width, u32 height) { - auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { - // Only consider free buffers. Buffers become free once again after they've been Acquired - // and Released by the compositor, see the NVFlinger::Compose method. - if (buffer.status != Buffer::Status::Free) { - return false; - } - // Make sure that the parameters match. - return buffer.igbp_buffer.width == width && buffer.igbp_buffer.height == height; - }); + if (free_buffers.empty()) { + return {}; + } + + auto f_itr = free_buffers.begin(); + auto itr = queue.end(); + + while (f_itr != free_buffers.end()) { + auto slot = *f_itr; + itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { + // Only consider free buffers. Buffers become free once again after they've been + // Acquired and Released by the compositor, see the NVFlinger::Compose method. + if (buffer.status != Buffer::Status::Free) { + return false; + } + + if (buffer.slot != slot) { + return false; + } + + // Make sure that the parameters match. + return buffer.igbp_buffer.width == width && buffer.igbp_buffer.height == height; + }); + + if (itr != queue.end()) { + free_buffers.erase(f_itr); + break; + } + ++f_itr; + } if (itr == queue.end()) { return {}; @@ -99,6 +121,7 @@ void BufferQueue::ReleaseBuffer(u32 slot) { ASSERT(itr != queue.end()); ASSERT(itr->status == Buffer::Status::Acquired); itr->status = Buffer::Status::Free; + free_buffers.push_back(slot); buffer_wait_event.writable->Signal(); } diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index f4bbfd945..f674823b0 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h @@ -101,6 +101,7 @@ private: u32 id; u64 layer_id; + std::list<u32> free_buffers; std::vector<Buffer> queue; std::list<u32> queue_sequence; Kernel::EventPair buffer_wait_event; diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp index 1660bbdb8..f509653a3 100644 --- a/src/core/hle/service/time/interface.cpp +++ b/src/core/hle/service/time/interface.cpp @@ -30,7 +30,7 @@ Time::Time(std::shared_ptr<Module> module, Core::System& system, const char* nam {400, &Time::GetClockSnapshot, "GetClockSnapshot"}, {401, &Time::GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"}, {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"}, - {501, nullptr, "CalculateSpanBetween"}, + {501, &Time::CalculateSpanBetween, "CalculateSpanBetween"}, }; // clang-format on diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 749b7be70..ce859f18d 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -308,6 +308,35 @@ void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLEReques ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot)); } +void Module::Interface::CalculateSpanBetween(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called"); + + IPC::RequestParser rp{ctx}; + const auto snapshot_a = rp.PopRaw<Clock::ClockSnapshot>(); + const auto snapshot_b = rp.PopRaw<Clock::ClockSnapshot>(); + + Clock::TimeSpanType time_span_type{}; + s64 span{}; + if (const ResultCode result{snapshot_a.steady_clock_time_point.GetSpanBetween( + snapshot_b.steady_clock_time_point, span)}; + result != RESULT_SUCCESS) { + if (snapshot_a.network_time && snapshot_b.network_time) { + time_span_type = + Clock::TimeSpanType::FromSeconds(snapshot_b.network_time - snapshot_a.network_time); + } else { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_TIME_NOT_FOUND); + return; + } + } else { + time_span_type = Clock::TimeSpanType::FromSeconds(span); + } + + IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw(time_span_type.nanoseconds); +} + void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Time, "called"); IPC::ResponseBuilder rb{ctx, 2, 1}; diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index aadc2df60..351988468 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h @@ -32,6 +32,7 @@ public: void CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx); void GetClockSnapshot(Kernel::HLERequestContext& ctx); void GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx); + void CalculateSpanBetween(Kernel::HLERequestContext& ctx); void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx); private: diff --git a/src/core/memory.cpp b/src/core/memory.cpp index f0888327f..6061d37ae 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -242,7 +242,52 @@ struct Memory::Impl { } case Common::PageType::RasterizerCachedMemory: { const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); - system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount); + system.GPU().FlushRegion(current_vaddr, copy_amount); + std::memcpy(dest_buffer, host_ptr, copy_amount); + break; + } + default: + UNREACHABLE(); + } + + page_index++; + page_offset = 0; + dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; + remaining_size -= copy_amount; + } + } + + void ReadBlockUnsafe(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, + const std::size_t size) { + const auto& page_table = process.VMManager().page_table; + + std::size_t remaining_size = size; + std::size_t page_index = src_addr >> PAGE_BITS; + std::size_t page_offset = src_addr & PAGE_MASK; + + while (remaining_size > 0) { + const std::size_t copy_amount = + std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); + const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); + + switch (page_table.attributes[page_index]) { + case Common::PageType::Unmapped: { + LOG_ERROR(HW_Memory, + "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, src_addr, size); + std::memset(dest_buffer, 0, copy_amount); + break; + } + case Common::PageType::Memory: { + DEBUG_ASSERT(page_table.pointers[page_index]); + + const u8* const src_ptr = + page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS); + std::memcpy(dest_buffer, src_ptr, copy_amount); + break; + } + case Common::PageType::RasterizerCachedMemory: { + const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); std::memcpy(dest_buffer, host_ptr, copy_amount); break; } @@ -261,6 +306,10 @@ struct Memory::Impl { ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size); } + void ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std::size_t size) { + ReadBlockUnsafe(*system.CurrentProcess(), src_addr, dest_buffer, size); + } + void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, const std::size_t size) { const auto& page_table = process.VMManager().page_table; @@ -290,7 +339,50 @@ struct Memory::Impl { } case Common::PageType::RasterizerCachedMemory: { u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); - system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount); + system.GPU().InvalidateRegion(current_vaddr, copy_amount); + std::memcpy(host_ptr, src_buffer, copy_amount); + break; + } + default: + UNREACHABLE(); + } + + page_index++; + page_offset = 0; + src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; + remaining_size -= copy_amount; + } + } + + void WriteBlockUnsafe(const Kernel::Process& process, const VAddr dest_addr, + const void* src_buffer, const std::size_t size) { + const auto& page_table = process.VMManager().page_table; + std::size_t remaining_size = size; + std::size_t page_index = dest_addr >> PAGE_BITS; + std::size_t page_offset = dest_addr & PAGE_MASK; + + while (remaining_size > 0) { + const std::size_t copy_amount = + std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); + const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); + + switch (page_table.attributes[page_index]) { + case Common::PageType::Unmapped: { + LOG_ERROR(HW_Memory, + "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, dest_addr, size); + break; + } + case Common::PageType::Memory: { + DEBUG_ASSERT(page_table.pointers[page_index]); + + u8* const dest_ptr = + page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS); + std::memcpy(dest_ptr, src_buffer, copy_amount); + break; + } + case Common::PageType::RasterizerCachedMemory: { + u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); std::memcpy(host_ptr, src_buffer, copy_amount); break; } @@ -309,6 +401,10 @@ struct Memory::Impl { WriteBlock(*system.CurrentProcess(), dest_addr, src_buffer, size); } + void WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { + WriteBlockUnsafe(*system.CurrentProcess(), dest_addr, src_buffer, size); + } + void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { const auto& page_table = process.VMManager().page_table; std::size_t remaining_size = size; @@ -337,7 +433,7 @@ struct Memory::Impl { } case Common::PageType::RasterizerCachedMemory: { u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); - system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount); + system.GPU().InvalidateRegion(current_vaddr, copy_amount); std::memset(host_ptr, 0, copy_amount); break; } @@ -384,7 +480,7 @@ struct Memory::Impl { } case Common::PageType::RasterizerCachedMemory: { const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); - system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount); + system.GPU().FlushRegion(current_vaddr, copy_amount); WriteBlock(process, dest_addr, host_ptr, copy_amount); break; } @@ -545,7 +641,7 @@ struct Memory::Impl { break; case Common::PageType::RasterizerCachedMemory: { const u8* const host_ptr = GetPointerFromVMA(vaddr); - system.GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T)); + system.GPU().FlushRegion(vaddr, sizeof(T)); T value; std::memcpy(&value, host_ptr, sizeof(T)); return value; @@ -587,7 +683,7 @@ struct Memory::Impl { break; case Common::PageType::RasterizerCachedMemory: { u8* const host_ptr{GetPointerFromVMA(vaddr)}; - system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T)); + system.GPU().InvalidateRegion(vaddr, sizeof(T)); std::memcpy(host_ptr, &data, sizeof(T)); break; } @@ -696,6 +792,15 @@ void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_ impl->ReadBlock(src_addr, dest_buffer, size); } +void Memory::ReadBlockUnsafe(const Kernel::Process& process, const VAddr src_addr, + void* dest_buffer, const std::size_t size) { + impl->ReadBlockUnsafe(process, src_addr, dest_buffer, size); +} + +void Memory::ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std::size_t size) { + impl->ReadBlockUnsafe(src_addr, dest_buffer, size); +} + void Memory::WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, std::size_t size) { impl->WriteBlock(process, dest_addr, src_buffer, size); @@ -705,6 +810,16 @@ void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std impl->WriteBlock(dest_addr, src_buffer, size); } +void Memory::WriteBlockUnsafe(const Kernel::Process& process, VAddr dest_addr, + const void* src_buffer, std::size_t size) { + impl->WriteBlockUnsafe(process, dest_addr, src_buffer, size); +} + +void Memory::WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer, + const std::size_t size) { + impl->WriteBlockUnsafe(dest_addr, src_buffer, size); +} + void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) { impl->ZeroBlock(process, dest_addr, size); } diff --git a/src/core/memory.h b/src/core/memory.h index 8913a9da4..b92d678a4 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -295,6 +295,27 @@ public: std::size_t size); /** + * Reads a contiguous block of bytes from a specified process' address space. + * This unsafe version does not trigger GPU flushing. + * + * @param process The process to read the data from. + * @param src_addr The virtual address to begin reading from. + * @param dest_buffer The buffer to place the read bytes into. + * @param size The amount of data to read, in bytes. + * + * @note If a size of 0 is specified, then this function reads nothing and + * no attempts to access memory are made at all. + * + * @pre dest_buffer must be at least size bytes in length, otherwise a + * buffer overrun will occur. + * + * @post The range [dest_buffer, size) contains the read bytes from the + * process' address space. + */ + void ReadBlockUnsafe(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, + std::size_t size); + + /** * Reads a contiguous block of bytes from the current process' address space. * * @param src_addr The virtual address to begin reading from. @@ -313,6 +334,25 @@ public: void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size); /** + * Reads a contiguous block of bytes from the current process' address space. + * This unsafe version does not trigger GPU flushing. + * + * @param src_addr The virtual address to begin reading from. + * @param dest_buffer The buffer to place the read bytes into. + * @param size The amount of data to read, in bytes. + * + * @note If a size of 0 is specified, then this function reads nothing and + * no attempts to access memory are made at all. + * + * @pre dest_buffer must be at least size bytes in length, otherwise a + * buffer overrun will occur. + * + * @post The range [dest_buffer, size) contains the read bytes from the + * current process' address space. + */ + void ReadBlockUnsafe(VAddr src_addr, void* dest_buffer, std::size_t size); + + /** * Writes a range of bytes into a given process' address space at the specified * virtual address. * @@ -336,6 +376,26 @@ public: std::size_t size); /** + * Writes a range of bytes into a given process' address space at the specified + * virtual address. + * This unsafe version does not invalidate GPU Memory. + * + * @param process The process to write data into the address space of. + * @param dest_addr The destination virtual address to begin writing the data at. + * @param src_buffer The data to write into the process' address space. + * @param size The size of the data to write, in bytes. + * + * @post The address range [dest_addr, size) in the process' address space + * contains the data that was within src_buffer. + * + * @post If an attempt is made to write into an unmapped region of memory, the writes + * will be ignored and an error will be logged. + * + */ + void WriteBlockUnsafe(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, + std::size_t size); + + /** * Writes a range of bytes into the current process' address space at the specified * virtual address. * @@ -357,6 +417,24 @@ public: void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size); /** + * Writes a range of bytes into the current process' address space at the specified + * virtual address. + * This unsafe version does not invalidate GPU Memory. + * + * @param dest_addr The destination virtual address to begin writing the data at. + * @param src_buffer The data to write into the current process' address space. + * @param size The size of the data to write, in bytes. + * + * @post The address range [dest_addr, size) in the current process' address space + * contains the data that was within src_buffer. + * + * @post If an attempt is made to write into an unmapped region of memory, the writes + * will be ignored and an error will be logged. + * + */ + void WriteBlockUnsafe(VAddr dest_addr, const void* src_buffer, std::size_t size); + + /** * Fills the specified address range within a process' address space with zeroes. * * @param process The process that will have a portion of its memory zeroed out. |