diff options
Diffstat (limited to 'src/core/hle/service')
-rw-r--r-- | src/core/hle/service/caps/caps.cpp | 7 | ||||
-rw-r--r-- | src/core/hle/service/caps/caps_manager.cpp | 87 | ||||
-rw-r--r-- | src/core/hle/service/caps/caps_manager.h | 11 | ||||
-rw-r--r-- | src/core/hle/service/caps/caps_ss.cpp | 75 | ||||
-rw-r--r-- | src/core/hle/service/caps/caps_ss.h | 8 | ||||
-rw-r--r-- | src/core/hle/service/caps/caps_su.cpp | 69 | ||||
-rw-r--r-- | src/core/hle/service/caps/caps_su.h | 8 | ||||
-rw-r--r-- | src/core/hle/service/caps/caps_types.h | 2 | ||||
-rw-r--r-- | src/core/hle/service/hle_ipc.cpp | 6 | ||||
-rw-r--r-- | src/core/hle/service/nvnflinger/buffer_queue_core.cpp | 6 | ||||
-rw-r--r-- | src/core/hle/service/nvnflinger/buffer_queue_producer.cpp | 5 |
11 files changed, 264 insertions, 20 deletions
diff --git a/src/core/hle/service/caps/caps.cpp b/src/core/hle/service/caps/caps.cpp index 31dd98140..cd1dfe993 100644 --- a/src/core/hle/service/caps/caps.cpp +++ b/src/core/hle/service/caps/caps.cpp @@ -25,11 +25,12 @@ void LoopProcess(Core::System& system) { server_manager->RegisterNamedService( "caps:u", std::make_shared<IAlbumApplicationService>(system, album_manager)); - server_manager->RegisterNamedService("caps:ss", std::make_shared<IScreenShotService>(system)); + server_manager->RegisterNamedService( + "caps:ss", std::make_shared<IScreenShotService>(system, album_manager)); server_manager->RegisterNamedService("caps:sc", std::make_shared<IScreenShotControlService>(system)); - server_manager->RegisterNamedService("caps:su", - std::make_shared<IScreenShotApplicationService>(system)); + server_manager->RegisterNamedService( + "caps:su", std::make_shared<IScreenShotApplicationService>(system, album_manager)); ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp index 2b4e3f076..7d733eb54 100644 --- a/src/core/hle/service/caps/caps_manager.cpp +++ b/src/core/hle/service/caps/caps_manager.cpp @@ -2,12 +2,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <sstream> -#include <stb_image.h> -#include <stb_image_resize.h> #include "common/fs/file.h" #include "common/fs/path_util.h" #include "common/logging/log.h" +#include "common/stb.h" #include "core/core.h" #include "core/hle/service/caps/caps_manager.h" #include "core/hle/service/caps/caps_result.h" @@ -227,6 +226,49 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail( +static_cast<int>(out_image_output.height), decoder_options.flags); } +Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, + const ScreenShotAttribute& attribute, + std::span<const u8> image_data, u64 aruid) { + return SaveScreenShot(out_entry, attribute, {}, image_data, aruid); +} + +Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, + const ScreenShotAttribute& attribute, + const ApplicationData& app_data, std::span<const u8> image_data, + u64 aruid) { + const u64 title_id = system.GetApplicationProcessProgramID(); + const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore(); + + s64 posix_time{}; + Result result = user_clock.GetCurrentTime(system, posix_time); + + if (result.IsError()) { + return result; + } + + const auto date = ConvertToAlbumDateTime(posix_time); + + return SaveImage(out_entry, image_data, title_id, date); +} + +Result AlbumManager::SaveEditedScreenShot(ApplicationAlbumEntry& out_entry, + const ScreenShotAttribute& attribute, + const AlbumFileId& file_id, + std::span<const u8> image_data) { + const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore(); + + s64 posix_time{}; + Result result = user_clock.GetCurrentTime(system, posix_time); + + if (result.IsError()) { + return result; + } + + const auto date = ConvertToAlbumDateTime(posix_time); + + return SaveImage(out_entry, image_data, file_id.application_id, date); +} + Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const { const auto file = album_files.find(file_id); @@ -365,6 +407,47 @@ Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::p return ResultSuccess; } +static void PNGToMemory(void* context, void* png, int len) { + std::vector<u8>* png_image = static_cast<std::vector<u8>*>(context); + png_image->reserve(len); + std::memcpy(png_image->data(), png, len); +} + +Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image, + u64 title_id, const AlbumFileDateTime& date) const { + const auto screenshot_path = + Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir); + const std::string formatted_date = + fmt::format("{:04}-{:02}-{:02}_{:02}-{:02}-{:02}-{:03}", date.year, date.month, date.day, + date.hour, date.minute, date.second, 0); + const std::string file_path = + fmt::format("{}/{:016x}_{}.png", screenshot_path, title_id, formatted_date); + + const Common::FS::IOFile db_file{file_path, Common::FS::FileAccessMode::Write, + Common::FS::FileType::BinaryFile}; + + std::vector<u8> png_image; + if (!stbi_write_png_to_func(PNGToMemory, &png_image, 1280, 720, STBI_rgb_alpha, image.data(), + 0)) { + return ResultFileCountLimit; + } + + if (db_file.Write(png_image) != png_image.size()) { + return ResultFileCountLimit; + } + + out_entry = { + .size = png_image.size(), + .hash = {}, + .datetime = date, + .storage = AlbumStorage::Sd, + .content = ContentType::Screenshot, + .unknown = 1, + }; + + return ResultSuccess; +} + AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const { Time::TimeZone::CalendarInfo calendar_date{}; const auto& time_zone_manager = diff --git a/src/core/hle/service/caps/caps_manager.h b/src/core/hle/service/caps/caps_manager.h index f65eb12c1..44d85117f 100644 --- a/src/core/hle/service/caps/caps_manager.h +++ b/src/core/hle/service/caps/caps_manager.h @@ -58,6 +58,15 @@ public: std::vector<u8>& out_image, const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options) const; + Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, + std::span<const u8> image_data, u64 aruid); + Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, + const ApplicationData& app_data, std::span<const u8> image_data, + u64 aruid); + Result SaveEditedScreenShot(ApplicationAlbumEntry& out_entry, + const ScreenShotAttribute& attribute, const AlbumFileId& file_id, + std::span<const u8> image_data); + private: static constexpr std::size_t NandAlbumFileLimit = 1000; static constexpr std::size_t SdAlbumFileLimit = 10000; @@ -67,6 +76,8 @@ private: Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const; Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width, int height, ScreenShotDecoderFlag flag) const; + Result SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image, u64 title_id, + const AlbumFileDateTime& date) const; AlbumFileDateTime ConvertToAlbumDateTime(u64 posix_time) const; diff --git a/src/core/hle/service/caps/caps_ss.cpp b/src/core/hle/service/caps/caps_ss.cpp index d0d1b5425..1ba2b7972 100644 --- a/src/core/hle/service/caps/caps_ss.cpp +++ b/src/core/hle/service/caps/caps_ss.cpp @@ -1,19 +1,25 @@ // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/logging/log.h" +#include "core/hle/service/caps/caps_manager.h" +#include "core/hle/service/caps/caps_types.h" +#include "core/hle/service/ipc_helpers.h" + #include "core/hle/service/caps/caps_ss.h" namespace Service::Capture { -IScreenShotService::IScreenShotService(Core::System& system_) - : ServiceFramework{system_, "caps:ss"} { +IScreenShotService::IScreenShotService(Core::System& system_, + std::shared_ptr<AlbumManager> album_manager) + : ServiceFramework{system_, "caps:ss"}, manager{album_manager} { // clang-format off static const FunctionInfo functions[] = { {201, nullptr, "SaveScreenShot"}, {202, nullptr, "SaveEditedScreenShot"}, - {203, nullptr, "SaveScreenShotEx0"}, + {203, &IScreenShotService::SaveScreenShotEx0, "SaveScreenShotEx0"}, {204, nullptr, "SaveEditedScreenShotEx0"}, - {206, nullptr, "Unknown206"}, + {206, &IScreenShotService::SaveEditedScreenShotEx1, "SaveEditedScreenShotEx1"}, {208, nullptr, "SaveScreenShotOfMovieEx1"}, {1000, nullptr, "Unknown1000"}, }; @@ -24,4 +30,65 @@ IScreenShotService::IScreenShotService(Core::System& system_) IScreenShotService::~IScreenShotService() = default; +void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + ScreenShotAttribute attribute{}; + u32 report_option{}; + INSERT_PADDING_BYTES(0x4); + u64 applet_resource_user_id{}; + }; + static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + const auto image_data_buffer = ctx.ReadBuffer(); + + LOG_INFO(Service_Capture, + "called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}", + parameters.report_option, image_data_buffer.size(), + parameters.applet_resource_user_id); + + ApplicationAlbumEntry entry{}; + const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer, + parameters.applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 10}; + rb.Push(result); + rb.PushRaw(entry); +} +void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + ScreenShotAttribute attribute; + u64 width; + u64 height; + u64 thumbnail_width; + u64 thumbnail_height; + AlbumFileId file_id; + }; + static_assert(sizeof(Parameters) == 0x78, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + const auto application_data_buffer = ctx.ReadBuffer(0); + const auto image_data_buffer = ctx.ReadBuffer(1); + const auto thumbnail_image_data_buffer = ctx.ReadBuffer(2); + + LOG_INFO(Service_Capture, + "called, width={}, height={}, thumbnail_width={}, thumbnail_height={}, " + "application_id={:016x}, storage={}, type={}, app_data_buffer_size={}, " + "image_data_buffer_size={}, thumbnail_image_buffer_size={}", + parameters.width, parameters.height, parameters.thumbnail_width, + parameters.thumbnail_height, parameters.file_id.application_id, + parameters.file_id.storage, parameters.file_id.type, application_data_buffer.size(), + image_data_buffer.size(), thumbnail_image_data_buffer.size()); + + ApplicationAlbumEntry entry{}; + const auto result = manager->SaveEditedScreenShot(entry, parameters.attribute, + parameters.file_id, image_data_buffer); + + IPC::ResponseBuilder rb{ctx, 10}; + rb.Push(result); + rb.PushRaw(entry); +} + } // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_ss.h b/src/core/hle/service/caps/caps_ss.h index 381e44fd4..a7e9972ab 100644 --- a/src/core/hle/service/caps/caps_ss.h +++ b/src/core/hle/service/caps/caps_ss.h @@ -13,8 +13,14 @@ namespace Service::Capture { class IScreenShotService final : public ServiceFramework<IScreenShotService> { public: - explicit IScreenShotService(Core::System& system_); + explicit IScreenShotService(Core::System& system_, std::shared_ptr<AlbumManager> album_manager); ~IScreenShotService() override; + +private: + void SaveScreenShotEx0(HLERequestContext& ctx); + void SaveEditedScreenShotEx1(HLERequestContext& ctx); + + std::shared_ptr<AlbumManager> manager; }; } // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp index cad173dc7..e85625ee4 100644 --- a/src/core/hle/service/caps/caps_su.cpp +++ b/src/core/hle/service/caps/caps_su.cpp @@ -2,19 +2,22 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/logging/log.h" +#include "core/hle/service/caps/caps_manager.h" #include "core/hle/service/caps/caps_su.h" +#include "core/hle/service/caps/caps_types.h" #include "core/hle/service/ipc_helpers.h" namespace Service::Capture { -IScreenShotApplicationService::IScreenShotApplicationService(Core::System& system_) - : ServiceFramework{system_, "caps:su"} { +IScreenShotApplicationService::IScreenShotApplicationService( + Core::System& system_, std::shared_ptr<AlbumManager> album_manager) + : ServiceFramework{system_, "caps:su"}, manager{album_manager} { // clang-format off static const FunctionInfo functions[] = { {32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"}, {201, nullptr, "SaveScreenShot"}, - {203, nullptr, "SaveScreenShotEx0"}, - {205, nullptr, "SaveScreenShotEx1"}, + {203, &IScreenShotApplicationService::SaveScreenShotEx0, "SaveScreenShotEx0"}, + {205, &IScreenShotApplicationService::SaveScreenShotEx1, "SaveScreenShotEx1"}, {210, nullptr, "SaveScreenShotEx2"}, }; // clang-format on @@ -36,4 +39,62 @@ void IScreenShotApplicationService::SetShimLibraryVersion(HLERequestContext& ctx rb.Push(ResultSuccess); } +void IScreenShotApplicationService::SaveScreenShotEx0(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + ScreenShotAttribute attribute{}; + AlbumReportOption report_option{}; + INSERT_PADDING_BYTES(0x4); + u64 applet_resource_user_id{}; + }; + static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + const auto image_data_buffer = ctx.ReadBuffer(); + + LOG_INFO(Service_Capture, + "called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}", + parameters.report_option, image_data_buffer.size(), + parameters.applet_resource_user_id); + + ApplicationAlbumEntry entry{}; + const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer, + parameters.applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 10}; + rb.Push(result); + rb.PushRaw(entry); +} + +void IScreenShotApplicationService::SaveScreenShotEx1(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + ScreenShotAttribute attribute{}; + AlbumReportOption report_option{}; + INSERT_PADDING_BYTES(0x4); + u64 applet_resource_user_id{}; + }; + static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + const auto app_data_buffer = ctx.ReadBuffer(0); + const auto image_data_buffer = ctx.ReadBuffer(1); + + LOG_INFO(Service_Capture, + "called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}", + parameters.report_option, image_data_buffer.size(), + parameters.applet_resource_user_id); + + ApplicationAlbumEntry entry{}; + ApplicationData app_data{}; + std::memcpy(&app_data, app_data_buffer.data(), sizeof(ApplicationData)); + const auto result = + manager->SaveScreenShot(entry, parameters.attribute, app_data, image_data_buffer, + parameters.applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 10}; + rb.Push(result); + rb.PushRaw(entry); +} + } // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_su.h b/src/core/hle/service/caps/caps_su.h index 647e3059d..89e71f506 100644 --- a/src/core/hle/service/caps/caps_su.h +++ b/src/core/hle/service/caps/caps_su.h @@ -10,14 +10,20 @@ class System; } namespace Service::Capture { +class AlbumManager; class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> { public: - explicit IScreenShotApplicationService(Core::System& system_); + explicit IScreenShotApplicationService(Core::System& system_, + std::shared_ptr<AlbumManager> album_manager); ~IScreenShotApplicationService() override; private: void SetShimLibraryVersion(HLERequestContext& ctx); + void SaveScreenShotEx0(HLERequestContext& ctx); + void SaveScreenShotEx1(HLERequestContext& ctx); + + std::shared_ptr<AlbumManager> manager; }; } // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_types.h b/src/core/hle/service/caps/caps_types.h index 7fd357954..589ac28d3 100644 --- a/src/core/hle/service/caps/caps_types.h +++ b/src/core/hle/service/caps/caps_types.h @@ -20,6 +20,8 @@ enum class AlbumImageOrientation { enum class AlbumReportOption : s32 { Disable, Enable, + Unknown2, + Unknown3, }; enum class ContentType : u8 { diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp index 6f3ae3cc4..ff374ae39 100644 --- a/src/core/hle/service/hle_ipc.cpp +++ b/src/core/hle/service/hle_ipc.cpp @@ -27,10 +27,12 @@ namespace { static thread_local std::array read_buffer_data_a{ Common::ScratchBuffer<u8>(), Common::ScratchBuffer<u8>(), + Common::ScratchBuffer<u8>(), }; static thread_local std::array read_buffer_data_x{ Common::ScratchBuffer<u8>(), Common::ScratchBuffer<u8>(), + Common::ScratchBuffer<u8>(), }; } // Anonymous namespace @@ -343,6 +345,7 @@ std::span<const u8> HLERequestContext::ReadBufferA(std::size_t buffer_index) con static thread_local std::array read_buffer_a{ Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), + Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), }; ASSERT_OR_EXECUTE_MSG( @@ -358,6 +361,7 @@ std::span<const u8> HLERequestContext::ReadBufferX(std::size_t buffer_index) con static thread_local std::array read_buffer_x{ Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), + Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), }; ASSERT_OR_EXECUTE_MSG( @@ -373,10 +377,12 @@ std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) cons static thread_local std::array read_buffer_a{ Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), + Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), }; static thread_local std::array read_buffer_x{ Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), + Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), }; const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && diff --git a/src/core/hle/service/nvnflinger/buffer_queue_core.cpp b/src/core/hle/service/nvnflinger/buffer_queue_core.cpp index 2dbe29616..ed66f6f5b 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvnflinger/buffer_queue_core.cpp @@ -41,7 +41,7 @@ bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) s32 BufferQueueCore::GetMinUndequeuedBufferCountLocked(bool async) const { // If DequeueBuffer is allowed to error out, we don't have to add an extra buffer. if (!use_async_buffer) { - return max_acquired_buffer_count; + return 0; } if (dequeue_buffer_cannot_block || async) { @@ -52,7 +52,7 @@ s32 BufferQueueCore::GetMinUndequeuedBufferCountLocked(bool async) const { } s32 BufferQueueCore::GetMinMaxBufferCountLocked(bool async) const { - return GetMinUndequeuedBufferCountLocked(async) + 1; + return GetMinUndequeuedBufferCountLocked(async); } s32 BufferQueueCore::GetMaxBufferCountLocked(bool async) const { @@ -61,7 +61,7 @@ s32 BufferQueueCore::GetMaxBufferCountLocked(bool async) const { if (override_max_buffer_count != 0) { ASSERT(override_max_buffer_count >= min_buffer_count); - max_buffer_count = override_max_buffer_count; + return override_max_buffer_count; } // Any buffers that are dequeued by the producer or sitting in the queue waiting to be consumed diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp index dc6917d5d..6e7a49658 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp @@ -134,7 +134,7 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, St const s32 max_buffer_count = core->GetMaxBufferCountLocked(async); if (async && core->override_max_buffer_count) { if (core->override_max_buffer_count < max_buffer_count) { - LOG_ERROR(Service_Nvnflinger, "async mode is invalid with buffer count override"); + *found = BufferQueueCore::INVALID_BUFFER_SLOT; return Status::BadValue; } } @@ -142,7 +142,8 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, St // Free up any buffers that are in slots beyond the max buffer count for (s32 s = max_buffer_count; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { ASSERT(slots[s].buffer_state == BufferState::Free); - if (slots[s].graphic_buffer != nullptr) { + if (slots[s].graphic_buffer != nullptr && slots[s].buffer_state == BufferState::Free && + !slots[s].is_preallocated) { core->FreeBufferLocked(s); *return_flags |= Status::ReleaseAllBuffers; } |