early-access version 3953

main
pineappleEA 2023-10-30 06:57:51 +01:00
parent e0a0f1dbda
commit b40dc6dc14
22 changed files with 250 additions and 139 deletions

View File

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 3952. This is the source code for early-access 3953.
## Legal Notice ## Legal Notice

View File

@ -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);
@ -796,7 +805,9 @@ ILockAccessor::ILockAccessor(Core::System& system_)
lock_event = service_context.CreateEvent("ILockAccessor::LockEvent"); lock_event = service_context.CreateEvent("ILockAccessor::LockEvent");
} }
ILockAccessor::~ILockAccessor() = default; ILockAccessor::~ILockAccessor() {
service_context.CloseEvent(lock_event);
};
void ILockAccessor::TryLock(HLERequestContext& ctx) { void ILockAccessor::TryLock(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
@ -909,7 +920,9 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
} }
ICommonStateGetter::~ICommonStateGetter() = default; ICommonStateGetter::~ICommonStateGetter() {
service_context.CloseEvent(sleep_lock_event);
};
void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) { void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called"); LOG_DEBUG(Service_AM, "called");

View File

@ -25,7 +25,9 @@ Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_,
service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent"); service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent");
} }
Cabinet::~Cabinet() = default; Cabinet::~Cabinet() {
service_context.CloseEvent(availability_change_event);
};
void Cabinet::Initialize() { void Cabinet::Initialize() {
Applet::Initialize(); Applet::Initialize();

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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;
}; };

View File

@ -19,7 +19,9 @@ Controller_Palma::Controller_Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared
operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent"); 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() {} void Controller_Palma::OnInit() {}

View File

@ -2757,6 +2757,10 @@ public:
joy_detach_event = service_context.CreateEvent("HidSys::JoyDetachEvent"); joy_detach_event = service_context.CreateEvent("HidSys::JoyDetachEvent");
} }
~HidSys() {
service_context.CloseEvent(joy_detach_event);
};
private: private:
void ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) { void ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "called"); LOG_WARNING(Service_HID, "called");

View File

@ -13,7 +13,10 @@ HidbusBase::HidbusBase(Core::System& system_, KernelHelpers::ServiceContext& ser
: system(system_), service_context(service_context_) { : system(system_), service_context(service_context_) {
send_command_async_event = service_context.CreateEvent("hidbus:SendCommandAsyncEvent"); send_command_async_event = service_context.CreateEvent("hidbus:SendCommandAsyncEvent");
} }
HidbusBase::~HidbusBase() = default;
HidbusBase::~HidbusBase() {
service_context.CloseEvent(send_command_async_event);
};
void HidbusBase::ActivateDevice() { void HidbusBase::ActivateDevice() {
if (is_activated) { if (is_activated) {

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
namespace Service::android { namespace Service::android {
@ -21,5 +22,6 @@ enum class BufferTransformFlags : u32 {
/// Rotate source image 270 degrees clockwise /// Rotate source image 270 degrees clockwise
Rotate270 = 0x07, Rotate270 = 0x07,
}; };
DECLARE_ENUM_FLAG_OPERATORS(BufferTransformFlags);
} // namespace Service::android } // namespace Service::android

View File

@ -141,6 +141,12 @@ public:
service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent"); service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent");
} }
~IParentalControlService() {
service_context.CloseEvent(synchronization_event);
service_context.CloseEvent(unlinked_event);
service_context.CloseEvent(request_suspension_event);
};
private: private:
bool CheckFreeCommunicationPermissionImpl() const { bool CheckFreeCommunicationPermissionImpl() const {
if (states.temporary_unlocked) { if (states.temporary_unlocked) {

View File

@ -39,6 +39,18 @@ bool IsConnectionBased(Type type) {
} }
} }
template <typename T>
T GetValue(std::span<const u8> buffer) {
T t{};
std::memcpy(&t, buffer.data(), std::min(sizeof(T), buffer.size()));
return t;
}
template <typename T>
void PutValue(std::span<u8> buffer, const T& t) {
std::memcpy(buffer.data(), &t, std::min(sizeof(T), buffer.size()));
}
} // Anonymous namespace } // Anonymous namespace
void BSD::PollWork::Execute(BSD* bsd) { void BSD::PollWork::Execute(BSD* bsd) {
@ -316,22 +328,12 @@ void BSD::SetSockOpt(HLERequestContext& ctx) {
const s32 fd = rp.Pop<s32>(); const s32 fd = rp.Pop<s32>();
const u32 level = rp.Pop<u32>(); const u32 level = rp.Pop<u32>();
const OptName optname = static_cast<OptName>(rp.Pop<u32>()); const OptName optname = static_cast<OptName>(rp.Pop<u32>());
const auto optval = ctx.ReadBuffer();
const auto buffer = ctx.ReadBuffer();
const u8* optval = buffer.empty() ? nullptr : buffer.data();
size_t optlen = buffer.size();
std::array<u64, 2> 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<const u8*>(values.data());
}
LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} optlen={}", fd, level, LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} optlen={}", fd, level,
static_cast<u32>(optname), optlen); static_cast<u32>(optname), optval.size());
BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optlen, optval)); BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval));
} }
void BSD::Shutdown(HLERequestContext& ctx) { void BSD::Shutdown(HLERequestContext& ctx) {
@ -521,18 +523,19 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
s32 nfds, s32 timeout) { 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)) { if (write_buffer.size() < nfds * sizeof(PollFD)) {
return {-1, Errno::INVAL}; 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<PollFD> fds(nfds); std::vector<PollFD> fds(nfds);
std::memcpy(fds.data(), read_buffer.data(), length); std::memcpy(fds.data(), read_buffer.data(), nfds * sizeof(PollFD));
if (timeout >= 0) { if (timeout >= 0) {
const s64 seconds = timeout / 1000; const s64 seconds = timeout / 1000;
@ -580,7 +583,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con
for (size_t i = 0; i < num; ++i) { for (size_t i = 0; i < num; ++i) {
fds[i].revents = Translate(host_pollfds[i].revents); fds[i].revents = Translate(host_pollfds[i].revents);
} }
std::memcpy(write_buffer.data(), fds.data(), length); std::memcpy(write_buffer.data(), fds.data(), nfds * sizeof(PollFD));
return Translate(result); return Translate(result);
} }
@ -608,8 +611,7 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
new_descriptor.is_connection_based = descriptor.is_connection_based; new_descriptor.is_connection_based = descriptor.is_connection_based;
const SockAddrIn guest_addr_in = Translate(result.sockaddr_in); const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
const size_t length = std::min(sizeof(guest_addr_in), write_buffer.size()); PutValue(write_buffer, guest_addr_in);
std::memcpy(write_buffer.data(), &guest_addr_in, length);
return {new_fd, Errno::SUCCESS}; return {new_fd, Errno::SUCCESS};
} }
@ -619,8 +621,7 @@ Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
return Errno::BADF; return Errno::BADF;
} }
ASSERT(addr.size() == sizeof(SockAddrIn)); ASSERT(addr.size() == sizeof(SockAddrIn));
SockAddrIn addr_in; auto addr_in = GetValue<SockAddrIn>(addr);
std::memcpy(&addr_in, addr.data(), sizeof(addr_in));
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in))); return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
} }
@ -631,8 +632,7 @@ Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
} }
UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn)); UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn));
SockAddrIn addr_in; auto addr_in = GetValue<SockAddrIn>(addr);
std::memcpy(&addr_in, addr.data(), sizeof(addr_in));
return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in))); return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in)));
} }
@ -650,7 +650,7 @@ Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
ASSERT(write_buffer.size() >= sizeof(guest_addrin)); ASSERT(write_buffer.size() >= sizeof(guest_addrin));
write_buffer.resize(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); return Translate(bsd_errno);
} }
@ -667,7 +667,7 @@ Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
ASSERT(write_buffer.size() >= sizeof(guest_addrin)); ASSERT(write_buffer.size() >= sizeof(guest_addrin));
write_buffer.resize(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); return Translate(bsd_errno);
} }
@ -725,7 +725,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& o
optval.size() == sizeof(Errno), { return Errno::INVAL; }, optval.size() == sizeof(Errno), { return Errno::INVAL; },
"Incorrect getsockopt option size"); "Incorrect getsockopt option size");
optval.resize(sizeof(Errno)); optval.resize(sizeof(Errno));
memcpy(optval.data(), &translated_pending_err, sizeof(Errno)); PutValue(optval, translated_pending_err);
} }
return Translate(getsockopt_err); return Translate(getsockopt_err);
} }
@ -735,7 +735,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& 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<const u8> optval) {
if (!IsFileDescriptorValid(fd)) { if (!IsFileDescriptorValid(fd)) {
return Errno::BADF; 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(); Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
if (optname == OptName::LINGER) { if (optname == OptName::LINGER) {
ASSERT(optlen == sizeof(Linger)); ASSERT(optval.size() == sizeof(Linger));
Linger linger; auto linger = GetValue<Linger>(optval);
std::memcpy(&linger, optval, sizeof(linger));
ASSERT(linger.onoff == 0 || linger.onoff == 1); ASSERT(linger.onoff == 0 || linger.onoff == 1);
return Translate(socket->SetLinger(linger.onoff != 0, linger.linger)); return Translate(socket->SetLinger(linger.onoff != 0, linger.linger));
} }
ASSERT(optlen == sizeof(u32)); ASSERT(optval.size() == sizeof(u32));
u32 value; auto value = GetValue<u32>(optval);
std::memcpy(&value, optval, sizeof(value));
switch (optname) { switch (optname) {
case OptName::REUSEADDR: case OptName::REUSEADDR:
@ -862,7 +860,7 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
} else { } else {
ASSERT(addr.size() == sizeof(SockAddrIn)); ASSERT(addr.size() == sizeof(SockAddrIn));
const SockAddrIn result = Translate(addr_in); const SockAddrIn result = Translate(addr_in);
std::memcpy(addr.data(), &result, sizeof(result)); PutValue(addr, result);
} }
} }
@ -886,8 +884,7 @@ std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> mes
Network::SockAddrIn* p_addr_in = nullptr; Network::SockAddrIn* p_addr_in = nullptr;
if (!addr.empty()) { if (!addr.empty()) {
ASSERT(addr.size() == sizeof(SockAddrIn)); ASSERT(addr.size() == sizeof(SockAddrIn));
SockAddrIn guest_addr_in; auto guest_addr_in = GetValue<SockAddrIn>(addr);
std::memcpy(&guest_addr_in, addr.data(), sizeof(guest_addr_in));
addr_in = Translate(guest_addr_in); addr_in = Translate(guest_addr_in);
p_addr_in = &addr_in; p_addr_in = &addr_in;
} }

View File

@ -163,7 +163,7 @@ private:
Errno ListenImpl(s32 fd, s32 backlog); Errno ListenImpl(s32 fd, s32 backlog);
std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg); std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg);
Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval); Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& 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<const u8> optval);
Errno ShutdownImpl(s32 fd, s32 how); Errno ShutdownImpl(s32 fd, s32 how);
std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message); std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,

View File

@ -137,6 +137,56 @@ BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWin
BlitScreen::~BlitScreen() = default; BlitScreen::~BlitScreen() = default;
static Common::Rectangle<f32> 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<f32>(framebuffer.crop_rect.left);
top = static_cast<f32>(framebuffer.crop_rect.top);
right = static_cast<f32>(framebuffer.crop_rect.right);
bottom = static_cast<f32>(framebuffer.crop_rect.bottom);
} else {
// Otherwise, fall back to framebuffer dimensions.
left = 0;
top = 0;
right = static_cast<f32>(framebuffer.width);
bottom = static_cast<f32>(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<u32>(framebuffer_transform_flags));
}
// Get the screen properties.
const f32 screen_width = static_cast<f32>(screen_info.width);
const f32 screen_height = static_cast<f32>(screen_info.height);
// Normalize coordinate space.
left /= screen_width;
top /= screen_height;
right /= screen_width;
bottom /= screen_height;
return Common::Rectangle<f32>(left, top, right, bottom);
}
void BlitScreen::Recreate() { void BlitScreen::Recreate() {
present_manager.WaitPresent(); present_manager.WaitPresent();
scheduler.Finish(); 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); source_image_view = smaa->Draw(scheduler, image_index, source_image, source_image_view);
} }
if (fsr) { if (fsr) {
auto crop_rect = framebuffer.crop_rect; const auto crop_rect = NormalizeCrop(framebuffer, screen_info);
if (crop_rect.GetWidth() == 0) { const VkExtent2D fsr_input_size{
crop_rect.right = framebuffer.width; .width = Settings::values.resolution_info.ScaleUp(screen_info.width),
} .height = Settings::values.resolution_info.ScaleUp(screen_info.height),
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),
}; };
VkImageView fsr_image_view = VkImageView fsr_image_view =
fsr->Draw(scheduler, image_index, source_image_view, fsr_input_size, crop_rect); 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, void BlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer,
const Layout::FramebufferLayout layout) const { const Layout::FramebufferLayout layout) const {
const auto& framebuffer_transform_flags = framebuffer.transform_flags; f32 left, top, right, bottom;
const auto& framebuffer_crop_rect = framebuffer.crop_rect;
static constexpr Common::Rectangle<f32> texcoords{0.f, 0.f, 1.f, 1.f}; if (fsr) {
auto left = texcoords.left; // FSR has already applied the crop, so we just want to render the image
auto right = texcoords.right; // 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) { // Apply the crop.
case Service::android::BufferTransformFlags::Unset: left = crop.left;
break; top = crop.top;
case Service::android::BufferTransformFlags::FlipV: right = crop.right;
// Flip the framebuffer vertically bottom = crop.bottom;
left = texcoords.right;
right = texcoords.left;
break;
default:
UNIMPLEMENTED_MSG("Unsupported framebuffer_transform_flags={}",
static_cast<u32>(framebuffer_transform_flags));
break;
}
UNIMPLEMENTED_IF(framebuffer_crop_rect.left != 0);
f32 left_start{};
if (framebuffer_crop_rect.Top() > 0) {
left_start = static_cast<f32>(framebuffer_crop_rect.Top()) /
static_cast<f32>(framebuffer_crop_rect.Bottom());
}
f32 scale_u = static_cast<f32>(framebuffer.width) / static_cast<f32>(screen_info.width);
f32 scale_v = static_cast<f32>(framebuffer.height) / static_cast<f32>(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<f32>(framebuffer_crop_rect.GetWidth()) /
static_cast<f32>(screen_info.width);
}
if (framebuffer_crop_rect.GetHeight() > 0) {
scale_v = static_cast<f32>(framebuffer_crop_rect.GetHeight()) /
static_cast<f32>(screen_info.height);
}
} }
// Map the coordinates to the screen.
const auto& screen = layout.screen; const auto& screen = layout.screen;
const auto x = static_cast<f32>(screen.left); const auto x = static_cast<f32>(screen.left);
const auto y = static_cast<f32>(screen.top); const auto y = static_cast<f32>(screen.top);
const auto w = static_cast<f32>(screen.GetWidth()); const auto w = static_cast<f32>(screen.GetWidth());
const auto h = static_cast<f32>(screen.GetHeight()); const auto h = static_cast<f32>(screen.GetHeight());
data.vertices[0] = ScreenRectVertex(x, y, texcoords.top * scale_u, left_start + left * scale_v);
data.vertices[1] = data.vertices[0] = ScreenRectVertex(x, y, left, top);
ScreenRectVertex(x + w, y, texcoords.bottom * scale_u, left_start + left * scale_v); data.vertices[1] = ScreenRectVertex(x + w, y, right, top);
data.vertices[2] = data.vertices[2] = ScreenRectVertex(x, y + h, left, bottom);
ScreenRectVertex(x, y + h, texcoords.top * scale_u, left_start + right * scale_v); data.vertices[3] = ScreenRectVertex(x + w, y + h, right, bottom);
data.vertices[3] =
ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, left_start + right * scale_v);
} }
void BlitScreen::CreateSMAA(VkExtent2D smaa_size) { void BlitScreen::CreateSMAA(VkExtent2D smaa_size) {

View File

@ -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, VkImageView FSR::Draw(Scheduler& scheduler, size_t image_index, VkImageView image_view,
VkExtent2D input_image_extent, const Common::Rectangle<int>& crop_rect) { VkExtent2D input_image_extent, const Common::Rectangle<f32>& crop_rect) {
UpdateDescriptorSet(image_index, image_view); 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); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *easu_pipeline);
std::array<u32, 4 * 4> push_constants; const f32 input_image_width = static_cast<f32>(input_image_extent.width);
FsrEasuConOffset( const f32 input_image_height = static_cast<f32>(input_image_extent.height);
push_constants.data() + 0, push_constants.data() + 4, push_constants.data() + 8, const f32 output_image_width = static_cast<f32>(output_size.width);
push_constants.data() + 12, const f32 output_image_height = static_cast<f32>(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<f32>(crop_rect.GetWidth()), static_cast<f32>(crop_rect.GetHeight()), std::array<u32, 4 * 4> push_constants;
static_cast<f32>(input_image_extent.width), static_cast<f32>(input_image_extent.height), FsrEasuConOffset(push_constants.data() + 0, push_constants.data() + 4,
static_cast<f32>(output_size.width), static_cast<f32>(output_size.height), push_constants.data() + 8, push_constants.data() + 12,
static_cast<f32>(crop_rect.left), static_cast<f32>(crop_rect.top));
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); cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, push_constants);
{ {

View File

@ -17,7 +17,7 @@ public:
explicit FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count, explicit FSR(const Device& device, MemoryAllocator& memory_allocator, size_t image_count,
VkExtent2D output_size); VkExtent2D output_size);
VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImageView image_view, VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImageView image_view,
VkExtent2D input_image_extent, const Common::Rectangle<int>& crop_rect); VkExtent2D input_image_extent, const Common::Rectangle<f32>& crop_rect);
private: private:
void CreateDescriptorPool(); void CreateDescriptorPool();

View File

@ -62,6 +62,7 @@ struct DrawParams {
VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) { VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) {
const auto& src = regs.viewport_transform[index]; 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) { const auto conv = [scale](float value) {
float new_value = value * scale; float new_value = value * scale;
if (scale < 1.0f) { if (scale < 1.0f) {
@ -82,7 +83,7 @@ VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t in
} }
if (y_negate) { if (y_negate) {
y += height; y += conv(static_cast<f32>(rt_height));
height = -height; height = -height;
} }

View File

@ -156,7 +156,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
// Ui General // Ui General
INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", ""); 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, 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, confirm_before_stopping, "Confirm before stopping emulation", "");
INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", ""); INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", "");
INSERT(UISettings, controller_applet_disabled, "Disable controller applet", ""); INSERT(UISettings, controller_applet_disabled, "Disable controller applet", "");

View File

@ -4847,7 +4847,12 @@ bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installe
} }
bool GMainWindow::ConfirmClose() { 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; return true;
} }
const auto text = tr("Are you sure you want to close yuzu?"); const auto text = tr("Are you sure you want to close yuzu?");
@ -4952,7 +4957,7 @@ bool GMainWindow::ConfirmChangeGame() {
} }
bool GMainWindow::ConfirmForceLockedExit() { bool GMainWindow::ConfirmForceLockedExit() {
if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) { if (emu_thread == nullptr) {
return true; return true;
} }
const auto text = tr("The currently running application has requested yuzu to not exit.\n\n" const auto text = tr("The currently running application has requested yuzu to not exit.\n\n"

View File

@ -93,10 +93,6 @@ struct Values {
Setting<bool> show_filter_bar{linkage, true, "showFilterBar", Category::Ui}; Setting<bool> show_filter_bar{linkage, true, "showFilterBar", Category::Ui};
Setting<bool> show_status_bar{linkage, true, "showStatusBar", Category::Ui}; Setting<bool> show_status_bar{linkage, true, "showStatusBar", Category::Ui};
Setting<bool> confirm_before_closing{
linkage, true, "confirmClose", Category::UiGeneral, Settings::Specialization::Default,
true, true};
SwitchableSetting<ConfirmStop> confirm_before_stopping{linkage, SwitchableSetting<ConfirmStop> confirm_before_stopping{linkage,
ConfirmStop::Ask_Always, ConfirmStop::Ask_Always,
"confirmStop", "confirmStop",