mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2026-07-10 01:34:41 -06:00
core: apt: Restore captured framebuffers on libapplet closure
This commit is contained in:
parent
49ba2e8d5f
commit
31e4ecea58
@ -274,8 +274,9 @@ void AppletManager::CancelAndSendParameter(const MessageParameter& parameter) {
|
|||||||
parameter.sender_id);
|
parameter.sender_id);
|
||||||
|
|
||||||
if (parameter.buffer.size() >= sizeof(CaptureBufferInfo)) {
|
if (parameter.buffer.size() >= sizeof(CaptureBufferInfo)) {
|
||||||
SetCaptureInfo(parameter.buffer);
|
SetCaptureInfoSuspendedApp(parameter.buffer);
|
||||||
CaptureFrameBuffers();
|
CaptureFrameBuffers();
|
||||||
|
TransferCapturedFramebuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
next_parameter->sender_id = parameter.destination_id;
|
next_parameter->sender_id = parameter.destination_id;
|
||||||
@ -616,8 +617,6 @@ Result AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) {
|
|||||||
last_library_launcher_slot = active_slot;
|
last_library_launcher_slot = active_slot;
|
||||||
last_prepared_library_applet = applet_id;
|
last_prepared_library_applet = applet_id;
|
||||||
|
|
||||||
capture_buffer_info.reset();
|
|
||||||
|
|
||||||
if (Settings::values.lle_applets) {
|
if (Settings::values.lle_applets) {
|
||||||
bool is_setup = system.GetAppLoader().DoingInitialSetup();
|
bool is_setup = system.GetAppLoader().DoingInitialSetup();
|
||||||
auto cfg = Service::CFG::GetModule(system);
|
auto cfg = Service::CFG::GetModule(system);
|
||||||
@ -638,6 +637,8 @@ Result AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) {
|
|||||||
LOG_DEBUG(Service_APT, "Creating HLE applet {:03X} with parent {:03X}", applet_id, parent);
|
LOG_DEBUG(Service_APT, "Creating HLE applet {:03X} with parent {:03X}", applet_id, parent);
|
||||||
return CreateHLEApplet(applet_id, parent, false);
|
return CreateHLEApplet(applet_id, parent, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
capture_info.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result AppletManager::PreloadLibraryApplet(AppletId applet_id) {
|
Result AppletManager::PreloadLibraryApplet(AppletId applet_id) {
|
||||||
@ -737,6 +738,14 @@ Result AppletManager::CloseLibraryApplet(std::shared_ptr<Kernel::Object> object,
|
|||||||
SendParameter(param);
|
SendParameter(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This doesn't work correctly when opening the
|
||||||
|
// theme shop and an error showwing, because for
|
||||||
|
// some reason the theme shop is an application.
|
||||||
|
if (last_library_launcher_slot == AppletSlot::SystemApplet &&
|
||||||
|
GetAppletSlotFromId(AppletId::Application) != AppletSlot::Error) {
|
||||||
|
TransferCapturedFramebuffers();
|
||||||
|
}
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -971,7 +980,7 @@ Result AppletManager::PrepareToJumpToHomeMenu() {
|
|||||||
|
|
||||||
last_jump_to_home_slot = active_slot;
|
last_jump_to_home_slot = active_slot;
|
||||||
|
|
||||||
capture_buffer_info.reset();
|
capture_info.reset();
|
||||||
|
|
||||||
if (last_jump_to_home_slot == AppletSlot::Application) {
|
if (last_jump_to_home_slot == AppletSlot::Application) {
|
||||||
EnsureHomeMenuLoaded();
|
EnsureHomeMenuLoaded();
|
||||||
@ -1465,7 +1474,7 @@ Result AppletManager::PrepareToStartApplication(u64 title_id, FS::MediaType medi
|
|||||||
app_start_parameters->next_title_id = title_id;
|
app_start_parameters->next_title_id = title_id;
|
||||||
app_start_parameters->next_media_type = media_type;
|
app_start_parameters->next_media_type = media_type;
|
||||||
|
|
||||||
capture_buffer_info.reset();
|
capture_info.reset();
|
||||||
|
|
||||||
app_jump_parameters.Invalidate();
|
app_jump_parameters.Invalidate();
|
||||||
|
|
||||||
@ -1632,8 +1641,8 @@ static u32 GetDisplayBufferModePixelSize(DisplayBufferMode mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CaptureFrameBuffer(Core::System& system, u32 capture_offset, VAddr src, u32 height,
|
static void CaptureFrameBuffer(Core::System& system, u32 capture_offset, std::span<u8> dst,
|
||||||
DisplayBufferMode mode) {
|
VAddr src, u32 height, DisplayBufferMode mode) {
|
||||||
const auto bpp = GetDisplayBufferModePixelSize(mode);
|
const auto bpp = GetDisplayBufferModePixelSize(mode);
|
||||||
if (bpp == 0) {
|
if (bpp == 0) {
|
||||||
return;
|
return;
|
||||||
@ -1642,15 +1651,8 @@ static void CaptureFrameBuffer(Core::System& system, u32 capture_offset, VAddr s
|
|||||||
system.Memory().RasterizerFlushVirtualRegion(src, GSP::FRAMEBUFFER_WIDTH * height * bpp,
|
system.Memory().RasterizerFlushVirtualRegion(src, GSP::FRAMEBUFFER_WIDTH * height * bpp,
|
||||||
Memory::FlushMode::Flush);
|
Memory::FlushMode::Flush);
|
||||||
|
|
||||||
// Address in VRAM that APT copies framebuffer captures to.
|
// APT captures the framebuffer to a copy on its own bss.
|
||||||
constexpr VAddr screen_capture_base_vaddr = Memory::VRAM_VADDR + 0x500000;
|
u8* dst_ptr = dst.data() + capture_offset;
|
||||||
const auto dst_vaddr = screen_capture_base_vaddr + capture_offset;
|
|
||||||
auto dst_ptr = system.Memory().GetPointer(dst_vaddr);
|
|
||||||
if (!dst_ptr) {
|
|
||||||
LOG_ERROR(Service_APT,
|
|
||||||
"Could not retrieve framebuffer capture destination buffer, skipping screen.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto src_ptr = system.Memory().GetPointer(src);
|
const auto src_ptr = system.Memory().GetPointer(src);
|
||||||
if (!src_ptr) {
|
if (!src_ptr) {
|
||||||
@ -1664,28 +1666,40 @@ static void CaptureFrameBuffer(Core::System& system, u32 capture_offset, VAddr s
|
|||||||
const auto dst_offset = VideoCore::GetMortonOffset(x, y, bpp) +
|
const auto dst_offset = VideoCore::GetMortonOffset(x, y, bpp) +
|
||||||
(y & ~7) * GSP::FRAMEBUFFER_WIDTH_POW2 * bpp;
|
(y & ~7) * GSP::FRAMEBUFFER_WIDTH_POW2 * bpp;
|
||||||
const auto src_offset = bpp * (GSP::FRAMEBUFFER_WIDTH * y + x);
|
const auto src_offset = bpp * (GSP::FRAMEBUFFER_WIDTH * y + x);
|
||||||
|
ASSERT(capture_offset + dst_offset + bpp <= dst.size());
|
||||||
std::memcpy(dst_ptr + dst_offset, src_ptr + src_offset, bpp);
|
std::memcpy(dst_ptr + dst_offset, src_ptr + src_offset, bpp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
system.Memory().RasterizerFlushVirtualRegion(
|
|
||||||
dst_vaddr, GSP::FRAMEBUFFER_WIDTH_POW2 * height * bpp, Memory::FlushMode::Invalidate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppletManager::CaptureFrameBuffers() {
|
void AppletManager::CaptureFrameBuffers() {
|
||||||
CaptureFrameBuffer(system, capture_info->bottom_screen_left_offset,
|
CaptureFrameBuffer(system, capture_info_suspended_app->bottom_screen_left_offset,
|
||||||
GSP::FRAMEBUFFER_SAVE_AREA_BOTTOM, GSP::BOTTOM_FRAMEBUFFER_HEIGHT,
|
framebuffer_backup, GSP::FRAMEBUFFER_SAVE_AREA_BOTTOM,
|
||||||
capture_info->bottom_screen_format);
|
GSP::BOTTOM_FRAMEBUFFER_HEIGHT,
|
||||||
CaptureFrameBuffer(system, capture_info->top_screen_left_offset,
|
capture_info_suspended_app->bottom_screen_format);
|
||||||
GSP::FRAMEBUFFER_SAVE_AREA_TOP_LEFT, GSP::TOP_FRAMEBUFFER_HEIGHT,
|
CaptureFrameBuffer(system, capture_info_suspended_app->top_screen_left_offset,
|
||||||
capture_info->top_screen_format);
|
framebuffer_backup, GSP::FRAMEBUFFER_SAVE_AREA_TOP_LEFT,
|
||||||
if (capture_info->is_3d) {
|
GSP::TOP_FRAMEBUFFER_HEIGHT, capture_info_suspended_app->top_screen_format);
|
||||||
CaptureFrameBuffer(system, capture_info->top_screen_right_offset,
|
if (capture_info_suspended_app->is_3d) {
|
||||||
GSP::FRAMEBUFFER_SAVE_AREA_TOP_RIGHT, GSP::TOP_FRAMEBUFFER_HEIGHT,
|
CaptureFrameBuffer(system, capture_info_suspended_app->top_screen_right_offset,
|
||||||
capture_info->top_screen_format);
|
framebuffer_backup, GSP::FRAMEBUFFER_SAVE_AREA_TOP_RIGHT,
|
||||||
|
GSP::TOP_FRAMEBUFFER_HEIGHT,
|
||||||
|
capture_info_suspended_app->top_screen_format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppletManager::TransferCapturedFramebuffers() {
|
||||||
|
constexpr u32 VRAM_TRANSFER_OFFSET = 0x500000;
|
||||||
|
|
||||||
|
const VAddr dst_vaddr = Memory::VRAM_VADDR + VRAM_TRANSFER_OFFSET;
|
||||||
|
auto dst_ptr = system.Memory().GetPointer(dst_vaddr);
|
||||||
|
|
||||||
|
memcpy(dst_ptr, framebuffer_backup.data(), framebuffer_backup.size());
|
||||||
|
|
||||||
|
system.Memory().RasterizerFlushVirtualRegion(dst_vaddr, framebuffer_backup.size(),
|
||||||
|
Memory::FlushMode::Invalidate);
|
||||||
|
}
|
||||||
|
|
||||||
void AppletManager::LoadInputDevices() {
|
void AppletManager::LoadInputDevices() {
|
||||||
home_button = Input::CreateDevice<Input::ButtonDevice>(
|
home_button = Input::CreateDevice<Input::ButtonDevice>(
|
||||||
Settings::values.current_input_profile.buttons[Settings::NativeButton::Home]);
|
Settings::values.current_input_profile.buttons[Settings::NativeButton::Home]);
|
||||||
|
|||||||
@ -367,35 +367,36 @@ public:
|
|||||||
deliver_arg = std::move(arg);
|
deliver_arg = std::move(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> GetCaptureInfo() {
|
std::vector<u8> GetCaptureInfoSuspendedApp() {
|
||||||
std::vector<u8> buffer;
|
std::vector<u8> buffer;
|
||||||
if (capture_info) {
|
if (capture_info_suspended_app) {
|
||||||
buffer.resize(sizeof(CaptureBufferInfo));
|
buffer.resize(sizeof(CaptureBufferInfo));
|
||||||
std::memcpy(buffer.data(), &capture_info.get(), sizeof(CaptureBufferInfo));
|
std::memcpy(buffer.data(), &capture_info_suspended_app.get(),
|
||||||
|
sizeof(CaptureBufferInfo));
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
void SetCaptureInfo(std::vector<u8> buffer) {
|
void SetCaptureInfoSuspendedApp(std::vector<u8> buffer) {
|
||||||
ASSERT_MSG(buffer.size() >= sizeof(CaptureBufferInfo), "CaptureBufferInfo is too small.");
|
ASSERT_MSG(buffer.size() >= sizeof(CaptureBufferInfo), "CaptureBufferInfo is too small.");
|
||||||
|
|
||||||
capture_info.emplace();
|
capture_info_suspended_app.emplace();
|
||||||
std::memcpy(&capture_info.get(), buffer.data(), sizeof(CaptureBufferInfo));
|
std::memcpy(&capture_info_suspended_app.get(), buffer.data(), sizeof(CaptureBufferInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> ReceiveCaptureBufferInfo() {
|
std::vector<u8> ReceiveCaptureBufferInfo() {
|
||||||
std::vector<u8> buffer;
|
std::vector<u8> buffer;
|
||||||
if (capture_buffer_info) {
|
if (capture_info) {
|
||||||
buffer.resize(sizeof(CaptureBufferInfo));
|
buffer.resize(sizeof(CaptureBufferInfo));
|
||||||
std::memcpy(buffer.data(), &capture_buffer_info.get(), sizeof(CaptureBufferInfo));
|
std::memcpy(buffer.data(), &capture_info.get(), sizeof(CaptureBufferInfo));
|
||||||
capture_buffer_info.reset();
|
capture_info.reset();
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
void SendCaptureBufferInfo(std::vector<u8> buffer) {
|
void SendCaptureBufferInfo(std::vector<u8> buffer) {
|
||||||
ASSERT_MSG(buffer.size() >= sizeof(CaptureBufferInfo), "CaptureBufferInfo is too small.");
|
ASSERT_MSG(buffer.size() >= sizeof(CaptureBufferInfo), "CaptureBufferInfo is too small.");
|
||||||
|
|
||||||
capture_buffer_info.emplace();
|
capture_info.emplace();
|
||||||
std::memcpy(&capture_buffer_info.get(), buffer.data(), sizeof(CaptureBufferInfo));
|
std::memcpy(&capture_info.get(), buffer.data(), sizeof(CaptureBufferInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PrepareToStartApplication(u64 title_id, FS::MediaType media_type);
|
Result PrepareToStartApplication(u64 title_id, FS::MediaType media_type);
|
||||||
@ -451,8 +452,11 @@ private:
|
|||||||
boost::optional<SysMenuArg> sys_menu_arg{};
|
boost::optional<SysMenuArg> sys_menu_arg{};
|
||||||
u64 home_menu_tid_to_start{};
|
u64 home_menu_tid_to_start{};
|
||||||
|
|
||||||
|
boost::optional<CaptureBufferInfo> capture_info_suspended_app;
|
||||||
boost::optional<CaptureBufferInfo> capture_info;
|
boost::optional<CaptureBufferInfo> capture_info;
|
||||||
boost::optional<CaptureBufferInfo> capture_buffer_info;
|
|
||||||
|
static constexpr size_t FRAMEBUFFER_BACKUP_SIZE = 0xE7000;
|
||||||
|
std::vector<u8> framebuffer_backup = std::vector<u8>(FRAMEBUFFER_BACKUP_SIZE);
|
||||||
|
|
||||||
static constexpr std::size_t NumAppletSlot = 4;
|
static constexpr std::size_t NumAppletSlot = 4;
|
||||||
|
|
||||||
@ -555,6 +559,7 @@ private:
|
|||||||
void EnsureHomeMenuLoaded();
|
void EnsureHomeMenuLoaded();
|
||||||
|
|
||||||
void CaptureFrameBuffers();
|
void CaptureFrameBuffers();
|
||||||
|
void TransferCapturedFramebuffers();
|
||||||
|
|
||||||
Result CreateHLEApplet(AppletId id, AppletId parent, bool preload);
|
Result CreateHLEApplet(AppletId id, AppletId parent, bool preload);
|
||||||
void HLEAppletUpdateEvent(std::uintptr_t user_data, s64 cycles_late);
|
void HLEAppletUpdateEvent(std::uintptr_t user_data, s64 cycles_late);
|
||||||
@ -571,8 +576,9 @@ private:
|
|||||||
ar & deliver_arg;
|
ar & deliver_arg;
|
||||||
ar & sys_menu_arg;
|
ar & sys_menu_arg;
|
||||||
ar & home_menu_tid_to_start;
|
ar & home_menu_tid_to_start;
|
||||||
|
ar & capture_info_suspended_app;
|
||||||
ar & capture_info;
|
ar & capture_info;
|
||||||
ar & capture_buffer_info;
|
ar & framebuffer_backup;
|
||||||
ar & active_slot;
|
ar & active_slot;
|
||||||
ar & last_library_launcher_slot;
|
ar & last_library_launcher_slot;
|
||||||
ar & last_prepared_library_applet;
|
ar & last_prepared_library_applet;
|
||||||
@ -584,7 +590,6 @@ private:
|
|||||||
ar & application_close_target;
|
ar & application_close_target;
|
||||||
ar & new_3ds_mode_blocked;
|
ar & new_3ds_mode_blocked;
|
||||||
ar & lock;
|
ar & lock;
|
||||||
ar & capture_info;
|
|
||||||
ar & applet_slots;
|
ar & applet_slots;
|
||||||
ar & library_applet_closing_command;
|
ar & library_applet_closing_command;
|
||||||
ar & next_app_mediatype;
|
ar & next_app_mediatype;
|
||||||
|
|||||||
@ -1123,7 +1123,7 @@ void Module::APTInterface::GetCaptureInfo(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
LOG_DEBUG(Service_APT, "called");
|
LOG_DEBUG(Service_APT, "called");
|
||||||
|
|
||||||
auto screen_capture_buffer = apt->applet_manager->GetCaptureInfo();
|
auto screen_capture_buffer = apt->applet_manager->GetCaptureInfoSuspendedApp();
|
||||||
auto real_size = std::min(static_cast<u32>(screen_capture_buffer.size()), size);
|
auto real_size = std::min(static_cast<u32>(screen_capture_buffer.size()), size);
|
||||||
screen_capture_buffer.resize(size);
|
screen_capture_buffer.resize(size);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user