Merge branch 'yuzu-emu:master' into new-shortcut

This commit is contained in:
Franco M 2023-10-26 19:11:15 -03:00 committed by GitHub
commit b5415b6872
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 11687 additions and 9925 deletions

View file

@ -147,3 +147,7 @@ License: GPL-3.0-or-later
Files: src/android/gradle/wrapper/* Files: src/android/gradle/wrapper/*
Copyright: 2023 yuzu Emulator Project Copyright: 2023 yuzu Emulator Project
License: GPL-3.0-or-later License: GPL-3.0-or-later
Files: externals/stb/*
Copyright: Sean Barrett
License: MIT

View file

@ -294,6 +294,7 @@ find_package(lz4 REQUIRED)
find_package(nlohmann_json 3.8 REQUIRED) find_package(nlohmann_json 3.8 REQUIRED)
find_package(Opus 1.3 MODULE) find_package(Opus 1.3 MODULE)
find_package(RenderDoc MODULE) find_package(RenderDoc MODULE)
find_package(stb MODULE)
find_package(VulkanMemoryAllocator CONFIG) find_package(VulkanMemoryAllocator CONFIG)
find_package(ZLIB 1.2 REQUIRED) find_package(ZLIB 1.2 REQUIRED)
find_package(zstd 1.5 REQUIRED) find_package(zstd 1.5 REQUIRED)

View file

@ -0,0 +1,31 @@
# SPDX-FileCopyrightText: 2023 Alexandre Bouvier <contact@amb.tf>
#
# SPDX-License-Identifier: GPL-3.0-or-later
find_path(stb_image_INCLUDE_DIR stb_image.h PATH_SUFFIXES stb)
find_path(stb_image_resize_INCLUDE_DIR stb_image_resize.h PATH_SUFFIXES stb)
find_path(stb_image_write_INCLUDE_DIR stb_image_write.h PATH_SUFFIXES stb)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(stb
REQUIRED_VARS
stb_image_INCLUDE_DIR
stb_image_resize_INCLUDE_DIR
stb_image_write_INCLUDE_DIR
)
if (stb_FOUND AND NOT TARGET stb::headers)
add_library(stb::headers INTERFACE IMPORTED)
set_property(TARGET stb::headers PROPERTY
INTERFACE_INCLUDE_DIRECTORIES
"${stb_image_INCLUDE_DIR}"
"${stb_image_resize_INCLUDE_DIR}"
"${stb_image_write_INCLUDE_DIR}"
)
endif()
mark_as_advanced(
stb_image_INCLUDE_DIR
stb_image_resize_INCLUDE_DIR
stb_image_write_INCLUDE_DIR
)

View file

@ -168,9 +168,13 @@ if (NOT TARGET LLVM::Demangle)
add_library(LLVM::Demangle ALIAS demangle) add_library(LLVM::Demangle ALIAS demangle)
endif() endif()
add_library(stb stb/stb_dxt.cpp stb/stb_image.cpp stb/stb_image_resize.cpp) add_library(stb stb/stb_dxt.cpp)
target_include_directories(stb PUBLIC ./stb) target_include_directories(stb PUBLIC ./stb)
if (NOT TARGET stb::headers)
add_library(stb::headers ALIAS stb)
endif()
add_library(bc_decoder bc_decoder/bc_decoder.cpp) add_library(bc_decoder bc_decoder/bc_decoder.cpp)
target_include_directories(bc_decoder PUBLIC ./bc_decoder) target_include_directories(bc_decoder PUBLIC ./bc_decoder)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

1724
externals/stb/stb_image_write.h vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -120,6 +120,8 @@ add_library(common STATIC
socket_types.h socket_types.h
spin_lock.cpp spin_lock.cpp
spin_lock.h spin_lock.h
stb.cpp
stb.h
steady_clock.cpp steady_clock.cpp
steady_clock.h steady_clock.h
stream.cpp stream.cpp
@ -208,6 +210,8 @@ if (MSVC)
/we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
/we4800 # Implicit conversion from 'type' to bool. Possible information loss /we4800 # Implicit conversion from 'type' to bool. Possible information loss
) )
else()
set_source_files_properties(stb.cpp PROPERTIES COMPILE_OPTIONS "-Wno-implicit-fallthrough;-Wno-missing-declarations;-Wno-missing-field-initializers")
endif() endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
@ -223,7 +227,7 @@ endif()
create_target_directory_groups(common) create_target_directory_groups(common)
target_link_libraries(common PUBLIC Boost::context Boost::headers fmt::fmt microprofile Threads::Threads) target_link_libraries(common PUBLIC Boost::context Boost::headers fmt::fmt microprofile stb::headers Threads::Threads)
target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd LLVM::Demangle) target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd LLVM::Demangle)
if (ANDROID) if (ANDROID)

8
src/common/stb.cpp Normal file
View file

@ -0,0 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "common/stb.h"

8
src/common/stb.h Normal file
View file

@ -0,0 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <stb_image.h>
#include <stb_image_resize.h>
#include <stb_image_write.h>

View file

@ -11,6 +11,7 @@
#include <mach/mach.h> #include <mach/mach.h>
#elif defined(_WIN32) #elif defined(_WIN32)
#include <windows.h> #include <windows.h>
#include "common/string_util.h"
#else #else
#if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) #if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#include <pthread_np.h> #include <pthread_np.h>
@ -82,29 +83,8 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
#ifdef _MSC_VER #ifdef _MSC_VER
// Sets the debugger-visible name of the current thread. // Sets the debugger-visible name of the current thread.
// Uses trick documented in:
// https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code
void SetCurrentThreadName(const char* name) { void SetCurrentThreadName(const char* name) {
static const DWORD MS_VC_EXCEPTION = 0x406D1388; SetThreadDescription(GetCurrentThread(), UTF8ToUTF16W(name).data());
#pragma pack(push, 8)
struct THREADNAME_INFO {
DWORD dwType; // must be 0x1000
LPCSTR szName; // pointer to name (in user addr space)
DWORD dwThreadID; // thread ID (-1=caller thread)
DWORD dwFlags; // reserved for future use, must be zero
} info;
#pragma pack(pop)
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = std::numeric_limits<DWORD>::max();
info.dwFlags = 0;
__try {
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
} __except (EXCEPTION_CONTINUE_EXECUTION) {
}
} }
#else // !MSVC_VER, so must be POSIX threads #else // !MSVC_VER, so must be POSIX threads

View file

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/file_sys/system_archive/system_version.h" #include "core/file_sys/system_archive/system_version.h"
#include "core/file_sys/vfs_vector.h" #include "core/file_sys/vfs_vector.h"
#include "core/hle/api_version.h" #include "core/hle/api_version.h"
@ -12,6 +13,9 @@ std::string GetLongDisplayVersion() {
} }
VirtualDir SystemVersion() { VirtualDir SystemVersion() {
LOG_WARNING(Common_Filesystem, "called - Using hardcoded firmware version '{}'",
GetLongDisplayVersion());
VirtualFile file = std::make_shared<VectorVfsFile>(std::vector<u8>(0x100), "file"); VirtualFile file = std::make_shared<VectorVfsFile>(std::vector<u8>(0x100), "file");
file->WriteObject(HLE::ApiVersion::HOS_VERSION_MAJOR, 0); file->WriteObject(HLE::ApiVersion::HOS_VERSION_MAJOR, 0);
file->WriteObject(HLE::ApiVersion::HOS_VERSION_MINOR, 1); file->WriteObject(HLE::ApiVersion::HOS_VERSION_MINOR, 1);

View file

@ -25,11 +25,12 @@ void LoopProcess(Core::System& system) {
server_manager->RegisterNamedService( server_manager->RegisterNamedService(
"caps:u", std::make_shared<IAlbumApplicationService>(system, album_manager)); "caps:u", std::make_shared<IAlbumApplicationService>(system, album_manager));
server_manager->RegisterNamedService("caps:ss", std::make_shared<IScreenShotService>(system)); server_manager->RegisterNamedService(
"caps:ss", std::make_shared<IScreenShotService>(system, album_manager));
server_manager->RegisterNamedService("caps:sc", server_manager->RegisterNamedService("caps:sc",
std::make_shared<IScreenShotControlService>(system)); std::make_shared<IScreenShotControlService>(system));
server_manager->RegisterNamedService("caps:su", server_manager->RegisterNamedService(
std::make_shared<IScreenShotApplicationService>(system)); "caps:su", std::make_shared<IScreenShotApplicationService>(system, album_manager));
ServerManager::RunServer(std::move(server_manager)); ServerManager::RunServer(std::move(server_manager));
} }

View file

@ -2,12 +2,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <sstream> #include <sstream>
#include <stb_image.h>
#include <stb_image_resize.h>
#include "common/fs/file.h" #include "common/fs/file.h"
#include "common/fs/path_util.h" #include "common/fs/path_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/stb.h"
#include "core/core.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_result.h" #include "core/hle/service/caps/caps_result.h"
@ -227,6 +226,49 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail(
+static_cast<int>(out_image_output.height), decoder_options.flags); +static_cast<int>(out_image_output.height), decoder_options.flags);
} }
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
const ScreenShotAttribute& attribute,
std::span<const u8> image_data, u64 aruid) {
return SaveScreenShot(out_entry, attribute, {}, image_data, aruid);
}
Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
const ScreenShotAttribute& attribute,
const ApplicationData& app_data, std::span<const u8> image_data,
u64 aruid) {
const u64 title_id = system.GetApplicationProcessProgramID();
const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore();
s64 posix_time{};
Result result = user_clock.GetCurrentTime(system, posix_time);
if (result.IsError()) {
return result;
}
const auto date = ConvertToAlbumDateTime(posix_time);
return SaveImage(out_entry, image_data, title_id, date);
}
Result AlbumManager::SaveEditedScreenShot(ApplicationAlbumEntry& out_entry,
const ScreenShotAttribute& attribute,
const AlbumFileId& file_id,
std::span<const u8> image_data) {
const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore();
s64 posix_time{};
Result result = user_clock.GetCurrentTime(system, posix_time);
if (result.IsError()) {
return result;
}
const auto date = ConvertToAlbumDateTime(posix_time);
return SaveImage(out_entry, image_data, file_id.application_id, date);
}
Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const { Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const {
const auto file = album_files.find(file_id); const auto file = album_files.find(file_id);
@ -365,6 +407,47 @@ Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::p
return ResultSuccess; return ResultSuccess;
} }
static void PNGToMemory(void* context, void* png, int len) {
std::vector<u8>* png_image = static_cast<std::vector<u8>*>(context);
png_image->reserve(len);
std::memcpy(png_image->data(), png, len);
}
Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image,
u64 title_id, const AlbumFileDateTime& date) const {
const auto screenshot_path =
Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir);
const std::string formatted_date =
fmt::format("{:04}-{:02}-{:02}_{:02}-{:02}-{:02}-{:03}", date.year, date.month, date.day,
date.hour, date.minute, date.second, 0);
const std::string file_path =
fmt::format("{}/{:016x}_{}.png", screenshot_path, title_id, formatted_date);
const Common::FS::IOFile db_file{file_path, Common::FS::FileAccessMode::Write,
Common::FS::FileType::BinaryFile};
std::vector<u8> png_image;
if (!stbi_write_png_to_func(PNGToMemory, &png_image, 1280, 720, STBI_rgb_alpha, image.data(),
0)) {
return ResultFileCountLimit;
}
if (db_file.Write(png_image) != png_image.size()) {
return ResultFileCountLimit;
}
out_entry = {
.size = png_image.size(),
.hash = {},
.datetime = date,
.storage = AlbumStorage::Sd,
.content = ContentType::Screenshot,
.unknown = 1,
};
return ResultSuccess;
}
AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const { AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const {
Time::TimeZone::CalendarInfo calendar_date{}; Time::TimeZone::CalendarInfo calendar_date{};
const auto& time_zone_manager = const auto& time_zone_manager =

View file

@ -58,6 +58,15 @@ public:
std::vector<u8>& out_image, const AlbumFileId& file_id, std::vector<u8>& out_image, const AlbumFileId& file_id,
const ScreenShotDecodeOption& decoder_options) const; const ScreenShotDecodeOption& decoder_options) const;
Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute,
std::span<const u8> image_data, u64 aruid);
Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute,
const ApplicationData& app_data, std::span<const u8> image_data,
u64 aruid);
Result SaveEditedScreenShot(ApplicationAlbumEntry& out_entry,
const ScreenShotAttribute& attribute, const AlbumFileId& file_id,
std::span<const u8> image_data);
private: 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;
@ -67,6 +76,8 @@ private:
Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const; Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const;
Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width, Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width,
int height, ScreenShotDecoderFlag flag) const; int height, ScreenShotDecoderFlag flag) const;
Result SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image, u64 title_id,
const AlbumFileDateTime& date) const;
AlbumFileDateTime ConvertToAlbumDateTime(u64 posix_time) const; AlbumFileDateTime ConvertToAlbumDateTime(u64 posix_time) const;

View file

@ -1,19 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/hle/service/caps/caps_manager.h"
#include "core/hle/service/caps/caps_types.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/caps/caps_ss.h" #include "core/hle/service/caps/caps_ss.h"
namespace Service::Capture { namespace Service::Capture {
IScreenShotService::IScreenShotService(Core::System& system_) IScreenShotService::IScreenShotService(Core::System& system_,
: ServiceFramework{system_, "caps:ss"} { std::shared_ptr<AlbumManager> album_manager)
: ServiceFramework{system_, "caps:ss"}, manager{album_manager} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{201, nullptr, "SaveScreenShot"}, {201, nullptr, "SaveScreenShot"},
{202, nullptr, "SaveEditedScreenShot"}, {202, nullptr, "SaveEditedScreenShot"},
{203, nullptr, "SaveScreenShotEx0"}, {203, &IScreenShotService::SaveScreenShotEx0, "SaveScreenShotEx0"},
{204, nullptr, "SaveEditedScreenShotEx0"}, {204, nullptr, "SaveEditedScreenShotEx0"},
{206, nullptr, "Unknown206"}, {206, &IScreenShotService::SaveEditedScreenShotEx1, "SaveEditedScreenShotEx1"},
{208, nullptr, "SaveScreenShotOfMovieEx1"}, {208, nullptr, "SaveScreenShotOfMovieEx1"},
{1000, nullptr, "Unknown1000"}, {1000, nullptr, "Unknown1000"},
}; };
@ -24,4 +30,65 @@ IScreenShotService::IScreenShotService(Core::System& system_)
IScreenShotService::~IScreenShotService() = default; IScreenShotService::~IScreenShotService() = default;
void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
ScreenShotAttribute attribute{};
u32 report_option{};
INSERT_PADDING_BYTES(0x4);
u64 applet_resource_user_id{};
};
static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
const auto image_data_buffer = ctx.ReadBuffer();
LOG_INFO(Service_Capture,
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
parameters.report_option, image_data_buffer.size(),
parameters.applet_resource_user_id);
ApplicationAlbumEntry entry{};
const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(result);
rb.PushRaw(entry);
}
void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
ScreenShotAttribute attribute;
u64 width;
u64 height;
u64 thumbnail_width;
u64 thumbnail_height;
AlbumFileId file_id;
};
static_assert(sizeof(Parameters) == 0x78, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
const auto application_data_buffer = ctx.ReadBuffer(0);
const auto image_data_buffer = ctx.ReadBuffer(1);
const auto thumbnail_image_data_buffer = ctx.ReadBuffer(2);
LOG_INFO(Service_Capture,
"called, width={}, height={}, thumbnail_width={}, thumbnail_height={}, "
"application_id={:016x}, storage={}, type={}, app_data_buffer_size={}, "
"image_data_buffer_size={}, thumbnail_image_buffer_size={}",
parameters.width, parameters.height, parameters.thumbnail_width,
parameters.thumbnail_height, parameters.file_id.application_id,
parameters.file_id.storage, parameters.file_id.type, application_data_buffer.size(),
image_data_buffer.size(), thumbnail_image_data_buffer.size());
ApplicationAlbumEntry entry{};
const auto result = manager->SaveEditedScreenShot(entry, parameters.attribute,
parameters.file_id, image_data_buffer);
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(result);
rb.PushRaw(entry);
}
} // namespace Service::Capture } // namespace Service::Capture

View file

@ -13,8 +13,14 @@ namespace Service::Capture {
class IScreenShotService final : public ServiceFramework<IScreenShotService> { class IScreenShotService final : public ServiceFramework<IScreenShotService> {
public: public:
explicit IScreenShotService(Core::System& system_); explicit IScreenShotService(Core::System& system_, std::shared_ptr<AlbumManager> album_manager);
~IScreenShotService() override; ~IScreenShotService() override;
private:
void SaveScreenShotEx0(HLERequestContext& ctx);
void SaveEditedScreenShotEx1(HLERequestContext& ctx);
std::shared_ptr<AlbumManager> manager;
}; };
} // namespace Service::Capture } // namespace Service::Capture

View file

@ -2,19 +2,22 @@
// 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/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/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
namespace Service::Capture { namespace Service::Capture {
IScreenShotApplicationService::IScreenShotApplicationService(Core::System& system_) IScreenShotApplicationService::IScreenShotApplicationService(
: ServiceFramework{system_, "caps:su"} { Core::System& system_, std::shared_ptr<AlbumManager> album_manager)
: ServiceFramework{system_, "caps:su"}, manager{album_manager} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"}, {32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
{201, nullptr, "SaveScreenShot"}, {201, nullptr, "SaveScreenShot"},
{203, nullptr, "SaveScreenShotEx0"}, {203, &IScreenShotApplicationService::SaveScreenShotEx0, "SaveScreenShotEx0"},
{205, nullptr, "SaveScreenShotEx1"}, {205, &IScreenShotApplicationService::SaveScreenShotEx1, "SaveScreenShotEx1"},
{210, nullptr, "SaveScreenShotEx2"}, {210, nullptr, "SaveScreenShotEx2"},
}; };
// clang-format on // clang-format on
@ -36,4 +39,62 @@ void IScreenShotApplicationService::SetShimLibraryVersion(HLERequestContext& ctx
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void IScreenShotApplicationService::SaveScreenShotEx0(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
ScreenShotAttribute attribute{};
AlbumReportOption report_option{};
INSERT_PADDING_BYTES(0x4);
u64 applet_resource_user_id{};
};
static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
const auto image_data_buffer = ctx.ReadBuffer();
LOG_INFO(Service_Capture,
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
parameters.report_option, image_data_buffer.size(),
parameters.applet_resource_user_id);
ApplicationAlbumEntry entry{};
const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(result);
rb.PushRaw(entry);
}
void IScreenShotApplicationService::SaveScreenShotEx1(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
ScreenShotAttribute attribute{};
AlbumReportOption report_option{};
INSERT_PADDING_BYTES(0x4);
u64 applet_resource_user_id{};
};
static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
const auto app_data_buffer = ctx.ReadBuffer(0);
const auto image_data_buffer = ctx.ReadBuffer(1);
LOG_INFO(Service_Capture,
"called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
parameters.report_option, image_data_buffer.size(),
parameters.applet_resource_user_id);
ApplicationAlbumEntry entry{};
ApplicationData app_data{};
std::memcpy(&app_data, app_data_buffer.data(), sizeof(ApplicationData));
const auto result =
manager->SaveScreenShot(entry, parameters.attribute, app_data, image_data_buffer,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(result);
rb.PushRaw(entry);
}
} // namespace Service::Capture } // namespace Service::Capture

View file

@ -10,14 +10,20 @@ class System;
} }
namespace Service::Capture { namespace Service::Capture {
class AlbumManager;
class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> { class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> {
public: public:
explicit IScreenShotApplicationService(Core::System& system_); explicit IScreenShotApplicationService(Core::System& system_,
std::shared_ptr<AlbumManager> album_manager);
~IScreenShotApplicationService() override; ~IScreenShotApplicationService() override;
private: private:
void SetShimLibraryVersion(HLERequestContext& ctx); void SetShimLibraryVersion(HLERequestContext& ctx);
void SaveScreenShotEx0(HLERequestContext& ctx);
void SaveScreenShotEx1(HLERequestContext& ctx);
std::shared_ptr<AlbumManager> manager;
}; };
} // namespace Service::Capture } // namespace Service::Capture

View file

@ -20,6 +20,8 @@ enum class AlbumImageOrientation {
enum class AlbumReportOption : s32 { enum class AlbumReportOption : s32 {
Disable, Disable,
Enable, Enable,
Unknown2,
Unknown3,
}; };
enum class ContentType : u8 { enum class ContentType : u8 {

View file

@ -27,10 +27,12 @@ namespace {
static thread_local std::array read_buffer_data_a{ static thread_local std::array read_buffer_data_a{
Common::ScratchBuffer<u8>(), Common::ScratchBuffer<u8>(),
Common::ScratchBuffer<u8>(), Common::ScratchBuffer<u8>(),
Common::ScratchBuffer<u8>(),
}; };
static thread_local std::array read_buffer_data_x{ static thread_local std::array read_buffer_data_x{
Common::ScratchBuffer<u8>(), Common::ScratchBuffer<u8>(),
Common::ScratchBuffer<u8>(), Common::ScratchBuffer<u8>(),
Common::ScratchBuffer<u8>(),
}; };
} // Anonymous namespace } // Anonymous namespace
@ -343,6 +345,7 @@ std::span<const u8> HLERequestContext::ReadBufferA(std::size_t buffer_index) con
static thread_local std::array read_buffer_a{ static thread_local std::array read_buffer_a{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
}; };
ASSERT_OR_EXECUTE_MSG( ASSERT_OR_EXECUTE_MSG(
@ -358,6 +361,7 @@ std::span<const u8> HLERequestContext::ReadBufferX(std::size_t buffer_index) con
static thread_local std::array read_buffer_x{ static thread_local std::array read_buffer_x{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
}; };
ASSERT_OR_EXECUTE_MSG( ASSERT_OR_EXECUTE_MSG(
@ -373,10 +377,12 @@ std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) cons
static thread_local std::array read_buffer_a{ static thread_local std::array read_buffer_a{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
}; };
static thread_local std::array read_buffer_x{ static thread_local std::array read_buffer_x{
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
}; };
const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&

View file

@ -9,6 +9,35 @@
namespace Service::PTM { namespace Service::PTM {
enum class Location : u8 {
Internal,
External,
};
class ISession : public ServiceFramework<ISession> {
public:
explicit ISession(Core::System& system_) : ServiceFramework{system_, "ISession"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetTemperatureRange"},
{2, nullptr, "SetMeasurementMode"},
{4, &ISession::GetTemperature, "GetTemperature"},
};
// clang-format on
RegisterHandlers(functions);
}
private:
void GetTemperature(HLERequestContext& ctx) {
constexpr f32 temperature = 35;
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(temperature);
}
};
TS::TS(Core::System& system_) : ServiceFramework{system_, "ts"} { TS::TS(Core::System& system_) : ServiceFramework{system_, "ts"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
@ -16,7 +45,7 @@ TS::TS(Core::System& system_) : ServiceFramework{system_, "ts"} {
{1, &TS::GetTemperature, "GetTemperature"}, {1, &TS::GetTemperature, "GetTemperature"},
{2, nullptr, "SetMeasurementMode"}, {2, nullptr, "SetMeasurementMode"},
{3, &TS::GetTemperatureMilliC, "GetTemperatureMilliC"}, {3, &TS::GetTemperatureMilliC, "GetTemperatureMilliC"},
{4, nullptr, "OpenSession"}, {4, &TS::OpenSession, "OpenSession"},
}; };
// clang-format on // clang-format on
@ -47,4 +76,13 @@ void TS::GetTemperatureMilliC(HLERequestContext& ctx) {
rb.Push(temperature); rb.Push(temperature);
} }
void TS::OpenSession(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
[[maybe_unused]] const u32 device_code = rp.Pop<u32>();
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISession>(system);
}
} // namespace Service::PTM } // namespace Service::PTM

View file

@ -14,13 +14,9 @@ public:
~TS() override; ~TS() override;
private: private:
enum class Location : u8 {
Internal,
External,
};
void GetTemperature(HLERequestContext& ctx); void GetTemperature(HLERequestContext& ctx);
void GetTemperatureMilliC(HLERequestContext& ctx); void GetTemperatureMilliC(HLERequestContext& ctx);
void OpenSession(HLERequestContext& ctx);
}; };
} // namespace Service::PTM } // namespace Service::PTM

View file

@ -5,8 +5,13 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/settings.h" #include "common/settings.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
#include "core/file_sys/system_archive/system_version.h" #include "core/file_sys/nca_metadata.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/system_archive/system_archive.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"
#include "core/hle/service/set/set.h" #include "core/hle/service/set/set.h"
@ -22,18 +27,30 @@ enum class GetFirmwareVersionType {
Version2, Version2,
}; };
void GetFirmwareVersionImpl(HLERequestContext& ctx, GetFirmwareVersionType type) { void GetFirmwareVersionImpl(Core::System& system, HLERequestContext& ctx,
LOG_WARNING(Service_SET, "called - Using hardcoded firmware version '{}'", GetFirmwareVersionType type) {
FileSys::SystemArchive::GetLongDisplayVersion());
ASSERT_MSG(ctx.GetWriteBufferSize() == 0x100, ASSERT_MSG(ctx.GetWriteBufferSize() == 0x100,
"FirmwareVersion output buffer must be 0x100 bytes in size!"); "FirmwareVersion output buffer must be 0x100 bytes in size!");
// Instead of using the normal procedure of checking for the real system archive and if it constexpr u64 FirmwareVersionSystemDataId = 0x0100000000000809;
// doesn't exist, synthesizing one, I feel that that would lead to strange bugs because a auto& fsc = system.GetFileSystemController();
// used is using a really old or really new SystemVersion title. The synthesized one ensures
// consistence (currently reports as 5.1.0-0.0) // Attempt to load version data from disk
const auto archive = FileSys::SystemArchive::SystemVersion(); const FileSys::RegisteredCache* bis_system{};
std::unique_ptr<FileSys::NCA> nca{};
FileSys::VirtualDir romfs{};
bis_system = fsc.GetSystemNANDContents();
if (bis_system) {
nca = bis_system->GetEntry(FirmwareVersionSystemDataId, FileSys::ContentRecordType::Data);
}
if (nca) {
romfs = FileSys::ExtractRomFS(nca->GetRomFS());
}
if (!romfs) {
romfs = FileSys::ExtractRomFS(
FileSys::SystemArchive::SynthesizeSystemArchive(FirmwareVersionSystemDataId));
}
const auto early_exit_failure = [&ctx](std::string_view desc, Result code) { const auto early_exit_failure = [&ctx](std::string_view desc, Result code) {
LOG_ERROR(Service_SET, "General failure while attempting to resolve firmware version ({}).", LOG_ERROR(Service_SET, "General failure while attempting to resolve firmware version ({}).",
@ -42,13 +59,7 @@ void GetFirmwareVersionImpl(HLERequestContext& ctx, GetFirmwareVersionType type)
rb.Push(code); rb.Push(code);
}; };
if (archive == nullptr) { const auto ver_file = romfs->GetFile("file");
early_exit_failure("The system version archive couldn't be synthesized.",
FileSys::ERROR_FAILED_MOUNT_ARCHIVE);
return;
}
const auto ver_file = archive->GetFile("file");
if (ver_file == nullptr) { if (ver_file == nullptr) {
early_exit_failure("The system version archive didn't contain the file 'file'.", early_exit_failure("The system version archive didn't contain the file 'file'.",
FileSys::ERROR_INVALID_ARGUMENT); FileSys::ERROR_INVALID_ARGUMENT);
@ -87,12 +98,12 @@ void SET_SYS::SetLanguageCode(HLERequestContext& ctx) {
void SET_SYS::GetFirmwareVersion(HLERequestContext& ctx) { void SET_SYS::GetFirmwareVersion(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called"); LOG_DEBUG(Service_SET, "called");
GetFirmwareVersionImpl(ctx, GetFirmwareVersionType::Version1); GetFirmwareVersionImpl(system, ctx, GetFirmwareVersionType::Version1);
} }
void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) { void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called"); LOG_DEBUG(Service_SET, "called");
GetFirmwareVersionImpl(ctx, GetFirmwareVersionType::Version2); GetFirmwareVersionImpl(system, ctx, GetFirmwareVersionType::Version2);
} }
void SET_SYS::GetAccountSettings(HLERequestContext& ctx) { void SET_SYS::GetAccountSettings(HLERequestContext& ctx) {

View file

@ -19,16 +19,23 @@ namespace Core::Memory {
namespace { namespace {
constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12}; constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12};
std::string_view ExtractName(std::string_view data, std::size_t start_index, char match) { std::string_view ExtractName(std::size_t& out_name_size, std::string_view data,
std::size_t start_index, char match) {
auto end_index = start_index; auto end_index = start_index;
while (data[end_index] != match) { while (data[end_index] != match) {
++end_index; ++end_index;
if (end_index > data.size() || if (end_index > data.size()) {
(end_index - start_index - 1) > sizeof(CheatDefinition::readable_name)) {
return {}; return {};
} }
} }
out_name_size = end_index - start_index;
// Clamp name if it's too big
if (out_name_size > sizeof(CheatDefinition::readable_name)) {
end_index = start_index + sizeof(CheatDefinition::readable_name);
}
return data.substr(start_index, end_index - start_index); return data.substr(start_index, end_index - start_index);
} }
} // Anonymous namespace } // Anonymous namespace
@ -113,7 +120,8 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
return {}; return {};
} }
const auto name = ExtractName(data, i + 1, '}'); std::size_t name_size{};
const auto name = ExtractName(name_size, data, i + 1, '}');
if (name.empty()) { if (name.empty()) {
return {}; return {};
} }
@ -125,12 +133,13 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
.definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] = .definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] =
'\0'; '\0';
i += name.length() + 1; i += name_size + 1;
} else if (data[i] == '[') { } else if (data[i] == '[') {
current_entry = out.size(); current_entry = out.size();
out.emplace_back(); out.emplace_back();
const auto name = ExtractName(data, i + 1, ']'); std::size_t name_size{};
const auto name = ExtractName(name_size, data, i + 1, ']');
if (name.empty()) { if (name.empty()) {
return {}; return {};
} }
@ -142,7 +151,7 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
.definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] = .definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] =
'\0'; '\0';
i += name.length() + 1; i += name_size + 1;
} else if (::isxdigit(data[i])) { } else if (::isxdigit(data[i])) {
if (!current_entry || out[*current_entry].definition.num_opcodes >= if (!current_entry || out[*current_entry].definition.num_opcodes >=
out[*current_entry].definition.opcodes.size()) { out[*current_entry].definition.opcodes.size()) {

View file

@ -242,6 +242,7 @@ std::string EmitGLSL(const Profile& profile, const RuntimeInfo& runtime_info, IR
} }
if (program.info.uses_subgroup_shuffles) { if (program.info.uses_subgroup_shuffles) {
ctx.header += "bool shfl_in_bounds;"; ctx.header += "bool shfl_in_bounds;";
ctx.header += "uint shfl_result;";
} }
ctx.code.insert(0, ctx.header); ctx.code.insert(0, ctx.header);
ctx.code += '}'; ctx.code += '}';

View file

@ -141,7 +141,8 @@ void EmitShuffleIndex(EmitContext& ctx, IR::Inst& inst, std::string_view value,
const auto src_thread_id{fmt::format("({})|({})", lhs, min_thread_id)}; const auto src_thread_id{fmt::format("({})|({})", lhs, min_thread_id)};
ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id); ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id);
SetInBoundsFlag(ctx, inst); SetInBoundsFlag(ctx, inst);
ctx.AddU32("{}=shfl_in_bounds?readInvocationARB({},{}):{};", inst, value, src_thread_id, value); ctx.Add("shfl_result=readInvocationARB({},{});", value, src_thread_id);
ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
} }
void EmitShuffleUp(EmitContext& ctx, IR::Inst& inst, std::string_view value, std::string_view index, void EmitShuffleUp(EmitContext& ctx, IR::Inst& inst, std::string_view value, std::string_view index,
@ -158,7 +159,8 @@ void EmitShuffleUp(EmitContext& ctx, IR::Inst& inst, std::string_view value, std
const auto src_thread_id{fmt::format("({}-{})", THREAD_ID, index)}; const auto src_thread_id{fmt::format("({}-{})", THREAD_ID, index)};
ctx.Add("shfl_in_bounds=int({})>=int({});", src_thread_id, max_thread_id); ctx.Add("shfl_in_bounds=int({})>=int({});", src_thread_id, max_thread_id);
SetInBoundsFlag(ctx, inst); SetInBoundsFlag(ctx, inst);
ctx.AddU32("{}=shfl_in_bounds?readInvocationARB({},{}):{};", inst, value, src_thread_id, value); ctx.Add("shfl_result=readInvocationARB({},{});", value, src_thread_id);
ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
} }
void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, std::string_view value, void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, std::string_view value,
@ -175,7 +177,8 @@ void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, std::string_view value,
const auto src_thread_id{fmt::format("({}+{})", THREAD_ID, index)}; const auto src_thread_id{fmt::format("({}+{})", THREAD_ID, index)};
ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id); ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id);
SetInBoundsFlag(ctx, inst); SetInBoundsFlag(ctx, inst);
ctx.AddU32("{}=shfl_in_bounds?readInvocationARB({},{}):{};", inst, value, src_thread_id, value); ctx.Add("shfl_result=readInvocationARB({},{});", value, src_thread_id);
ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
} }
void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view value, void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view value,
@ -193,7 +196,8 @@ void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view val
const auto src_thread_id{fmt::format("({}^{})", THREAD_ID, index)}; const auto src_thread_id{fmt::format("({}^{})", THREAD_ID, index)};
ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id); ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id);
SetInBoundsFlag(ctx, inst); SetInBoundsFlag(ctx, inst);
ctx.AddU32("{}=shfl_in_bounds?readInvocationARB({},{}):{};", inst, value, src_thread_id, value); ctx.Add("shfl_result=readInvocationARB({},{});", value, src_thread_id);
ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
} }
void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, std::string_view op_a, std::string_view op_b, void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, std::string_view op_a, std::string_view op_b,

View file

@ -111,16 +111,33 @@ Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr,
} else if (element_size > 1) { } else if (element_size > 1) {
const u32 log2_element_size{static_cast<u32>(std::countr_zero(element_size))}; const u32 log2_element_size{static_cast<u32>(std::countr_zero(element_size))};
const Id shift{ctx.Const(log2_element_size)}; const Id shift{ctx.Const(log2_element_size)};
buffer_offset = ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), shift); buffer_offset = ctx.OpShiftRightLogical(ctx.U32[1], ctx.Def(offset), shift);
} else { } else {
buffer_offset = ctx.Def(offset); buffer_offset = ctx.Def(offset);
} }
if (!binding.IsImmediate()) { if (!binding.IsImmediate()) {
return ctx.OpFunctionCall(result_type, indirect_func, ctx.Def(binding), buffer_offset); return ctx.OpFunctionCall(result_type, indirect_func, ctx.Def(binding), buffer_offset);
} }
const Id cbuf{ctx.cbufs[binding.U32()].*member_ptr}; const Id cbuf{ctx.cbufs[binding.U32()].*member_ptr};
const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, buffer_offset)}; const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, buffer_offset)};
return ctx.OpLoad(result_type, access_chain); const Id val = ctx.OpLoad(result_type, access_chain);
if (offset.IsImmediate() || !ctx.profile.has_broken_robust) {
return val;
}
const auto is_float = UniformDefinitions::IsFloat(member_ptr);
const auto num_elements = UniformDefinitions::NumElements(member_ptr);
const std::array zero_vec{
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
is_float ? ctx.Const(0.0f) : ctx.Const(0u),
};
const Id cond = ctx.OpULessThanEqual(ctx.TypeBool(), buffer_offset, ctx.Const(0xFFFFu));
const Id zero = ctx.OpCompositeConstruct(result_type, std::span(zero_vec.data(), num_elements));
return ctx.OpSelect(result_type, cond, val, zero);
} }
Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
@ -138,7 +155,7 @@ Id GetCbufElement(EmitContext& ctx, Id vector, const IR::Value& offset, u32 inde
const u32 element{(offset.U32() / 4) % 4 + index_offset}; const u32 element{(offset.U32() / 4) % 4 + index_offset};
return ctx.OpCompositeExtract(ctx.U32[1], vector, element); return ctx.OpCompositeExtract(ctx.U32[1], vector, element);
} }
const Id shift{ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), ctx.Const(2u))}; const Id shift{ctx.OpShiftRightLogical(ctx.U32[1], ctx.Def(offset), ctx.Const(2u))};
Id element{ctx.OpBitwiseAnd(ctx.U32[1], shift, ctx.Const(3u))}; Id element{ctx.OpBitwiseAnd(ctx.U32[1], shift, ctx.Const(3u))};
if (index_offset > 0) { if (index_offset > 0) {
element = ctx.OpIAdd(ctx.U32[1], element, ctx.Const(index_offset)); element = ctx.OpIAdd(ctx.U32[1], element, ctx.Const(index_offset));

View file

@ -64,6 +64,42 @@ struct UniformDefinitions {
Id F32{}; Id F32{};
Id U32x2{}; Id U32x2{};
Id U32x4{}; Id U32x4{};
constexpr static size_t NumElements(Id UniformDefinitions::*member_ptr) {
if (member_ptr == &UniformDefinitions::U8) {
return 1;
}
if (member_ptr == &UniformDefinitions::S8) {
return 1;
}
if (member_ptr == &UniformDefinitions::U16) {
return 1;
}
if (member_ptr == &UniformDefinitions::S16) {
return 1;
}
if (member_ptr == &UniformDefinitions::U32) {
return 1;
}
if (member_ptr == &UniformDefinitions::F32) {
return 1;
}
if (member_ptr == &UniformDefinitions::U32x2) {
return 2;
}
if (member_ptr == &UniformDefinitions::U32x4) {
return 4;
}
ASSERT(false);
return 1;
}
constexpr static bool IsFloat(Id UniformDefinitions::*member_ptr) {
if (member_ptr == &UniformDefinitions::F32) {
return true;
}
return false;
}
}; };
struct StorageTypeDefinition { struct StorageTypeDefinition {

View file

@ -9,7 +9,6 @@ namespace Shader {
struct Profile { struct Profile {
u32 supported_spirv{0x00010000}; u32 supported_spirv{0x00010000};
bool unified_descriptor_binding{}; bool unified_descriptor_binding{};
bool support_descriptor_aliasing{}; bool support_descriptor_aliasing{};
bool support_int8{}; bool support_int8{};
@ -82,6 +81,9 @@ struct Profile {
bool has_broken_spirv_subgroup_mask_vector_extract_dynamic{}; bool has_broken_spirv_subgroup_mask_vector_extract_dynamic{};
u32 gl_max_compute_smem_size{}; u32 gl_max_compute_smem_size{};
/// Maxwell and earlier nVidia architectures have broken robust support
bool has_broken_robust{};
}; };
} // namespace Shader } // namespace Shader

View file

@ -356,7 +356,11 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
.has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY, .has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY,
.ignore_nan_fp_comparisons = false, .ignore_nan_fp_comparisons = false,
.has_broken_spirv_subgroup_mask_vector_extract_dynamic = .has_broken_spirv_subgroup_mask_vector_extract_dynamic =
driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY}; driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY,
.has_broken_robust =
device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Maxwell,
};
host_info = Shader::HostTranslateInfo{ host_info = Shader::HostTranslateInfo{
.support_float64 = device.IsFloat64Supported(), .support_float64 = device.IsFloat64Supported(),
.support_float16 = device.IsFloat16Supported(), .support_float16 = device.IsFloat16Supported(),

View file

@ -83,15 +83,6 @@ constexpr std::array VK_FORMAT_A4B4G4R4_UNORM_PACK16{
} // namespace Alternatives } // namespace Alternatives
enum class NvidiaArchitecture {
KeplerOrOlder,
Maxwell,
Pascal,
Volta,
Turing,
AmpereOrNewer,
};
template <typename T> template <typename T>
void SetNext(void**& next, T& data) { void SetNext(void**& next, T& data) {
*next = &data; *next = &data;
@ -326,9 +317,9 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
if (shading_rate_props.primitiveFragmentShadingRateWithMultipleViewports) { if (shading_rate_props.primitiveFragmentShadingRateWithMultipleViewports) {
// Only Ampere and newer support this feature // Only Ampere and newer support this feature
// TODO: Find a way to differentiate Ampere and Ada // TODO: Find a way to differentiate Ampere and Ada
return NvidiaArchitecture::AmpereOrNewer; return NvidiaArchitecture::Arch_AmpereOrNewer;
} }
return NvidiaArchitecture::Turing; return NvidiaArchitecture::Arch_Turing;
} }
if (exts.contains(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME)) { if (exts.contains(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME)) {
@ -340,7 +331,7 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
physical_properties.pNext = &advanced_blending_props; physical_properties.pNext = &advanced_blending_props;
physical.GetProperties2(physical_properties); physical.GetProperties2(physical_properties);
if (advanced_blending_props.advancedBlendMaxColorAttachments == 1) { if (advanced_blending_props.advancedBlendMaxColorAttachments == 1) {
return NvidiaArchitecture::Maxwell; return NvidiaArchitecture::Arch_Maxwell;
} }
if (exts.contains(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME)) { if (exts.contains(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME)) {
@ -350,13 +341,13 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
physical_properties.pNext = &conservative_raster_props; physical_properties.pNext = &conservative_raster_props;
physical.GetProperties2(physical_properties); physical.GetProperties2(physical_properties);
if (conservative_raster_props.degenerateLinesRasterized) { if (conservative_raster_props.degenerateLinesRasterized) {
return NvidiaArchitecture::Volta; return NvidiaArchitecture::Arch_Volta;
} }
return NvidiaArchitecture::Pascal; return NvidiaArchitecture::Arch_Pascal;
} }
} }
return NvidiaArchitecture::KeplerOrOlder; return NvidiaArchitecture::Arch_KeplerOrOlder;
} }
std::vector<const char*> ExtensionListForVulkan( std::vector<const char*> ExtensionListForVulkan(
@ -436,6 +427,10 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER); throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER);
} }
if (is_nvidia) {
nvidia_arch = GetNvidiaArchitecture(physical, supported_extensions);
}
SetupFamilies(surface); SetupFamilies(surface);
const auto queue_cis = GetDeviceQueueCreateInfos(); const auto queue_cis = GetDeviceQueueCreateInfos();
@ -532,11 +527,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
if (is_nvidia) { if (is_nvidia) {
const u32 nv_major_version = (properties.properties.driverVersion >> 22) & 0x3ff; const u32 nv_major_version = (properties.properties.driverVersion >> 22) & 0x3ff;
const auto arch = GetNvidiaArchitecture(physical, supported_extensions); const auto arch = GetNvidiaArch();
if (arch >= NvidiaArchitecture::AmpereOrNewer) { if (arch >= NvidiaArchitecture::Arch_AmpereOrNewer) {
LOG_WARNING(Render_Vulkan, "Ampere and newer have broken float16 math"); LOG_WARNING(Render_Vulkan, "Ampere and newer have broken float16 math");
features.shader_float16_int8.shaderFloat16 = false; features.shader_float16_int8.shaderFloat16 = false;
} else if (arch <= NvidiaArchitecture::Volta) { } else if (arch <= NvidiaArchitecture::Arch_Volta) {
if (nv_major_version < 527) { if (nv_major_version < 527) {
LOG_WARNING(Render_Vulkan, "Volta and older have broken VK_KHR_push_descriptor"); LOG_WARNING(Render_Vulkan, "Volta and older have broken VK_KHR_push_descriptor");
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
@ -686,8 +681,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
} }
} else if (extensions.push_descriptor && is_nvidia) { } else if (extensions.push_descriptor && is_nvidia) {
const auto arch = GetNvidiaArchitecture(physical, supported_extensions); const auto arch = GetNvidiaArch();
if (arch <= NvidiaArchitecture::Pascal) { if (arch <= NvidiaArchitecture::Arch_Pascal) {
LOG_WARNING(Render_Vulkan, LOG_WARNING(Render_Vulkan,
"Pascal and older architectures have broken VK_KHR_push_descriptor"); "Pascal and older architectures have broken VK_KHR_push_descriptor");
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);

View file

@ -177,6 +177,15 @@ enum class FormatType { Linear, Optimal, Buffer };
/// Subgroup size of the guest emulated hardware (Nvidia has 32 threads per subgroup). /// Subgroup size of the guest emulated hardware (Nvidia has 32 threads per subgroup).
const u32 GuestWarpSize = 32; const u32 GuestWarpSize = 32;
enum class NvidiaArchitecture {
Arch_KeplerOrOlder,
Arch_Maxwell,
Arch_Pascal,
Arch_Volta,
Arch_Turing,
Arch_AmpereOrNewer,
};
/// Handles data specific to a physical device. /// Handles data specific to a physical device.
class Device { class Device {
public: public:
@ -670,6 +679,14 @@ public:
return false; return false;
} }
bool IsNvidia() const noexcept {
return properties.driver.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY;
}
NvidiaArchitecture GetNvidiaArch() const noexcept {
return nvidia_arch;
}
private: private:
/// Checks if the physical device is suitable and configures the object state /// Checks if the physical device is suitable and configures the object state
/// with all necessary info about its properties. /// with all necessary info about its properties.
@ -788,6 +805,7 @@ private:
bool supports_conditional_barriers{}; ///< Allows barriers in conditional control flow. bool supports_conditional_barriers{}; ///< Allows barriers in conditional control flow.
u64 device_access_memory{}; ///< Total size of device local memory in bytes. u64 device_access_memory{}; ///< Total size of device local memory in bytes.
u32 sets_per_pool{}; ///< Sets per Description Pool u32 sets_per_pool{}; ///< Sets per Description Pool
NvidiaArchitecture nvidia_arch{NvidiaArchitecture::Arch_AmpereOrNewer};
// Telemetry parameters // Telemetry parameters
std::set<std::string, std::less<>> supported_extensions; ///< Reported Vulkan extensions. std::set<std::string, std::less<>> supported_extensions; ///< Reported Vulkan extensions.

View file

@ -522,7 +522,7 @@ Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char
.applicationVersion = VK_MAKE_VERSION(0, 1, 0), .applicationVersion = VK_MAKE_VERSION(0, 1, 0),
.pEngineName = "yuzu Emulator", .pEngineName = "yuzu Emulator",
.engineVersion = VK_MAKE_VERSION(0, 1, 0), .engineVersion = VK_MAKE_VERSION(0, 1, 0),
.apiVersion = version, .apiVersion = VK_API_VERSION_1_3,
}; };
const VkInstanceCreateInfo ci{ const VkInstanceCreateInfo ci{
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,

View file

@ -114,7 +114,7 @@ const std::map<Settings::ShaderBackend, QString> Config::shader_backend_texts_ma
// This must be in alphabetical order according to action name as it must have the same order as // This must be in alphabetical order according to action name as it must have the same order as
// UISetting::values.shortcuts, which is alphabetically ordered. // UISetting::values.shortcuts, which is alphabetically ordered.
// clang-format off // clang-format off
const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{ const std::array<UISettings::Shortcut, 23> Config::default_hotkeys{{
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut, true}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("="), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("="), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut, true}},
@ -136,6 +136,7 @@ const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral(""), QStringLiteral(""), Qt::ApplicationShortcut, false}},
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut, false}}, {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut, false}},
}}; }};
// clang-format on // clang-format on

View file

@ -48,7 +48,7 @@ public:
default_mouse_buttons; default_mouse_buttons;
static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys; static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods; static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods;
static const std::array<UISettings::Shortcut, 22> default_hotkeys; static const std::array<UISettings::Shortcut, 23> default_hotkeys;
static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map; static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map;
static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map; static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map;

View file

@ -319,6 +319,13 @@ void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) {
void ConfigureHotkeys::RestoreDefaults() { void ConfigureHotkeys::RestoreDefaults() {
for (int r = 0; r < model->rowCount(); ++r) { for (int r = 0; r < model->rowCount(); ++r) {
const QStandardItem* parent = model->item(r, 0); const QStandardItem* parent = model->item(r, 0);
const int hotkey_size = static_cast<int>(Config::default_hotkeys.size());
if (hotkey_size != parent->rowCount()) {
QMessageBox::warning(this, tr("Invalid hotkey settings"),
tr("An error occurred. Please report this issue on github."));
return;
}
for (int r2 = 0; r2 < parent->rowCount(); ++r2) { for (int r2 = 0; r2 < parent->rowCount(); ++r2) {
model->item(r, 0) model->item(r, 0)

View file

@ -89,7 +89,7 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type
auto& player = Settings::values.players.GetValue()[player_index]; auto& player = Settings::values.players.GetValue()[player_index];
auto controller = hid_core.GetEmulatedControllerByIndex(player_index); auto controller = hid_core.GetEmulatedControllerByIndex(player_index);
const int vibration_strenght = vibration_spinboxes[player_index]->value(); const int vibration_strength = vibration_spinboxes[player_index]->value();
const auto& buttons = controller->GetButtonsValues(); const auto& buttons = controller->GetButtonsValues();
bool button_is_pressed = false; bool button_is_pressed = false;
@ -105,10 +105,10 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type
return; return;
} }
const int old_vibration_enabled = player.vibration_enabled; const bool old_vibration_enabled = player.vibration_enabled;
const bool old_vibration_strenght = player.vibration_strength; const int old_vibration_strength = player.vibration_strength;
player.vibration_enabled = true; player.vibration_enabled = true;
player.vibration_strength = vibration_strenght; player.vibration_strength = vibration_strength;
const Core::HID::VibrationValue vibration{ const Core::HID::VibrationValue vibration{
.low_amplitude = 1.0f, .low_amplitude = 1.0f,
@ -121,7 +121,7 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type
// Restore previous values // Restore previous values
player.vibration_enabled = old_vibration_enabled; player.vibration_enabled = old_vibration_enabled;
player.vibration_strength = old_vibration_strenght; player.vibration_strength = old_vibration_strength;
} }
void ConfigureVibration::StopVibrations() { void ConfigureVibration::StopVibrations() {