forked from suyu/suyu
Merge pull request #11892 from german77/pkm_screenshot
service: am: Implement ISelfController::SaveCurrentScreenshot
This commit is contained in:
commit
db5c24eb66
6 changed files with 82 additions and 17 deletions
|
@ -31,6 +31,7 @@
|
||||||
#include "core/hle/service/apm/apm_controller.h"
|
#include "core/hle/service/apm/apm_controller.h"
|
||||||
#include "core/hle/service/apm/apm_interface.h"
|
#include "core/hle/service/apm/apm_interface.h"
|
||||||
#include "core/hle/service/bcat/backend/backend.h"
|
#include "core/hle/service/bcat/backend/backend.h"
|
||||||
|
#include "core/hle/service/caps/caps_su.h"
|
||||||
#include "core/hle/service/caps/caps_types.h"
|
#include "core/hle/service/caps/caps_types.h"
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
@ -702,9 +703,17 @@ void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& c
|
||||||
void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) {
|
void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const auto album_report_option = rp.PopEnum<Capture::AlbumReportOption>();
|
const auto report_option = rp.PopEnum<Capture::AlbumReportOption>();
|
||||||
|
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called. album_report_option={}", album_report_option);
|
LOG_INFO(Service_AM, "called, report_option={}", report_option);
|
||||||
|
|
||||||
|
const auto screenshot_service =
|
||||||
|
system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>(
|
||||||
|
"caps:su");
|
||||||
|
|
||||||
|
if (screenshot_service) {
|
||||||
|
screenshot_service->CaptureAndSaveScreenshot(report_option);
|
||||||
|
}
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
|
|
@ -228,12 +228,14 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail(
|
||||||
|
|
||||||
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
|
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
|
||||||
const ScreenShotAttribute& attribute,
|
const ScreenShotAttribute& attribute,
|
||||||
std::span<const u8> image_data, u64 aruid) {
|
AlbumReportOption report_option, std::span<const u8> image_data,
|
||||||
return SaveScreenShot(out_entry, attribute, {}, image_data, aruid);
|
u64 aruid) {
|
||||||
|
return SaveScreenShot(out_entry, attribute, report_option, {}, image_data, aruid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
|
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
|
||||||
const ScreenShotAttribute& attribute,
|
const ScreenShotAttribute& attribute,
|
||||||
|
AlbumReportOption report_option,
|
||||||
const ApplicationData& app_data, std::span<const u8> image_data,
|
const ApplicationData& app_data, std::span<const u8> image_data,
|
||||||
u64 aruid) {
|
u64 aruid) {
|
||||||
const u64 title_id = system.GetApplicationProcessProgramID();
|
const u64 title_id = system.GetApplicationProcessProgramID();
|
||||||
|
@ -407,10 +409,14 @@ Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::p
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PNGToMemory(void* context, void* png, int len) {
|
void AlbumManager::FlipVerticallyOnWrite(bool flip) {
|
||||||
|
stbi_flip_vertically_on_write(flip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PNGToMemory(void* context, void* data, int len) {
|
||||||
std::vector<u8>* png_image = static_cast<std::vector<u8>*>(context);
|
std::vector<u8>* png_image = static_cast<std::vector<u8>*>(context);
|
||||||
png_image->reserve(len);
|
unsigned char* png = static_cast<unsigned char*>(data);
|
||||||
std::memcpy(png_image->data(), png, len);
|
png_image->insert(png_image->end(), png, png + len);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image,
|
Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image,
|
||||||
|
|
|
@ -59,14 +59,17 @@ public:
|
||||||
const ScreenShotDecodeOption& decoder_options) const;
|
const ScreenShotDecodeOption& decoder_options) const;
|
||||||
|
|
||||||
Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute,
|
Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute,
|
||||||
std::span<const u8> image_data, u64 aruid);
|
AlbumReportOption report_option, std::span<const u8> image_data,
|
||||||
Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute,
|
|
||||||
const ApplicationData& app_data, std::span<const u8> image_data,
|
|
||||||
u64 aruid);
|
u64 aruid);
|
||||||
|
Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute,
|
||||||
|
AlbumReportOption report_option, const ApplicationData& app_data,
|
||||||
|
std::span<const u8> image_data, u64 aruid);
|
||||||
Result SaveEditedScreenShot(ApplicationAlbumEntry& out_entry,
|
Result SaveEditedScreenShot(ApplicationAlbumEntry& out_entry,
|
||||||
const ScreenShotAttribute& attribute, const AlbumFileId& file_id,
|
const ScreenShotAttribute& attribute, const AlbumFileId& file_id,
|
||||||
std::span<const u8> image_data);
|
std::span<const u8> image_data);
|
||||||
|
|
||||||
|
void FlipVerticallyOnWrite(bool flip);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr std::size_t NandAlbumFileLimit = 1000;
|
static constexpr std::size_t NandAlbumFileLimit = 1000;
|
||||||
static constexpr std::size_t SdAlbumFileLimit = 10000;
|
static constexpr std::size_t SdAlbumFileLimit = 10000;
|
||||||
|
|
|
@ -34,7 +34,7 @@ void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
struct Parameters {
|
struct Parameters {
|
||||||
ScreenShotAttribute attribute{};
|
ScreenShotAttribute attribute{};
|
||||||
u32 report_option{};
|
AlbumReportOption report_option{};
|
||||||
INSERT_PADDING_BYTES(0x4);
|
INSERT_PADDING_BYTES(0x4);
|
||||||
u64 applet_resource_user_id{};
|
u64 applet_resource_user_id{};
|
||||||
};
|
};
|
||||||
|
@ -49,13 +49,16 @@ void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) {
|
||||||
parameters.applet_resource_user_id);
|
parameters.applet_resource_user_id);
|
||||||
|
|
||||||
ApplicationAlbumEntry entry{};
|
ApplicationAlbumEntry entry{};
|
||||||
const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer,
|
manager->FlipVerticallyOnWrite(false);
|
||||||
parameters.applet_resource_user_id);
|
const auto result =
|
||||||
|
manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option,
|
||||||
|
image_data_buffer, parameters.applet_resource_user_id);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 10};
|
IPC::ResponseBuilder rb{ctx, 10};
|
||||||
rb.Push(result);
|
rb.Push(result);
|
||||||
rb.PushRaw(entry);
|
rb.PushRaw(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) {
|
void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
struct Parameters {
|
struct Parameters {
|
||||||
|
@ -83,6 +86,7 @@ void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) {
|
||||||
image_data_buffer.size(), thumbnail_image_data_buffer.size());
|
image_data_buffer.size(), thumbnail_image_data_buffer.size());
|
||||||
|
|
||||||
ApplicationAlbumEntry entry{};
|
ApplicationAlbumEntry entry{};
|
||||||
|
manager->FlipVerticallyOnWrite(false);
|
||||||
const auto result = manager->SaveEditedScreenShot(entry, parameters.attribute,
|
const auto result = manager->SaveEditedScreenShot(entry, parameters.attribute,
|
||||||
parameters.file_id, image_data_buffer);
|
parameters.file_id, image_data_buffer);
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/service/caps/caps_manager.h"
|
#include "core/hle/service/caps/caps_manager.h"
|
||||||
#include "core/hle/service/caps/caps_su.h"
|
#include "core/hle/service/caps/caps_su.h"
|
||||||
#include "core/hle/service/caps/caps_types.h"
|
#include "core/hle/service/caps/caps_types.h"
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
|
#include "video_core/renderer_base.h"
|
||||||
|
|
||||||
namespace Service::Capture {
|
namespace Service::Capture {
|
||||||
|
|
||||||
|
@ -58,8 +60,10 @@ void IScreenShotApplicationService::SaveScreenShotEx0(HLERequestContext& ctx) {
|
||||||
parameters.applet_resource_user_id);
|
parameters.applet_resource_user_id);
|
||||||
|
|
||||||
ApplicationAlbumEntry entry{};
|
ApplicationAlbumEntry entry{};
|
||||||
const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer,
|
manager->FlipVerticallyOnWrite(false);
|
||||||
parameters.applet_resource_user_id);
|
const auto result =
|
||||||
|
manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option,
|
||||||
|
image_data_buffer, parameters.applet_resource_user_id);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 10};
|
IPC::ResponseBuilder rb{ctx, 10};
|
||||||
rb.Push(result);
|
rb.Push(result);
|
||||||
|
@ -88,13 +92,43 @@ void IScreenShotApplicationService::SaveScreenShotEx1(HLERequestContext& ctx) {
|
||||||
ApplicationAlbumEntry entry{};
|
ApplicationAlbumEntry entry{};
|
||||||
ApplicationData app_data{};
|
ApplicationData app_data{};
|
||||||
std::memcpy(&app_data, app_data_buffer.data(), sizeof(ApplicationData));
|
std::memcpy(&app_data, app_data_buffer.data(), sizeof(ApplicationData));
|
||||||
|
manager->FlipVerticallyOnWrite(false);
|
||||||
const auto result =
|
const auto result =
|
||||||
manager->SaveScreenShot(entry, parameters.attribute, app_data, image_data_buffer,
|
manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option, app_data,
|
||||||
parameters.applet_resource_user_id);
|
image_data_buffer, parameters.applet_resource_user_id);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 10};
|
IPC::ResponseBuilder rb{ctx, 10};
|
||||||
rb.Push(result);
|
rb.Push(result);
|
||||||
rb.PushRaw(entry);
|
rb.PushRaw(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IScreenShotApplicationService::CaptureAndSaveScreenshot(AlbumReportOption report_option) {
|
||||||
|
auto& renderer = system.Renderer();
|
||||||
|
Layout::FramebufferLayout layout =
|
||||||
|
Layout::DefaultFrameLayout(screenshot_width, screenshot_height);
|
||||||
|
|
||||||
|
const Capture::ScreenShotAttribute attribute{
|
||||||
|
.unknown_0{},
|
||||||
|
.orientation = Capture::AlbumImageOrientation::None,
|
||||||
|
.unknown_1{},
|
||||||
|
.unknown_2{},
|
||||||
|
};
|
||||||
|
|
||||||
|
renderer.RequestScreenshot(
|
||||||
|
image_data.data(),
|
||||||
|
[attribute, report_option, this](bool invert_y) {
|
||||||
|
// Convert from BGRA to RGBA
|
||||||
|
for (std::size_t i = 0; i < image_data.size(); i += bytes_per_pixel) {
|
||||||
|
const u8 temp = image_data[i];
|
||||||
|
image_data[i] = image_data[i + 2];
|
||||||
|
image_data[i + 2] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Capture::ApplicationAlbumEntry entry{};
|
||||||
|
manager->FlipVerticallyOnWrite(invert_y);
|
||||||
|
manager->SaveScreenShot(entry, attribute, report_option, image_data, {});
|
||||||
|
},
|
||||||
|
layout);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Service::Capture
|
} // namespace Service::Capture
|
||||||
|
|
|
@ -10,6 +10,7 @@ class System;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Service::Capture {
|
namespace Service::Capture {
|
||||||
|
enum class AlbumReportOption : s32;
|
||||||
class AlbumManager;
|
class AlbumManager;
|
||||||
|
|
||||||
class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> {
|
class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> {
|
||||||
|
@ -18,11 +19,19 @@ public:
|
||||||
std::shared_ptr<AlbumManager> album_manager);
|
std::shared_ptr<AlbumManager> album_manager);
|
||||||
~IScreenShotApplicationService() override;
|
~IScreenShotApplicationService() override;
|
||||||
|
|
||||||
|
void CaptureAndSaveScreenshot(AlbumReportOption report_option);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static constexpr std::size_t screenshot_width = 1280;
|
||||||
|
static constexpr std::size_t screenshot_height = 720;
|
||||||
|
static constexpr std::size_t bytes_per_pixel = 4;
|
||||||
|
|
||||||
void SetShimLibraryVersion(HLERequestContext& ctx);
|
void SetShimLibraryVersion(HLERequestContext& ctx);
|
||||||
void SaveScreenShotEx0(HLERequestContext& ctx);
|
void SaveScreenShotEx0(HLERequestContext& ctx);
|
||||||
void SaveScreenShotEx1(HLERequestContext& ctx);
|
void SaveScreenShotEx1(HLERequestContext& ctx);
|
||||||
|
|
||||||
|
std::array<u8, screenshot_width * screenshot_height * bytes_per_pixel> image_data;
|
||||||
|
|
||||||
std::shared_ptr<AlbumManager> manager;
|
std::shared_ptr<AlbumManager> manager;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue