diff --git a/README.md b/README.md index 542968b01..2791481ea 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 3952. +This is the source code for early-access 3953. ## Legal Notice diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 26ae274a3..1238eb438 100755 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -31,6 +31,7 @@ #include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/apm/apm_interface.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/filesystem/filesystem.h" #include "core/hle/service/ipc_helpers.h" @@ -702,9 +703,17 @@ void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& c void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto album_report_option = rp.PopEnum(); + const auto report_option = rp.PopEnum(); - 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( + "caps:su"); + + if (screenshot_service) { + screenshot_service->CaptureAndSaveScreenshot(report_option); + } IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -796,7 +805,9 @@ ILockAccessor::ILockAccessor(Core::System& system_) lock_event = service_context.CreateEvent("ILockAccessor::LockEvent"); } -ILockAccessor::~ILockAccessor() = default; +ILockAccessor::~ILockAccessor() { + service_context.CloseEvent(lock_event); +}; void ILockAccessor::TryLock(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; @@ -909,7 +920,9 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); } -ICommonStateGetter::~ICommonStateGetter() = default; +ICommonStateGetter::~ICommonStateGetter() { + service_context.CloseEvent(sleep_lock_event); +}; void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index 19ed184e8..b379dadeb 100755 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -25,7 +25,9 @@ Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent"); } -Cabinet::~Cabinet() = default; +Cabinet::~Cabinet() { + service_context.CloseEvent(availability_change_event); +}; void Cabinet::Initialize() { Applet::Initialize(); diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp index 7d733eb54..96b225d5f 100755 --- a/src/core/hle/service/caps/caps_manager.cpp +++ b/src/core/hle/service/caps/caps_manager.cpp @@ -228,12 +228,14 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail( Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, - std::span image_data, u64 aruid) { - return SaveScreenShot(out_entry, attribute, {}, image_data, aruid); + AlbumReportOption report_option, std::span image_data, + u64 aruid) { + return SaveScreenShot(out_entry, attribute, report_option, {}, image_data, aruid); } Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, + AlbumReportOption report_option, const ApplicationData& app_data, std::span image_data, u64 aruid) { const u64 title_id = system.GetApplicationProcessProgramID(); @@ -407,10 +409,14 @@ Result AlbumManager::LoadImage(std::span out_image, const std::filesystem::p 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* png_image = static_cast*>(context); - png_image->reserve(len); - std::memcpy(png_image->data(), png, len); + unsigned char* png = static_cast(data); + png_image->insert(png_image->end(), png, png + len); } Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span image, diff --git a/src/core/hle/service/caps/caps_manager.h b/src/core/hle/service/caps/caps_manager.h index 44d85117f..e20c70c7b 100755 --- a/src/core/hle/service/caps/caps_manager.h +++ b/src/core/hle/service/caps/caps_manager.h @@ -59,14 +59,17 @@ public: const ScreenShotDecodeOption& decoder_options) const; Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, - std::span image_data, u64 aruid); - Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, - const ApplicationData& app_data, std::span image_data, + AlbumReportOption report_option, std::span image_data, u64 aruid); + Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, + AlbumReportOption report_option, const ApplicationData& app_data, + std::span image_data, u64 aruid); Result SaveEditedScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, const AlbumFileId& file_id, std::span image_data); + void FlipVerticallyOnWrite(bool flip); + private: static constexpr std::size_t NandAlbumFileLimit = 1000; static constexpr std::size_t SdAlbumFileLimit = 10000; diff --git a/src/core/hle/service/caps/caps_ss.cpp b/src/core/hle/service/caps/caps_ss.cpp index b7b4bf782..1aff490b2 100755 --- a/src/core/hle/service/caps/caps_ss.cpp +++ b/src/core/hle/service/caps/caps_ss.cpp @@ -34,7 +34,7 @@ void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { ScreenShotAttribute attribute{}; - u32 report_option{}; + AlbumReportOption report_option{}; INSERT_PADDING_BYTES(0x4); u64 applet_resource_user_id{}; }; @@ -49,13 +49,16 @@ void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) { parameters.applet_resource_user_id); ApplicationAlbumEntry entry{}; - const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer, - parameters.applet_resource_user_id); + manager->FlipVerticallyOnWrite(false); + const auto result = + manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option, + 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 { @@ -83,6 +86,7 @@ void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) { image_data_buffer.size(), thumbnail_image_data_buffer.size()); ApplicationAlbumEntry entry{}; + manager->FlipVerticallyOnWrite(false); const auto result = manager->SaveEditedScreenShot(entry, parameters.attribute, parameters.file_id, image_data_buffer); diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp index c4ca04418..7fbbe5816 100755 --- a/src/core/hle/service/caps/caps_su.cpp +++ b/src/core/hle/service/caps/caps_su.cpp @@ -2,10 +2,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/logging/log.h" +#include "core/core.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" +#include "video_core/renderer_base.h" namespace Service::Capture { @@ -58,8 +60,10 @@ void IScreenShotApplicationService::SaveScreenShotEx0(HLERequestContext& ctx) { parameters.applet_resource_user_id); ApplicationAlbumEntry entry{}; - const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer, - parameters.applet_resource_user_id); + manager->FlipVerticallyOnWrite(false); + const auto result = + manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option, + image_data_buffer, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 10}; rb.Push(result); @@ -88,13 +92,43 @@ void IScreenShotApplicationService::SaveScreenShotEx1(HLERequestContext& ctx) { ApplicationAlbumEntry entry{}; ApplicationData app_data{}; std::memcpy(&app_data, app_data_buffer.data(), sizeof(ApplicationData)); + manager->FlipVerticallyOnWrite(false); const auto result = - manager->SaveScreenShot(entry, parameters.attribute, app_data, image_data_buffer, - parameters.applet_resource_user_id); + manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option, app_data, + image_data_buffer, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 10}; rb.Push(result); 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 diff --git a/src/core/hle/service/caps/caps_su.h b/src/core/hle/service/caps/caps_su.h index 8b0144831..aa3019c2a 100755 --- a/src/core/hle/service/caps/caps_su.h +++ b/src/core/hle/service/caps/caps_su.h @@ -10,6 +10,7 @@ class System; } namespace Service::Capture { +enum class AlbumReportOption : s32; class AlbumManager; class IScreenShotApplicationService final : public ServiceFramework { @@ -18,11 +19,19 @@ public: std::shared_ptr album_manager); ~IScreenShotApplicationService() override; + void CaptureAndSaveScreenshot(AlbumReportOption report_option); + 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 SaveScreenShotEx0(HLERequestContext& ctx); void SaveScreenShotEx1(HLERequestContext& ctx); + std::array image_data; + std::shared_ptr manager; }; diff --git a/src/core/hle/service/hid/controllers/palma.cpp b/src/core/hle/service/hid/controllers/palma.cpp index c5b05779b..c31c9c095 100755 --- a/src/core/hle/service/hid/controllers/palma.cpp +++ b/src/core/hle/service/hid/controllers/palma.cpp @@ -19,7 +19,9 @@ Controller_Palma::Controller_Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent"); } -Controller_Palma::~Controller_Palma() = default; +Controller_Palma::~Controller_Palma() { + service_context.CloseEvent(operation_complete_event); +}; void Controller_Palma::OnInit() {} diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 46a5d9c76..58f34035a 100755 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -2757,6 +2757,10 @@ public: joy_detach_event = service_context.CreateEvent("HidSys::JoyDetachEvent"); } + ~HidSys() { + service_context.CloseEvent(joy_detach_event); + }; + private: void ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) { LOG_WARNING(Service_HID, "called"); diff --git a/src/core/hle/service/hid/hidbus/hidbus_base.cpp b/src/core/hle/service/hid/hidbus/hidbus_base.cpp index 2a3aa8cd8..c6cef6d87 100755 --- a/src/core/hle/service/hid/hidbus/hidbus_base.cpp +++ b/src/core/hle/service/hid/hidbus/hidbus_base.cpp @@ -13,7 +13,10 @@ HidbusBase::HidbusBase(Core::System& system_, KernelHelpers::ServiceContext& ser : system(system_), service_context(service_context_) { send_command_async_event = service_context.CreateEvent("hidbus:SendCommandAsyncEvent"); } -HidbusBase::~HidbusBase() = default; + +HidbusBase::~HidbusBase() { + service_context.CloseEvent(send_command_async_event); +}; void HidbusBase::ActivateDevice() { if (is_activated) { diff --git a/src/core/hle/service/nvnflinger/buffer_transform_flags.h b/src/core/hle/service/nvnflinger/buffer_transform_flags.h index 67aa5dad6..ffe579718 100755 --- a/src/core/hle/service/nvnflinger/buffer_transform_flags.h +++ b/src/core/hle/service/nvnflinger/buffer_transform_flags.h @@ -3,6 +3,7 @@ #pragma once +#include "common/common_funcs.h" #include "common/common_types.h" namespace Service::android { @@ -21,5 +22,6 @@ enum class BufferTransformFlags : u32 { /// Rotate source image 270 degrees clockwise Rotate270 = 0x07, }; +DECLARE_ENUM_FLAG_OPERATORS(BufferTransformFlags); } // namespace Service::android diff --git a/src/core/hle/service/pctl/pctl_module.cpp b/src/core/hle/service/pctl/pctl_module.cpp index 1041fbdbe..5ea2f0b99 100755 --- a/src/core/hle/service/pctl/pctl_module.cpp +++ b/src/core/hle/service/pctl/pctl_module.cpp @@ -141,6 +141,12 @@ public: service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent"); } + ~IParentalControlService() { + service_context.CloseEvent(synchronization_event); + service_context.CloseEvent(unlinked_event); + service_context.CloseEvent(request_suspension_event); + }; + private: bool CheckFreeCommunicationPermissionImpl() const { if (states.temporary_unlocked) { diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index b2e00b48e..c16c56754 100755 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -39,6 +39,18 @@ bool IsConnectionBased(Type type) { } } +template +T GetValue(std::span buffer) { + T t{}; + std::memcpy(&t, buffer.data(), std::min(sizeof(T), buffer.size())); + return t; +} + +template +void PutValue(std::span buffer, const T& t) { + std::memcpy(buffer.data(), &t, std::min(sizeof(T), buffer.size())); +} + } // Anonymous namespace void BSD::PollWork::Execute(BSD* bsd) { @@ -316,22 +328,12 @@ void BSD::SetSockOpt(HLERequestContext& ctx) { const s32 fd = rp.Pop(); const u32 level = rp.Pop(); const OptName optname = static_cast(rp.Pop()); - - const auto buffer = ctx.ReadBuffer(); - const u8* optval = buffer.empty() ? nullptr : buffer.data(); - size_t optlen = buffer.size(); - - std::array values; - if ((optname == OptName::SNDTIMEO || optname == OptName::RCVTIMEO) && buffer.size() == 8) { - std::memcpy(values.data(), buffer.data(), sizeof(values)); - optlen = sizeof(values); - optval = reinterpret_cast(values.data()); - } + const auto optval = ctx.ReadBuffer(); LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} optlen={}", fd, level, - static_cast(optname), optlen); + static_cast(optname), optval.size()); - BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optlen, optval)); + BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval)); } void BSD::Shutdown(HLERequestContext& ctx) { @@ -521,18 +523,19 @@ std::pair BSD::SocketImpl(Domain domain, Type type, Protocol protoco std::pair BSD::PollImpl(std::vector& write_buffer, std::span read_buffer, s32 nfds, s32 timeout) { + if (nfds <= 0) { + // When no entries are provided, -1 is returned with errno zero + return {-1, Errno::SUCCESS}; + } + if (read_buffer.size() < nfds * sizeof(PollFD)) { + return {-1, Errno::INVAL}; + } if (write_buffer.size() < nfds * sizeof(PollFD)) { return {-1, Errno::INVAL}; } - if (nfds == 0) { - // When no entries are provided, -1 is returned with errno zero - return {-1, Errno::SUCCESS}; - } - - const size_t length = std::min(read_buffer.size(), write_buffer.size()); std::vector fds(nfds); - std::memcpy(fds.data(), read_buffer.data(), length); + std::memcpy(fds.data(), read_buffer.data(), nfds * sizeof(PollFD)); if (timeout >= 0) { const s64 seconds = timeout / 1000; @@ -580,7 +583,7 @@ std::pair BSD::PollImpl(std::vector& write_buffer, std::span BSD::AcceptImpl(s32 fd, std::vector& write_buffer) { new_descriptor.is_connection_based = descriptor.is_connection_based; const SockAddrIn guest_addr_in = Translate(result.sockaddr_in); - const size_t length = std::min(sizeof(guest_addr_in), write_buffer.size()); - std::memcpy(write_buffer.data(), &guest_addr_in, length); + PutValue(write_buffer, guest_addr_in); return {new_fd, Errno::SUCCESS}; } @@ -619,8 +621,7 @@ Errno BSD::BindImpl(s32 fd, std::span addr) { return Errno::BADF; } ASSERT(addr.size() == sizeof(SockAddrIn)); - SockAddrIn addr_in; - std::memcpy(&addr_in, addr.data(), sizeof(addr_in)); + auto addr_in = GetValue(addr); return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in))); } @@ -631,8 +632,7 @@ Errno BSD::ConnectImpl(s32 fd, std::span addr) { } UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn)); - SockAddrIn addr_in; - std::memcpy(&addr_in, addr.data(), sizeof(addr_in)); + auto addr_in = GetValue(addr); return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in))); } @@ -650,7 +650,7 @@ Errno BSD::GetPeerNameImpl(s32 fd, std::vector& write_buffer) { ASSERT(write_buffer.size() >= sizeof(guest_addrin)); write_buffer.resize(sizeof(guest_addrin)); - std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin)); + PutValue(write_buffer, guest_addrin); return Translate(bsd_errno); } @@ -667,7 +667,7 @@ Errno BSD::GetSockNameImpl(s32 fd, std::vector& write_buffer) { ASSERT(write_buffer.size() >= sizeof(guest_addrin)); write_buffer.resize(sizeof(guest_addrin)); - std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin)); + PutValue(write_buffer, guest_addrin); return Translate(bsd_errno); } @@ -725,7 +725,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector& o optval.size() == sizeof(Errno), { return Errno::INVAL; }, "Incorrect getsockopt option size"); optval.resize(sizeof(Errno)); - memcpy(optval.data(), &translated_pending_err, sizeof(Errno)); + PutValue(optval, translated_pending_err); } return Translate(getsockopt_err); } @@ -735,7 +735,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector& o } } -Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) { +Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span optval) { if (!IsFileDescriptorValid(fd)) { return Errno::BADF; } @@ -748,17 +748,15 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, con Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); if (optname == OptName::LINGER) { - ASSERT(optlen == sizeof(Linger)); - Linger linger; - std::memcpy(&linger, optval, sizeof(linger)); + ASSERT(optval.size() == sizeof(Linger)); + auto linger = GetValue(optval); ASSERT(linger.onoff == 0 || linger.onoff == 1); return Translate(socket->SetLinger(linger.onoff != 0, linger.linger)); } - ASSERT(optlen == sizeof(u32)); - u32 value; - std::memcpy(&value, optval, sizeof(value)); + ASSERT(optval.size() == sizeof(u32)); + auto value = GetValue(optval); switch (optname) { case OptName::REUSEADDR: @@ -862,7 +860,7 @@ std::pair BSD::RecvFromImpl(s32 fd, u32 flags, std::vector& mess } else { ASSERT(addr.size() == sizeof(SockAddrIn)); const SockAddrIn result = Translate(addr_in); - std::memcpy(addr.data(), &result, sizeof(result)); + PutValue(addr, result); } } @@ -886,8 +884,7 @@ std::pair BSD::SendToImpl(s32 fd, u32 flags, std::span mes Network::SockAddrIn* p_addr_in = nullptr; if (!addr.empty()) { ASSERT(addr.size() == sizeof(SockAddrIn)); - SockAddrIn guest_addr_in; - std::memcpy(&guest_addr_in, addr.data(), sizeof(guest_addr_in)); + auto guest_addr_in = GetValue(addr); addr_in = Translate(guest_addr_in); p_addr_in = &addr_in; } diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index 4fc58bb87..a87f697f7 100755 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h @@ -163,7 +163,7 @@ private: Errno ListenImpl(s32 fd, s32 backlog); std::pair FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg); Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector& optval); - Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval); + Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span optval); Errno ShutdownImpl(s32 fd, s32 how); std::pair RecvImpl(s32 fd, u32 flags, std::vector& message); std::pair RecvFromImpl(s32 fd, u32 flags, std::vector& message, diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 40bf52db1..e9859c777 100755 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -137,6 +137,56 @@ BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWin BlitScreen::~BlitScreen() = default; +static Common::Rectangle NormalizeCrop(const Tegra::FramebufferConfig& framebuffer, + const ScreenInfo& screen_info) { + f32 left, top, right, bottom; + + if (!framebuffer.crop_rect.IsEmpty()) { + // If crop rectangle is not empty, apply properties from rectangle. + left = static_cast(framebuffer.crop_rect.left); + top = static_cast(framebuffer.crop_rect.top); + right = static_cast(framebuffer.crop_rect.right); + bottom = static_cast(framebuffer.crop_rect.bottom); + } else { + // Otherwise, fall back to framebuffer dimensions. + left = 0; + top = 0; + right = static_cast(framebuffer.width); + bottom = static_cast(framebuffer.height); + } + + // Apply transformation flags. + auto framebuffer_transform_flags = framebuffer.transform_flags; + + if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipH)) { + // Switch left and right. + std::swap(left, right); + } + if (True(framebuffer_transform_flags & Service::android::BufferTransformFlags::FlipV)) { + // Switch top and bottom. + std::swap(top, bottom); + } + + framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipH; + framebuffer_transform_flags &= ~Service::android::BufferTransformFlags::FlipV; + if (True(framebuffer_transform_flags)) { + UNIMPLEMENTED_MSG("Unsupported framebuffer_transform_flags={}", + static_cast(framebuffer_transform_flags)); + } + + // Get the screen properties. + const f32 screen_width = static_cast(screen_info.width); + const f32 screen_height = static_cast(screen_info.height); + + // Normalize coordinate space. + left /= screen_width; + top /= screen_height; + right /= screen_width; + bottom /= screen_height; + + return Common::Rectangle(left, top, right, bottom); +} + void BlitScreen::Recreate() { present_manager.WaitPresent(); scheduler.Finish(); @@ -354,17 +404,10 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, source_image_view = smaa->Draw(scheduler, image_index, source_image, source_image_view); } if (fsr) { - auto crop_rect = framebuffer.crop_rect; - if (crop_rect.GetWidth() == 0) { - crop_rect.right = framebuffer.width; - } - if (crop_rect.GetHeight() == 0) { - crop_rect.bottom = framebuffer.height; - } - crop_rect = crop_rect.Scale(Settings::values.resolution_info.up_factor); - VkExtent2D fsr_input_size{ - .width = Settings::values.resolution_info.ScaleUp(framebuffer.width), - .height = Settings::values.resolution_info.ScaleUp(framebuffer.height), + const auto crop_rect = NormalizeCrop(framebuffer, screen_info); + const VkExtent2D fsr_input_size{ + .width = Settings::values.resolution_info.ScaleUp(screen_info.width), + .height = Settings::values.resolution_info.ScaleUp(screen_info.height), }; VkImageView fsr_image_view = fsr->Draw(scheduler, image_index, source_image_view, fsr_input_size, crop_rect); @@ -1397,61 +1440,37 @@ void BlitScreen::SetUniformData(BufferData& data, const Layout::FramebufferLayou void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, const Layout::FramebufferLayout layout) const { - const auto& framebuffer_transform_flags = framebuffer.transform_flags; - const auto& framebuffer_crop_rect = framebuffer.crop_rect; + f32 left, top, right, bottom; - static constexpr Common::Rectangle texcoords{0.f, 0.f, 1.f, 1.f}; - auto left = texcoords.left; - auto right = texcoords.right; + if (fsr) { + // FSR has already applied the crop, so we just want to render the image + // it has produced. + left = 0; + top = 0; + right = 1; + bottom = 1; + } else { + // Get the normalized crop rectangle. + const auto crop = NormalizeCrop(framebuffer, screen_info); - switch (framebuffer_transform_flags) { - case Service::android::BufferTransformFlags::Unset: - break; - case Service::android::BufferTransformFlags::FlipV: - // Flip the framebuffer vertically - left = texcoords.right; - right = texcoords.left; - break; - default: - UNIMPLEMENTED_MSG("Unsupported framebuffer_transform_flags={}", - static_cast(framebuffer_transform_flags)); - break; - } - - UNIMPLEMENTED_IF(framebuffer_crop_rect.left != 0); - - f32 left_start{}; - if (framebuffer_crop_rect.Top() > 0) { - left_start = static_cast(framebuffer_crop_rect.Top()) / - static_cast(framebuffer_crop_rect.Bottom()); - } - f32 scale_u = static_cast(framebuffer.width) / static_cast(screen_info.width); - f32 scale_v = static_cast(framebuffer.height) / static_cast(screen_info.height); - // Scale the output by the crop width/height. This is commonly used with 1280x720 rendering - // (e.g. handheld mode) on a 1920x1080 framebuffer. - if (!fsr) { - if (framebuffer_crop_rect.GetWidth() > 0) { - scale_u = static_cast(framebuffer_crop_rect.GetWidth()) / - static_cast(screen_info.width); - } - if (framebuffer_crop_rect.GetHeight() > 0) { - scale_v = static_cast(framebuffer_crop_rect.GetHeight()) / - static_cast(screen_info.height); - } + // Apply the crop. + left = crop.left; + top = crop.top; + right = crop.right; + bottom = crop.bottom; } + // Map the coordinates to the screen. const auto& screen = layout.screen; const auto x = static_cast(screen.left); const auto y = static_cast(screen.top); const auto w = static_cast(screen.GetWidth()); const auto h = static_cast(screen.GetHeight()); - data.vertices[0] = ScreenRectVertex(x, y, texcoords.top * scale_u, left_start + left * scale_v); - data.vertices[1] = - ScreenRectVertex(x + w, y, texcoords.bottom * scale_u, left_start + left * scale_v); - data.vertices[2] = - ScreenRectVertex(x, y + h, texcoords.top * scale_u, left_start + right * scale_v); - data.vertices[3] = - ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, left_start + right * scale_v); + + data.vertices[0] = ScreenRectVertex(x, y, left, top); + data.vertices[1] = ScreenRectVertex(x + w, y, right, top); + data.vertices[2] = ScreenRectVertex(x, y + h, left, bottom); + data.vertices[3] = ScreenRectVertex(x + w, y + h, right, bottom); } void BlitScreen::CreateSMAA(VkExtent2D smaa_size) { diff --git a/src/video_core/renderer_vulkan/vk_fsr.cpp b/src/video_core/renderer_vulkan/vk_fsr.cpp index e0bf4e679..440a91f9a 100755 --- a/src/video_core/renderer_vulkan/vk_fsr.cpp +++ b/src/video_core/renderer_vulkan/vk_fsr.cpp @@ -34,7 +34,7 @@ FSR::FSR(const Device& device_, MemoryAllocator& memory_allocator_, size_t image } VkImageView FSR::Draw(Scheduler& scheduler, size_t image_index, VkImageView image_view, - VkExtent2D input_image_extent, const Common::Rectangle& crop_rect) { + VkExtent2D input_image_extent, const Common::Rectangle& crop_rect) { UpdateDescriptorSet(image_index, image_view); @@ -61,15 +61,21 @@ VkImageView FSR::Draw(Scheduler& scheduler, size_t image_index, VkImageView imag cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *easu_pipeline); - std::array push_constants; - FsrEasuConOffset( - push_constants.data() + 0, push_constants.data() + 4, push_constants.data() + 8, - push_constants.data() + 12, + const f32 input_image_width = static_cast(input_image_extent.width); + const f32 input_image_height = static_cast(input_image_extent.height); + const f32 output_image_width = static_cast(output_size.width); + const f32 output_image_height = static_cast(output_size.height); + const f32 viewport_width = (crop_rect.right - crop_rect.left) * input_image_width; + const f32 viewport_x = crop_rect.left * input_image_width; + const f32 viewport_height = (crop_rect.bottom - crop_rect.top) * input_image_height; + const f32 viewport_y = crop_rect.top * input_image_height; - static_cast(crop_rect.GetWidth()), static_cast(crop_rect.GetHeight()), - static_cast(input_image_extent.width), static_cast(input_image_extent.height), - static_cast(output_size.width), static_cast(output_size.height), - static_cast(crop_rect.left), static_cast(crop_rect.top)); + std::array push_constants; + FsrEasuConOffset(push_constants.data() + 0, push_constants.data() + 4, + push_constants.data() + 8, push_constants.data() + 12, + + viewport_width, viewport_height, input_image_width, input_image_height, + output_image_width, output_image_height, viewport_x, viewport_y); cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, push_constants); { diff --git a/src/video_core/renderer_vulkan/vk_fsr.h b/src/video_core/renderer_vulkan/vk_fsr.h index 4f1ecc3ee..e285ca907 100755 --- a/src/video_core/renderer_vulkan/vk_fsr.h +++ b/src/video_core/renderer_vulkan/vk_fsr.h @@ -17,7 +17,7 @@ public: explicit FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, VkExtent2D output_size); VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImageView image_view, - VkExtent2D input_image_extent, const Common::Rectangle& crop_rect); + VkExtent2D input_image_extent, const Common::Rectangle& crop_rect); private: void CreateDescriptorPool(); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 5b0e7c8a0..6a4da6528 100755 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -62,6 +62,7 @@ struct DrawParams { VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) { const auto& src = regs.viewport_transform[index]; + const u32 rt_height = src.scale_y != 0 ? regs.rt[index].height : 0; const auto conv = [scale](float value) { float new_value = value * scale; if (scale < 1.0f) { @@ -82,7 +83,7 @@ VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t in } if (y_negate) { - y += height; + y += conv(static_cast(rt_height)); height = -height; } diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index 3fe448f27..1434b1a56 100755 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -156,7 +156,6 @@ std::unique_ptr InitializeTranslations(QWidget* parent) { // Ui General INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", ""); INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", ""); - INSERT(UISettings, confirm_before_closing, "Confirm exit while emulation is running", ""); INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", ""); INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", ""); INSERT(UISettings, controller_applet_disabled, "Disable controller applet", ""); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index b80cb8c38..d9e3c39d3 100755 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -4847,7 +4847,12 @@ bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installe } bool GMainWindow::ConfirmClose() { - if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) { + if (emu_thread == nullptr || + UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Never) { + return true; + } + if (!system->GetExitLocked() && + UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Based_On_Game) { return true; } const auto text = tr("Are you sure you want to close yuzu?"); @@ -4952,7 +4957,7 @@ bool GMainWindow::ConfirmChangeGame() { } bool GMainWindow::ConfirmForceLockedExit() { - if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) { + if (emu_thread == nullptr) { return true; } const auto text = tr("The currently running application has requested yuzu to not exit.\n\n" diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 06562b1c7..c2c33cb91 100755 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -93,10 +93,6 @@ struct Values { Setting show_filter_bar{linkage, true, "showFilterBar", Category::Ui}; Setting show_status_bar{linkage, true, "showStatusBar", Category::Ui}; - Setting confirm_before_closing{ - linkage, true, "confirmClose", Category::UiGeneral, Settings::Specialization::Default, - true, true}; - SwitchableSetting confirm_before_stopping{linkage, ConfirmStop::Ask_Always, "confirmStop",