diff options
Diffstat (limited to 'src')
71 files changed, 894 insertions, 287 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 850ce8006..5639021d3 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -91,6 +91,8 @@ add_library(common STATIC logging/log.h logging/text_formatter.cpp logging/text_formatter.h + lz4_compression.cpp + lz4_compression.h math_util.h memory_hook.cpp memory_hook.h @@ -136,3 +138,4 @@ endif() create_target_directory_groups(common) target_link_libraries(common PUBLIC Boost::boost fmt microprofile) +target_link_libraries(common PRIVATE lz4_static) diff --git a/src/common/lz4_compression.cpp b/src/common/lz4_compression.cpp new file mode 100644 index 000000000..ade6759bb --- /dev/null +++ b/src/common/lz4_compression.cpp @@ -0,0 +1,76 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <lz4hc.h> + +#include "common/assert.h" +#include "common/lz4_compression.h" + +namespace Common::Compression { + +std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size) { + ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size"); + + const auto source_size_int = static_cast<int>(source_size); + const int max_compressed_size = LZ4_compressBound(source_size_int); + std::vector<u8> compressed(max_compressed_size); + + const int compressed_size = LZ4_compress_default(reinterpret_cast<const char*>(source), + reinterpret_cast<char*>(compressed.data()), + source_size_int, max_compressed_size); + + if (compressed_size <= 0) { + // Compression failed + return {}; + } + + compressed.resize(compressed_size); + + return compressed; +} + +std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, + s32 compression_level) { + ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size"); + + compression_level = std::clamp(compression_level, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX); + + const auto source_size_int = static_cast<int>(source_size); + const int max_compressed_size = LZ4_compressBound(source_size_int); + std::vector<u8> compressed(max_compressed_size); + + const int compressed_size = LZ4_compress_HC( + reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()), + source_size_int, max_compressed_size, compression_level); + + if (compressed_size <= 0) { + // Compression failed + return {}; + } + + compressed.resize(compressed_size); + + return compressed; +} + +std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size) { + return CompressDataLZ4HC(source, source_size, LZ4HC_CLEVEL_MAX); +} + +std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, + std::size_t uncompressed_size) { + std::vector<u8> uncompressed(uncompressed_size); + const int size_check = LZ4_decompress_safe(reinterpret_cast<const char*>(compressed.data()), + reinterpret_cast<char*>(uncompressed.data()), + static_cast<int>(compressed.size()), + static_cast<int>(uncompressed.size())); + if (static_cast<int>(uncompressed_size) != size_check) { + // Decompression failed + return {}; + } + return uncompressed; +} + +} // namespace Common::Compression diff --git a/src/common/lz4_compression.h b/src/common/lz4_compression.h new file mode 100644 index 000000000..fe2231a6c --- /dev/null +++ b/src/common/lz4_compression.h @@ -0,0 +1,55 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <vector> + +#include "common/common_types.h" + +namespace Common::Compression { + +/** + * Compresses a source memory region with LZ4 and returns the compressed data in a vector. + * + * @param source the uncompressed source memory region. + * @param source_size the size in bytes of the uncompressed source memory region. + * + * @return the compressed data. + */ +std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size); + +/** + * Utilizes the LZ4 subalgorithm LZ4HC with the specified compression level. Higher compression + * levels result in a smaller compressed size, but require more CPU time for compression. The + * compression level has almost no impact on decompression speed. Data compressed with LZ4HC can + * also be decompressed with the default LZ4 decompression. + * + * @param source the uncompressed source memory region. + * @param source_size the size in bytes of the uncompressed source memory region. + * @param compression_level the used compression level. Should be between 3 and 12. + * + * @return the compressed data. + */ +std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, s32 compression_level); + +/** + * Utilizes the LZ4 subalgorithm LZ4HC with the highest possible compression level. + * + * @param source the uncompressed source memory region. + * @param source_size the size in bytes of the uncompressed source memory region. + * + * @return the compressed data. + */ +std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size); + +/** + * Decompresses a source memory region with LZ4 and returns the uncompressed data in a vector. + * + * @param compressed the compressed source memory region. + * @param uncompressed_size the size in bytes of the uncompressed data. + * + * @return the decompressed data. + */ +std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, std::size_t uncompressed_size); + +} // namespace Common::Compression
\ No newline at end of file diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 9e23afe85..c59107102 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -458,7 +458,7 @@ add_library(core STATIC create_target_directory_groups(core) target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) -target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn open_source_archives) +target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt mbedtls opus unicorn open_source_archives) if (ENABLE_WEB_SERVICE) target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) target_link_libraries(core PRIVATE web_service) diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index 83c184750..60ea9ad12 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp @@ -67,7 +67,7 @@ std::string NACP::GetDeveloperName(Language language) const { } u64 NACP::GetTitleId() const { - return raw.title_id; + return raw.save_data_owner_id; } u64 NACP::GetDLCBaseTitleId() const { @@ -80,11 +80,11 @@ std::string NACP::GetVersionString() const { } u64 NACP::GetDefaultNormalSaveSize() const { - return raw.normal_save_data_size; + return raw.user_account_save_data_size; } u64 NACP::GetDefaultJournalSaveSize() const { - return raw.journal_sava_data_size; + return raw.user_account_save_data_journal_size; } std::vector<u8> NACP::GetRawBytes() const { diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 7b9cdc910..280710ddf 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -38,23 +38,35 @@ struct RawNACP { u8 video_capture_mode; bool data_loss_confirmation; INSERT_PADDING_BYTES(1); - u64_le title_id; + u64_le presence_group_id; std::array<u8, 0x20> rating_age; std::array<char, 0x10> version_string; u64_le dlc_base_title_id; - u64_le title_id_2; - u64_le normal_save_data_size; - u64_le journal_sava_data_size; - INSERT_PADDING_BYTES(0x18); - u64_le product_code; + u64_le save_data_owner_id; + u64_le user_account_save_data_size; + u64_le user_account_save_data_journal_size; + u64_le device_save_data_size; + u64_le device_save_data_journal_size; + u64_le bcat_delivery_cache_storage_size; + char application_error_code_category[8]; std::array<u64_le, 0x8> local_communication; u8 logo_type; u8 logo_handling; bool runtime_add_on_content_install; INSERT_PADDING_BYTES(5); - u64_le title_id_update; - std::array<u8, 0x40> bcat_passphrase; - INSERT_PADDING_BYTES(0xEC0); + u64_le seed_for_pseudo_device_id; + std::array<u8, 0x41> bcat_passphrase; + INSERT_PADDING_BYTES(7); + u64_le user_account_save_data_max_size; + u64_le user_account_save_data_max_journal_size; + u64_le device_save_data_max_size; + u64_le device_save_data_max_journal_size; + u64_le temporary_storage_size; + u64_le cache_storage_size; + u64_le cache_storage_journal_size; + u64_le cache_storage_data_and_journal_max_size; + u64_le cache_storage_max_index; + INSERT_PADDING_BYTES(0xE70); }; static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size."); diff --git a/src/core/hle/kernel/code_set.h b/src/core/hle/kernel/code_set.h index 834fd23d2..879957dcb 100644 --- a/src/core/hle/kernel/code_set.h +++ b/src/core/hle/kernel/code_set.h @@ -5,7 +5,6 @@ #pragma once #include <cstddef> -#include <memory> #include <vector> #include "common/common_types.h" @@ -78,7 +77,7 @@ struct CodeSet final { } /// The overall data that backs this code set. - std::shared_ptr<std::vector<u8>> memory; + std::vector<u8> memory; /// The segments that comprise this code set. std::array<Segment, 3> segments; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 6baeb3494..3f14bfa86 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -115,7 +115,7 @@ struct KernelCore::Impl { // Creates the default system resource limit void InitializeSystemResourceLimit(KernelCore& kernel) { - system_resource_limit = ResourceLimit::Create(kernel, "System"); + system_resource_limit = ResourceLimit::Create(kernel); // If setting the default system values fails, then something seriously wrong has occurred. ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x200000000) @@ -191,6 +191,10 @@ const Process* KernelCore::CurrentProcess() const { return impl->current_process; } +const std::vector<SharedPtr<Process>>& KernelCore::GetProcessList() const { + return impl->process_list; +} + void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) { impl->named_ports.emplace(std::move(name), std::move(port)); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 03ea5b659..6b8738599 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -72,6 +72,9 @@ public: /// Retrieves a const pointer to the current process. const Process* CurrentProcess() const; + /// Retrieves the list of processes. + const std::vector<SharedPtr<Process>>& GetProcessList() const; + /// Adds a port to the named port table void AddNamedPort(std::string name, SharedPtr<ClientPort> port); diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp index 217144efc..10431e94c 100644 --- a/src/core/hle/kernel/object.cpp +++ b/src/core/hle/kernel/object.cpp @@ -24,7 +24,6 @@ bool Object::IsWaitable() const { case HandleType::WritableEvent: case HandleType::SharedMemory: case HandleType::TransferMemory: - case HandleType::AddressArbiter: case HandleType::ResourceLimit: case HandleType::ClientPort: case HandleType::ClientSession: diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index 3f6baa094..332876c27 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -25,7 +25,6 @@ enum class HandleType : u32 { TransferMemory, Thread, Process, - AddressArbiter, ResourceLimit, ClientPort, ServerPort, diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index b0b7af76b..041267318 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -80,6 +80,14 @@ u64 Process::GetTotalPhysicalMemoryUsed() const { return vm_manager.GetCurrentHeapSize() + main_thread_stack_size + code_memory_size; } +void Process::RegisterThread(const Thread* thread) { + thread_list.push_back(thread); +} + +void Process::UnregisterThread(const Thread* thread) { + thread_list.remove(thread); +} + ResultCode Process::ClearSignalState() { if (status == ProcessStatus::Exited) { LOG_ERROR(Kernel, "called on a terminated process instance."); @@ -218,11 +226,13 @@ void Process::FreeTLSSlot(VAddr tls_address) { } void Process::LoadModule(CodeSet module_, VAddr base_addr) { + const auto memory = std::make_shared<std::vector<u8>>(std::move(module_.memory)); + const auto MapSegment = [&](const CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) { const auto vma = vm_manager - .MapMemoryBlock(segment.addr + base_addr, module_.memory, - segment.offset, segment.size, memory_state) + .MapMemoryBlock(segment.addr + base_addr, memory, segment.offset, + segment.size, memory_state) .Unwrap(); vm_manager.Reprotect(vma, permissions); }; @@ -232,7 +242,7 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeData); MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeData); - code_memory_size += module_.memory->size(); + code_memory_size += module_.memory.size(); // Clear instruction cache in CPU JIT system.InvalidateCpuInstructionCaches(); @@ -247,7 +257,7 @@ void Process::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "Object unavailable!"); } -bool Process::ShouldWait(Thread* thread) const { +bool Process::ShouldWait(const Thread* thread) const { return !is_signaled; } diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 732d12170..f060f2a3b 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -7,6 +7,7 @@ #include <array> #include <bitset> #include <cstddef> +#include <list> #include <string> #include <vector> #include <boost/container/static_vector.hpp> @@ -189,6 +190,19 @@ public: /// Retrieves the total physical memory used by this process in bytes. u64 GetTotalPhysicalMemoryUsed() const; + /// Gets the list of all threads created with this process as their owner. + const std::list<const Thread*>& GetThreadList() const { + return thread_list; + } + + /// Registers a thread as being created under this process, + /// adding it to this process' thread list. + void RegisterThread(const Thread* thread); + + /// Unregisters a thread from this process, removing it + /// from this process' thread list. + void UnregisterThread(const Thread* thread); + /// Clears the signaled state of the process if and only if it's signaled. /// /// @pre The process must not be already terminated. If this is called on a @@ -237,7 +251,7 @@ private: ~Process() override; /// Checks if the specified thread should wait until this process is available. - bool ShouldWait(Thread* thread) const override; + bool ShouldWait(const Thread* thread) const override; /// Acquires/locks this process for the specified thread if it's available. void Acquire(Thread* thread) override; @@ -308,6 +322,9 @@ private: /// Random values for svcGetInfo RandomEntropy std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy; + /// List of threads that are running with this process as their owner. + std::list<const Thread*> thread_list; + /// System context Core::System& system; diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp index 0e5083f70..c2b798a4e 100644 --- a/src/core/hle/kernel/readable_event.cpp +++ b/src/core/hle/kernel/readable_event.cpp @@ -14,7 +14,7 @@ namespace Kernel { ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {} ReadableEvent::~ReadableEvent() = default; -bool ReadableEvent::ShouldWait(Thread* thread) const { +bool ReadableEvent::ShouldWait(const Thread* thread) const { return !signaled; } diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h index 77a9c362c..2eb9dcbb7 100644 --- a/src/core/hle/kernel/readable_event.h +++ b/src/core/hle/kernel/readable_event.h @@ -36,7 +36,7 @@ public: return HANDLE_TYPE; } - bool ShouldWait(Thread* thread) const override; + bool ShouldWait(const Thread* thread) const override; void Acquire(Thread* thread) override; /// Unconditionally clears the readable event's state. diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp index 2f9695005..173f69915 100644 --- a/src/core/hle/kernel/resource_limit.cpp +++ b/src/core/hle/kernel/resource_limit.cpp @@ -16,11 +16,8 @@ constexpr std::size_t ResourceTypeToIndex(ResourceType type) { ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {} ResourceLimit::~ResourceLimit() = default; -SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel, std::string name) { - SharedPtr<ResourceLimit> resource_limit(new ResourceLimit(kernel)); - - resource_limit->name = std::move(name); - return resource_limit; +SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) { + return new ResourceLimit(kernel); } s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h index 59dc11c22..70e09858a 100644 --- a/src/core/hle/kernel/resource_limit.h +++ b/src/core/hle/kernel/resource_limit.h @@ -31,16 +31,14 @@ constexpr bool IsValidResourceType(ResourceType type) { class ResourceLimit final : public Object { public: - /** - * Creates a resource limit object. - */ - static SharedPtr<ResourceLimit> Create(KernelCore& kernel, std::string name = "Unknown"); + /// Creates a resource limit object. + static SharedPtr<ResourceLimit> Create(KernelCore& kernel); std::string GetTypeName() const override { return "ResourceLimit"; } std::string GetName() const override { - return name; + return GetTypeName(); } static const HandleType HANDLE_TYPE = HandleType::ResourceLimit; @@ -95,9 +93,6 @@ private: ResourceArray limits{}; /// Current resource limit values. ResourceArray values{}; - - /// Name of resource limit object. - std::string name; }; } // namespace Kernel diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 0e1515c89..708fdf9e1 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -30,7 +30,7 @@ void ServerPort::AppendPendingSession(SharedPtr<ServerSession> pending_session) pending_sessions.push_back(std::move(pending_session)); } -bool ServerPort::ShouldWait(Thread* thread) const { +bool ServerPort::ShouldWait(const Thread* thread) const { // If there are no pending sessions, we wait until a new one is added. return pending_sessions.empty(); } diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index 9bc667cf2..76293cb8b 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -75,7 +75,7 @@ public: /// waiting to be accepted by this port. void AppendPendingSession(SharedPtr<ServerSession> pending_session); - bool ShouldWait(Thread* thread) const override; + bool ShouldWait(const Thread* thread) const override; void Acquire(Thread* thread) override; private: diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 4d8a337a7..40cec143e 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -46,7 +46,7 @@ ResultVal<SharedPtr<ServerSession>> ServerSession::Create(KernelCore& kernel, st return MakeResult(std::move(server_session)); } -bool ServerSession::ShouldWait(Thread* thread) const { +bool ServerSession::ShouldWait(const Thread* thread) const { // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. if (parent->client == nullptr) return false; diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index aea4ccfeb..79b84bade 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -82,7 +82,7 @@ public: */ ResultCode HandleSyncRequest(SharedPtr<Thread> thread); - bool ShouldWait(Thread* thread) const override; + bool ShouldWait(const Thread* thread) const override; void Acquire(Thread* thread) override; diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 62861da36..f15c5ee36 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -9,7 +9,6 @@ #include "core/hle/kernel/errors.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/shared_memory.h" -#include "core/memory.h" namespace Kernel { @@ -119,7 +118,15 @@ ResultCode SharedMemory::Map(Process& target_process, VAddr address, MemoryPermi ConvertPermissions(permissions)); } -ResultCode SharedMemory::Unmap(Process& target_process, VAddr address) { +ResultCode SharedMemory::Unmap(Process& target_process, VAddr address, u64 unmap_size) { + if (unmap_size != size) { + LOG_ERROR(Kernel, + "Invalid size passed to Unmap. Size must be equal to the size of the " + "memory managed. Shared memory size=0x{:016X}, Unmap size=0x{:016X}", + size, unmap_size); + return ERR_INVALID_SIZE; + } + // TODO(Subv): Verify what happens if the application tries to unmap an address that is not // mapped to a SharedMemory. return target_process.VMManager().UnmapRange(address, size); diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index dab2a6bea..37e18c443 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -104,11 +104,17 @@ public: /** * Unmaps a shared memory block from the specified address in system memory + * * @param target_process Process from which to unmap the memory block. - * @param address Address in system memory where the shared memory block is mapped + * @param address Address in system memory where the shared memory block is mapped. + * @param unmap_size The amount of bytes to unmap from this shared memory instance. + * * @return Result code of the unmap operation + * + * @pre The given size to unmap must be the same size as the amount of memory managed by + * the SharedMemory instance itself, otherwise ERR_INVALID_SIZE will be returned. */ - ResultCode Unmap(Process& target_process, VAddr address); + ResultCode Unmap(Process& target_process, VAddr address, u64 unmap_size); /** * Gets a pointer to the shared memory block diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 76a8b0191..ab10db3df 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1140,7 +1140,7 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 return ERR_INVALID_MEMORY_RANGE; } - return shared_memory->Unmap(*current_process, addr); + return shared_memory->Unmap(*current_process, addr, size); } static ResultCode QueryProcessMemory(VAddr memory_info_address, VAddr page_info_address, @@ -1983,6 +1983,83 @@ static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource return RESULT_SUCCESS; } +static ResultCode GetProcessList(u32* out_num_processes, VAddr out_process_ids, + u32 out_process_ids_size) { + LOG_DEBUG(Kernel_SVC, "called. out_process_ids=0x{:016X}, out_process_ids_size={}", + out_process_ids, out_process_ids_size); + + // If the supplied size is negative or greater than INT32_MAX / sizeof(u64), bail. + if ((out_process_ids_size & 0xF0000000) != 0) { + LOG_ERROR(Kernel_SVC, + "Supplied size outside [0, 0x0FFFFFFF] range. out_process_ids_size={}", + out_process_ids_size); + return ERR_OUT_OF_RANGE; + } + + const auto& kernel = Core::System::GetInstance().Kernel(); + const auto& vm_manager = kernel.CurrentProcess()->VMManager(); + const auto total_copy_size = out_process_ids_size * sizeof(u64); + + if (out_process_ids_size > 0 && + !vm_manager.IsWithinAddressSpace(out_process_ids, total_copy_size)) { + LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}", + out_process_ids, out_process_ids + total_copy_size); + return ERR_INVALID_ADDRESS_STATE; + } + + const auto& process_list = kernel.GetProcessList(); + const auto num_processes = process_list.size(); + const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes); + + for (std::size_t i = 0; i < copy_amount; ++i) { + Memory::Write64(out_process_ids, process_list[i]->GetProcessID()); + out_process_ids += sizeof(u64); + } + + *out_num_processes = static_cast<u32>(num_processes); + return RESULT_SUCCESS; +} + +ResultCode GetThreadList(u32* out_num_threads, VAddr out_thread_ids, u32 out_thread_ids_size, + Handle debug_handle) { + // TODO: Handle this case when debug events are supported. + UNIMPLEMENTED_IF(debug_handle != InvalidHandle); + + LOG_DEBUG(Kernel_SVC, "called. out_thread_ids=0x{:016X}, out_thread_ids_size={}", + out_thread_ids, out_thread_ids_size); + + // If the size is negative or larger than INT32_MAX / sizeof(u64) + if ((out_thread_ids_size & 0xF0000000) != 0) { + LOG_ERROR(Kernel_SVC, "Supplied size outside [0, 0x0FFFFFFF] range. size={}", + out_thread_ids_size); + return ERR_OUT_OF_RANGE; + } + + const auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess(); + const auto& vm_manager = current_process->VMManager(); + const auto total_copy_size = out_thread_ids_size * sizeof(u64); + + if (out_thread_ids_size > 0 && + !vm_manager.IsWithinAddressSpace(out_thread_ids, total_copy_size)) { + LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}", + out_thread_ids, out_thread_ids + total_copy_size); + return ERR_INVALID_ADDRESS_STATE; + } + + const auto& thread_list = current_process->GetThreadList(); + const auto num_threads = thread_list.size(); + const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads); + + auto list_iter = thread_list.cbegin(); + for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) { + Memory::Write64(out_thread_ids, (*list_iter)->GetThreadID()); + out_thread_ids += sizeof(u64); + } + + *out_num_threads = static_cast<u32>(num_threads); + return RESULT_SUCCESS; +} + namespace { struct FunctionDef { using Func = void(); @@ -2095,8 +2172,8 @@ static const FunctionDef SVC_Table[] = { {0x62, nullptr, "TerminateDebugProcess"}, {0x63, nullptr, "GetDebugEvent"}, {0x64, nullptr, "ContinueDebugEvent"}, - {0x65, nullptr, "GetProcessList"}, - {0x66, nullptr, "GetThreadList"}, + {0x65, SvcWrap<GetProcessList>, "GetProcessList"}, + {0x66, SvcWrap<GetThreadList>, "GetThreadList"}, {0x67, nullptr, "GetDebugThreadContext"}, {0x68, nullptr, "SetDebugThreadContext"}, {0x69, nullptr, "QueryDebugProcessMemory"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 2a2c2c5ea..b3733680f 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -78,6 +78,14 @@ void SvcWrap() { FuncReturn(retval); } +template <ResultCode func(u32*, u64, u32)> +void SvcWrap() { + u32 param_1 = 0; + const u32 retval = func(¶m_1, Param(1), static_cast<u32>(Param(2))).raw; + Core::CurrentArmInterface().SetReg(1, param_1); + FuncReturn(retval); +} + template <ResultCode func(u64*, u32)> void SvcWrap() { u64 param_1 = 0; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index fa3ac3abc..1b891f632 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -28,7 +28,7 @@ namespace Kernel { -bool Thread::ShouldWait(Thread* thread) const { +bool Thread::ShouldWait(const Thread* thread) const { return status != ThreadStatus::Dead; } @@ -62,6 +62,8 @@ void Thread::Stop() { } wait_objects.clear(); + owner_process->UnregisterThread(this); + // Mark the TLS slot in the thread's page as free. owner_process->FreeTLSSlot(tls_address); } @@ -202,6 +204,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name thread->scheduler->AddThread(thread); thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread); + thread->owner_process->RegisterThread(thread.get()); + // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used // to initialize the context ResetThreadContext(thread->context, stack_top, entry_point, arg); @@ -229,16 +233,16 @@ void Thread::SetWaitSynchronizationOutput(s32 output) { context.cpu_registers[1] = output; } -s32 Thread::GetWaitObjectIndex(WaitObject* object) const { +s32 Thread::GetWaitObjectIndex(const WaitObject* object) const { ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything"); - auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object); + const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object); return static_cast<s32>(std::distance(match, wait_objects.rend()) - 1); } VAddr Thread::GetCommandBufferAddress() const { // Offset from the start of TLS at which the IPC command buffer begins. - static constexpr int CommandHeaderOffset = 0x80; - return GetTLSAddress() + CommandHeaderOffset; + constexpr u64 command_header_offset = 0x80; + return GetTLSAddress() + command_header_offset; } void Thread::SetStatus(ThreadStatus new_status) { @@ -367,7 +371,7 @@ void Thread::ChangeScheduler() { system.CpuCore(processor_id).PrepareReschedule(); } -bool Thread::AllWaitObjectsReady() { +bool Thread::AllWaitObjectsReady() const { return std::none_of( wait_objects.begin(), wait_objects.end(), [this](const SharedPtr<WaitObject>& object) { return object->ShouldWait(this); }); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 9c684758c..73e5d1bb4 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -111,7 +111,7 @@ public: return HANDLE_TYPE; } - bool ShouldWait(Thread* thread) const override; + bool ShouldWait(const Thread* thread) const override; void Acquire(Thread* thread) override; /** @@ -205,7 +205,7 @@ public: * object in the list. * @param object Object to query the index of. */ - s32 GetWaitObjectIndex(WaitObject* object) const; + s32 GetWaitObjectIndex(const WaitObject* object) const; /** * Stops a thread, invalidating it from further use @@ -299,7 +299,7 @@ public: } /// Determines whether all the objects this thread is waiting on are ready. - bool AllWaitObjectsReady(); + bool AllWaitObjectsReady() const; const MutexWaitingThreads& GetMutexWaitingThreads() const { return wait_mutex_threads; diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp index 23228e1b5..26c4e5e67 100644 --- a/src/core/hle/kernel/transfer_memory.cpp +++ b/src/core/hle/kernel/transfer_memory.cpp @@ -14,8 +14,8 @@ namespace Kernel { TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {} TransferMemory::~TransferMemory() = default; -SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, - size_t size, MemoryPermission permissions) { +SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, u64 size, + MemoryPermission permissions) { SharedPtr<TransferMemory> transfer_memory{new TransferMemory(kernel)}; transfer_memory->base_address = base_address; @@ -26,7 +26,15 @@ SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_ return transfer_memory; } -ResultCode TransferMemory::MapMemory(VAddr address, size_t size, MemoryPermission permissions) { +const u8* TransferMemory::GetPointer() const { + return backing_block.get()->data(); +} + +u64 TransferMemory::GetSize() const { + return memory_size; +} + +ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission permissions) { if (memory_size != size) { return ERR_INVALID_SIZE; } @@ -39,13 +47,13 @@ ResultCode TransferMemory::MapMemory(VAddr address, size_t size, MemoryPermissio return ERR_INVALID_STATE; } + backing_block = std::make_shared<std::vector<u8>>(size); + const auto map_state = owner_permissions == MemoryPermission::None ? MemoryState::TransferMemoryIsolated : MemoryState::TransferMemory; auto& vm_manager = owner_process->VMManager(); - const auto map_result = vm_manager.MapMemoryBlock( - address, std::make_shared<std::vector<u8>>(size), 0, size, map_state); - + const auto map_result = vm_manager.MapMemoryBlock(address, backing_block, 0, size, map_state); if (map_result.Failed()) { return map_result.Code(); } @@ -54,7 +62,7 @@ ResultCode TransferMemory::MapMemory(VAddr address, size_t size, MemoryPermissio return RESULT_SUCCESS; } -ResultCode TransferMemory::UnmapMemory(VAddr address, size_t size) { +ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) { if (memory_size != size) { return ERR_INVALID_SIZE; } diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h index ec294951e..a140b1e2b 100644 --- a/src/core/hle/kernel/transfer_memory.h +++ b/src/core/hle/kernel/transfer_memory.h @@ -4,6 +4,9 @@ #pragma once +#include <memory> +#include <vector> + #include "core/hle/kernel/object.h" union ResultCode; @@ -25,7 +28,7 @@ class TransferMemory final : public Object { public: static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; - static SharedPtr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, size_t size, + static SharedPtr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size, MemoryPermission permissions); TransferMemory(const TransferMemory&) = delete; @@ -46,6 +49,12 @@ public: return HANDLE_TYPE; } + /// Gets a pointer to the backing block of this instance. + const u8* GetPointer() const; + + /// Gets the size of the memory backing this instance in bytes. + u64 GetSize() const; + /// Attempts to map transfer memory with the given range and memory permissions. /// /// @param address The base address to being mapping memory at. @@ -56,7 +65,7 @@ public: /// the same values that were given when creating the transfer memory /// instance. /// - ResultCode MapMemory(VAddr address, size_t size, MemoryPermission permissions); + ResultCode MapMemory(VAddr address, u64 size, MemoryPermission permissions); /// Unmaps the transfer memory with the given range /// @@ -66,17 +75,20 @@ public: /// @pre The given address and size must be the same as the ones used /// to create the transfer memory instance. /// - ResultCode UnmapMemory(VAddr address, size_t size); + ResultCode UnmapMemory(VAddr address, u64 size); private: explicit TransferMemory(KernelCore& kernel); ~TransferMemory() override; + /// Memory block backing this instance. + std::shared_ptr<std::vector<u8>> backing_block; + /// The base address for the memory managed by this instance. VAddr base_address = 0; /// Size of the memory, in bytes, that this instance manages. - size_t memory_size = 0; + u64 memory_size = 0; /// The memory permissions that are applied to this instance. MemoryPermission owner_permissions{}; diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h index 5987fb971..04464a51a 100644 --- a/src/core/hle/kernel/wait_object.h +++ b/src/core/hle/kernel/wait_object.h @@ -24,7 +24,7 @@ public: * @param thread The thread about which we're deciding. * @return True if the current thread should wait due to this object being unavailable */ - virtual bool ShouldWait(Thread* thread) const = 0; + virtual bool ShouldWait(const Thread* thread) const = 0; /// Acquire/lock the object for the specified thread if it is available virtual void Acquire(Thread* thread) = 0; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 9c44e27c6..85271d418 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -13,7 +13,7 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/readable_event.h" -#include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/transfer_memory.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am.h" @@ -239,8 +239,8 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger {0, nullptr, "Exit"}, {1, &ISelfController::LockExit, "LockExit"}, {2, &ISelfController::UnlockExit, "UnlockExit"}, - {3, nullptr, "EnterFatalSection"}, - {4, nullptr, "LeaveFatalSection"}, + {3, &ISelfController::EnterFatalSection, "EnterFatalSection"}, + {4, &ISelfController::LeaveFatalSection, "LeaveFatalSection"}, {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"}, {10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"}, {11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"}, @@ -285,41 +285,54 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger ISelfController::~ISelfController() = default; -void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { - // Takes 3 input u8s with each field located immediately after the previous - // u8, these are bool flags. No output. +void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - struct FocusHandlingModeParams { - u8 unknown0; - u8 unknown1; - u8 unknown2; - }; - auto flags = rp.PopRaw<FocusHandlingModeParams>(); +void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } -void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); +void ISelfController::EnterFatalSection(Kernel::HLERequestContext& ctx) { + ++num_fatal_sections_entered; + LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", num_fatal_sections_entered); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } -void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; +void ISelfController::LeaveFatalSection(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called."); - bool flag = rp.Pop<bool>(); - LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); + // Entry and exit of fatal sections must be balanced. + if (num_fatal_sections_entered == 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultCode{ErrorModule::AM, 512}); + return; + } + + --num_fatal_sections_entered; IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } +void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + launchable_event.writable->Signal(); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(launchable_event.readable); +} + void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); @@ -337,40 +350,52 @@ void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestCont rb.Push(RESULT_SUCCESS); } -void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) { - // Takes 3 input u8s with each field located immediately after the previous - // u8, these are bool flags. No output. +void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - bool enabled = rp.Pop<bool>(); - LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); + bool flag = rp.Pop<bool>(); + LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } -void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); +void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { + // Takes 3 input u8s with each field located immediately after the previous + // u8, these are bool flags. No output. + IPC::RequestParser rp{ctx}; + + struct FocusHandlingModeParams { + u8 unknown0; + u8 unknown1; + u8 unknown2; + }; + const auto flags = rp.PopRaw<FocusHandlingModeParams>(); + + LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}", + flags.unknown0, flags.unknown1, flags.unknown2); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } -void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { +void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } -void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); +void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) { + // Takes 3 input u8s with each field located immediately after the previous + // u8, these are bool flags. No output. + IPC::RequestParser rp{ctx}; - launchable_event.writable->Signal(); + bool enabled = rp.Pop<bool>(); + LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); - IPC::ResponseBuilder rb{ctx, 2, 1}; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(launchable_event.readable); } void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { @@ -907,19 +932,19 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex rp.SetCurrentOffset(3); const auto handle{rp.Pop<Kernel::Handle>()}; - const auto shared_mem = - Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::SharedMemory>( + const auto transfer_mem = + Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>( handle); - if (shared_mem == nullptr) { + if (transfer_mem == nullptr) { LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultCode(-1)); return; } - const u8* mem_begin = shared_mem->GetPointer(); - const u8* mem_end = mem_begin + shared_mem->GetSize(); + const u8* const mem_begin = transfer_mem->GetPointer(); + const u8* const mem_end = mem_begin + transfer_mem->GetSize(); std::vector<u8> memory{mem_begin, mem_end}; IPC::ResponseBuilder rb{ctx, 2, 0, 1}; diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 565dd8e9e..991b7d47c 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -117,17 +117,19 @@ public: ~ISelfController() override; private: - void SetFocusHandlingMode(Kernel::HLERequestContext& ctx); - void SetRestartMessageEnabled(Kernel::HLERequestContext& ctx); - void SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx); - void SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx); - void SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx); void LockExit(Kernel::HLERequestContext& ctx); void UnlockExit(Kernel::HLERequestContext& ctx); + void EnterFatalSection(Kernel::HLERequestContext& ctx); + void LeaveFatalSection(Kernel::HLERequestContext& ctx); void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx); + void SetScreenShotPermission(Kernel::HLERequestContext& ctx); + void SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx); + void SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx); + void SetFocusHandlingMode(Kernel::HLERequestContext& ctx); + void SetRestartMessageEnabled(Kernel::HLERequestContext& ctx); + void SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx); void SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx); void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx); - void SetScreenShotPermission(Kernel::HLERequestContext& ctx); void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx); void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); @@ -135,6 +137,7 @@ private: std::shared_ptr<NVFlinger::NVFlinger> nvflinger; Kernel::EventPair launchable_event; u32 idle_time_detection_extension = 0; + u64 num_fatal_sections_entered = 0; }; class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 21f5e64c7..39acb7b23 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -150,7 +150,6 @@ private: void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "called {}", ctx.Description()); - IPC::RequestParser rp{ctx}; const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)}; const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)}; @@ -194,12 +193,9 @@ private: void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "called"); - IPC::RequestParser rp{ctx}; - ctx.WriteBuffer(DefaultDevice); IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); rb.Push<u32>(1); // Amount of audio devices } diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index c9de10a24..1dde6edb7 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -10,6 +10,7 @@ #include "common/alignment.h" #include "common/common_funcs.h" #include "common/logging/log.h" +#include "common/string_util.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" @@ -184,7 +185,6 @@ public: private: void ListAudioDeviceName(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_Audio, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; constexpr std::array<char, 15> audio_interface{{"AudioInterface"}}; ctx.WriteBuffer(audio_interface); @@ -195,13 +195,13 @@ private: } void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_Audio, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - f32 volume = static_cast<f32>(rp.Pop<u32>()); + const f32 volume = rp.Pop<f32>(); - auto file_buffer = ctx.ReadBuffer(); - auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); + const auto device_name_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(device_name_buffer); + + LOG_WARNING(Service_Audio, "(STUBBED) called. name={}, volume={}", name, volume); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -209,7 +209,6 @@ private: void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_Audio, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; constexpr std::array<char, 12> audio_interface{{"AudioDevice"}}; ctx.WriteBuffer(audio_interface); diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index f03fb629c..592dce31a 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -315,61 +315,53 @@ public: void CreateFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - auto file_buffer = ctx.ReadBuffer(); - std::string name = Common::StringFromBuffer(file_buffer); + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); - u64 mode = rp.Pop<u64>(); - u32 size = rp.Pop<u32>(); + const u64 mode = rp.Pop<u64>(); + const u32 size = rp.Pop<u32>(); - LOG_DEBUG(Service_FS, "called file {} mode 0x{:X} size 0x{:08X}", name, mode, size); + LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, mode, size); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(backend.CreateFile(name, size)); } void DeleteFile(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - auto file_buffer = ctx.ReadBuffer(); - std::string name = Common::StringFromBuffer(file_buffer); + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); - LOG_DEBUG(Service_FS, "called file {}", name); + LOG_DEBUG(Service_FS, "called. file={}", name); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(backend.DeleteFile(name)); } void CreateDirectory(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - auto file_buffer = ctx.ReadBuffer(); - std::string name = Common::StringFromBuffer(file_buffer); + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); - LOG_DEBUG(Service_FS, "called directory {}", name); + LOG_DEBUG(Service_FS, "called. directory={}", name); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(backend.CreateDirectory(name)); } void DeleteDirectory(Kernel::HLERequestContext& ctx) { - const IPC::RequestParser rp{ctx}; - const auto file_buffer = ctx.ReadBuffer(); - std::string name = Common::StringFromBuffer(file_buffer); + const std::string name = Common::StringFromBuffer(file_buffer); - LOG_DEBUG(Service_FS, "called directory {}", name); + LOG_DEBUG(Service_FS, "called. directory={}", name); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(backend.DeleteDirectory(name)); } void DeleteDirectoryRecursively(Kernel::HLERequestContext& ctx) { - const IPC::RequestParser rp{ctx}; - const auto file_buffer = ctx.ReadBuffer(); - std::string name = Common::StringFromBuffer(file_buffer); + const std::string name = Common::StringFromBuffer(file_buffer); - LOG_DEBUG(Service_FS, "called directory {}", name); + LOG_DEBUG(Service_FS, "called. directory={}", name); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(backend.DeleteDirectoryRecursively(name)); @@ -386,18 +378,16 @@ public: } void RenameFile(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - std::vector<u8> buffer; buffer.resize(ctx.BufferDescriptorX()[0].Size()); Memory::ReadBlock(ctx.BufferDescriptorX()[0].Address(), buffer.data(), buffer.size()); - std::string src_name = Common::StringFromBuffer(buffer); + const std::string src_name = Common::StringFromBuffer(buffer); buffer.resize(ctx.BufferDescriptorX()[1].Size()); Memory::ReadBlock(ctx.BufferDescriptorX()[1].Address(), buffer.data(), buffer.size()); - std::string dst_name = Common::StringFromBuffer(buffer); + const std::string dst_name = Common::StringFromBuffer(buffer); - LOG_DEBUG(Service_FS, "called file '{}' to file '{}'", src_name, dst_name); + LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(backend.RenameFile(src_name, dst_name)); @@ -406,12 +396,12 @@ public: void OpenFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - auto file_buffer = ctx.ReadBuffer(); - std::string name = Common::StringFromBuffer(file_buffer); + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); - auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>()); + const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>()); - LOG_DEBUG(Service_FS, "called file {} mode {}", name, static_cast<u32>(mode)); + LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, static_cast<u32>(mode)); auto result = backend.OpenFile(name, mode); if (result.Failed()) { @@ -430,13 +420,13 @@ public: void OpenDirectory(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - auto file_buffer = ctx.ReadBuffer(); - std::string name = Common::StringFromBuffer(file_buffer); + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); // TODO(Subv): Implement this filter. - u32 filter_flags = rp.Pop<u32>(); + const u32 filter_flags = rp.Pop<u32>(); - LOG_DEBUG(Service_FS, "called directory {} filter {}", name, filter_flags); + LOG_DEBUG(Service_FS, "called. directory={}, filter={}", name, filter_flags); auto result = backend.OpenDirectory(name); if (result.Failed()) { @@ -453,12 +443,10 @@ public: } void GetEntryType(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - auto file_buffer = ctx.ReadBuffer(); - std::string name = Common::StringFromBuffer(file_buffer); + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); - LOG_DEBUG(Service_FS, "called file {}", name); + LOG_DEBUG(Service_FS, "called. file={}", name); auto result = backend.GetEntryType(name); if (result.Failed()) { diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index 13ab1d31e..852e71e4b 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp @@ -8,12 +8,20 @@ namespace Service::Sockets { void SFDNSRES::GetAddrInfo(Kernel::HLERequestContext& ctx) { + struct Parameters { + u8 use_nsd_resolve; + u32 unknown; + u64 process_id; + }; + IPC::RequestParser rp{ctx}; + const auto parameters = rp.PopRaw<Parameters>(); - LOG_WARNING(Service, "(STUBBED) called"); + LOG_WARNING(Service, + "(STUBBED) called. use_nsd_resolve={}, unknown=0x{:08X}, process_id=0x{:016X}", + parameters.use_nsd_resolve, parameters.unknown, parameters.process_id); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); } diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp index 8db0c2f13..e724d4ab8 100644 --- a/src/core/hle/service/spl/module.cpp +++ b/src/core/hle/service/spl/module.cpp @@ -26,9 +26,7 @@ Module::Interface::~Interface() = default; void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_SPL, "called"); - IPC::RequestParser rp{ctx}; - - std::size_t size = ctx.GetWriteBufferSize(); + const std::size_t size = ctx.GetWriteBufferSize(); std::uniform_int_distribution<u16> distribution(0, std::numeric_limits<u8>::max()); std::vector<u8> data(size); diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index af40a1815..f671f355e 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp @@ -68,9 +68,16 @@ public: private: void SetOption(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_SSL, "(STUBBED) called"); + struct Parameters { + u8 enable; + u32 option; + }; IPC::RequestParser rp{ctx}; + const auto parameters = rp.PopRaw<Parameters>(); + + LOG_WARNING(Service_SSL, "(STUBBED) called. enable={}, option={}", parameters.enable, + parameters.option); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 566cd6006..b77cb495d 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -1037,7 +1037,6 @@ private: void ListDisplays(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; DisplayInfo display_info; display_info.width *= static_cast<u64>(Settings::values.resolution_factor); display_info.height *= static_cast<u64>(Settings::values.resolution_factor); diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 8b1920f22..46ac372f6 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -341,7 +341,7 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) { } codeset.entrypoint = base_addr + header->e_entry; - codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image)); + codeset.memory = std::move(program_image); LOG_DEBUG(Loader, "Done loading."); diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 5de02a94b..31e4a0c84 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -187,7 +187,7 @@ static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data, program_image.resize(static_cast<u32>(program_image.size()) + bss_size); // Load codeset for current process - codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image)); + codeset.memory = std::move(program_image); process.LoadModule(std::move(codeset), load_base); // Register module with GDBStub diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 714d85a59..ffe2eea8a 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -4,11 +4,12 @@ #include <cinttypes> #include <vector> -#include <lz4.h> + #include "common/common_funcs.h" #include "common/file_util.h" #include "common/hex_util.h" #include "common/logging/log.h" +#include "common/lz4_compression.h" #include "common/swap.h" #include "core/core.h" #include "core/file_sys/patch_manager.h" @@ -35,15 +36,11 @@ static_assert(sizeof(MODHeader) == 0x1c, "MODHeader has incorrect size."); std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data, const NSOSegmentHeader& header) { - std::vector<u8> uncompressed_data(header.size); - const int bytes_uncompressed = - LZ4_decompress_safe(reinterpret_cast<const char*>(compressed_data.data()), - reinterpret_cast<char*>(uncompressed_data.data()), - static_cast<int>(compressed_data.size()), header.size); + const std::vector<u8> uncompressed_data = + Common::Compression::DecompressDataLZ4(compressed_data, header.size); - ASSERT_MSG(bytes_uncompressed == static_cast<int>(header.size) && - bytes_uncompressed == static_cast<int>(uncompressed_data.size()), - "{} != {} != {}", bytes_uncompressed, header.size, uncompressed_data.size()); + ASSERT_MSG(uncompressed_data.size() == static_cast<int>(header.size), "{} != {}", header.size, + uncompressed_data.size()); return uncompressed_data; } @@ -161,7 +158,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, } // Load codeset for current process - codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image)); + codeset.memory = std::move(program_image); process.LoadModule(std::move(codeset), load_base); // Register module with GDBStub diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 14b76680f..242a0d1cd 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -128,7 +128,9 @@ if (ENABLE_VULKAN) renderer_vulkan/vk_scheduler.cpp renderer_vulkan/vk_scheduler.h renderer_vulkan/vk_stream_buffer.cpp - renderer_vulkan/vk_stream_buffer.h) + renderer_vulkan/vk_stream_buffer.h + renderer_vulkan/vk_swapchain.cpp + renderer_vulkan/vk_swapchain.h) target_include_directories(video_core PRIVATE ../../externals/Vulkan-Headers/include) target_compile_definitions(video_core PRIVATE HAS_VULKAN) @@ -137,4 +139,4 @@ endif() create_target_directory_groups(video_core) target_link_libraries(video_core PUBLIC common core) -target_link_libraries(video_core PRIVATE glad lz4_static) +target_link_libraries(video_core PRIVATE glad) diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index fd091c84c..7989ec11b 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp @@ -7,7 +7,6 @@ #include "common/alignment.h" #include "core/core.h" -#include "core/memory.h" #include "video_core/renderer_opengl/gl_buffer_cache.h" #include "video_core/renderer_opengl/gl_rasterizer.h" diff --git a/src/video_core/renderer_opengl/gl_global_cache.cpp b/src/video_core/renderer_opengl/gl_global_cache.cpp index da9326253..5842d6213 100644 --- a/src/video_core/renderer_opengl/gl_global_cache.cpp +++ b/src/video_core/renderer_opengl/gl_global_cache.cpp @@ -4,7 +4,6 @@ #include <glad/glad.h> -#include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" #include "video_core/renderer_opengl/gl_global_cache.h" diff --git a/src/video_core/renderer_opengl/gl_primitive_assembler.cpp b/src/video_core/renderer_opengl/gl_primitive_assembler.cpp index 2bcbd3da2..c3e94d917 100644 --- a/src/video_core/renderer_opengl/gl_primitive_assembler.cpp +++ b/src/video_core/renderer_opengl/gl_primitive_assembler.cpp @@ -7,7 +7,7 @@ #include "common/assert.h" #include "common/common_types.h" #include "core/core.h" -#include "core/memory.h" +#include "video_core/memory_manager.h" #include "video_core/renderer_opengl/gl_buffer_cache.h" #include "video_core/renderer_opengl/gl_primitive_assembler.h" diff --git a/src/video_core/renderer_opengl/gl_primitive_assembler.h b/src/video_core/renderer_opengl/gl_primitive_assembler.h index 0e2e7dc36..4e87ce4d6 100644 --- a/src/video_core/renderer_opengl/gl_primitive_assembler.h +++ b/src/video_core/renderer_opengl/gl_primitive_assembler.h @@ -4,11 +4,9 @@ #pragma once -#include <vector> #include <glad/glad.h> #include "common/common_types.h" -#include "video_core/memory_manager.h" namespace OpenGL { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 046fc935b..7ff1e6737 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -17,7 +17,6 @@ #include "common/microprofile.h" #include "common/scope_exit.h" #include "core/core.h" -#include "core/frontend/emu_window.h" #include "core/hle/kernel/process.h" #include "core/settings.h" #include "video_core/engines/maxwell_3d.h" @@ -26,7 +25,6 @@ #include "video_core/renderer_opengl/gl_shader_gen.h" #include "video_core/renderer_opengl/maxwell_to_gl.h" #include "video_core/renderer_opengl/renderer_opengl.h" -#include "video_core/video_core.h" namespace OpenGL { @@ -318,7 +316,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { const std::size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5 GLShader::MaxwellUniformData ubo{}; - ubo.SetFromRegs(gpu.state.shader_stages[stage]); + ubo.SetFromRegs(gpu, stage); const GLintptr offset = buffer_cache.UploadHostMemory( &ubo, sizeof(ubo), static_cast<std::size_t>(uniform_buffer_alignment)); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 4de565321..54fbf48aa 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -12,15 +12,12 @@ #include <optional> #include <tuple> #include <utility> -#include <vector> #include <boost/icl/interval_map.hpp> -#include <boost/range/iterator_range.hpp> #include <glad/glad.h> #include "common/common_types.h" #include "video_core/engines/maxwell_3d.h" -#include "video_core/memory_manager.h" #include "video_core/rasterizer_cache.h" #include "video_core/rasterizer_interface.h" #include "video_core/renderer_opengl/gl_buffer_cache.h" @@ -29,10 +26,8 @@ #include "video_core/renderer_opengl/gl_rasterizer_cache.h" #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_shader_cache.h" -#include "video_core/renderer_opengl/gl_shader_gen.h" #include "video_core/renderer_opengl/gl_shader_manager.h" #include "video_core/renderer_opengl/gl_state.h" -#include "video_core/renderer_opengl/gl_stream_buffer.h" namespace Core { class System; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index aba6ce731..7a3280620 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -13,7 +13,6 @@ #include "common/scope_exit.h" #include "core/core.h" #include "core/hle/kernel/process.h" -#include "core/memory.h" #include "core/settings.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/morton.h" diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index e8073579f..ad4fd3ad2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -5,10 +5,9 @@ #pragma once #include <array> -#include <map> #include <memory> #include <string> -#include <unordered_set> +#include <tuple> #include <vector> #include "common/alignment.h" diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 290e654bc..7030db365 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -6,13 +6,11 @@ #include "common/assert.h" #include "common/hash.h" #include "core/core.h" -#include "core/memory.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_opengl/gl_rasterizer.h" #include "video_core/renderer_opengl/gl_shader_cache.h" #include "video_core/renderer_opengl/gl_shader_decompiler.h" #include "video_core/renderer_opengl/gl_shader_disk_cache.h" -#include "video_core/renderer_opengl/gl_shader_manager.h" #include "video_core/renderer_opengl/utils.h" #include "video_core/shader/shader_ir.h" diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index fd1c85115..0cf8e0b3d 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h @@ -5,21 +5,20 @@ #pragma once #include <array> +#include <atomic> #include <memory> #include <set> #include <tuple> #include <unordered_map> +#include <vector> #include <glad/glad.h> -#include "common/assert.h" #include "common/common_types.h" #include "video_core/rasterizer_cache.h" -#include "video_core/renderer_base.h" #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_shader_decompiler.h" #include "video_core/renderer_opengl/gl_shader_disk_cache.h" -#include "video_core/renderer_opengl/gl_shader_gen.h" namespace Core { class System; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 11d1169f0..7300a4037 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -1196,11 +1196,12 @@ private: switch (meta->element) { case 0: case 1: - return "textureSize(" + sampler + ", " + lod + ')' + GetSwizzle(meta->element); + return "itof(int(textureSize(" + sampler + ", " + lod + ')' + + GetSwizzle(meta->element) + "))"; case 2: return "0"; case 3: - return "textureQueryLevels(" + sampler + ')'; + return "itof(textureQueryLevels(" + sampler + "))"; } UNREACHABLE(); return "0"; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h index 72aca4938..4e04ab2f8 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.h +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h @@ -5,7 +5,6 @@ #pragma once #include <array> -#include <set> #include <string> #include <utility> #include <vector> diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp index 82fc4d44b..d2d979997 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp @@ -4,13 +4,13 @@ #include <cstring> #include <fmt/format.h> -#include <lz4.h> #include "common/assert.h" #include "common/common_paths.h" #include "common/common_types.h" #include "common/file_util.h" #include "common/logging/log.h" +#include "common/lz4_compression.h" #include "common/scm_rev.h" #include "core/core.h" @@ -49,39 +49,6 @@ ShaderCacheVersionHash GetShaderCacheVersionHash() { return hash; } -template <typename T> -std::vector<u8> CompressData(const T* source, std::size_t source_size) { - if (source_size > LZ4_MAX_INPUT_SIZE) { - // Source size exceeds LZ4 maximum input size - return {}; - } - const auto source_size_int = static_cast<int>(source_size); - const int max_compressed_size = LZ4_compressBound(source_size_int); - std::vector<u8> compressed(max_compressed_size); - const int compressed_size = LZ4_compress_default(reinterpret_cast<const char*>(source), - reinterpret_cast<char*>(compressed.data()), - source_size_int, max_compressed_size); - if (compressed_size <= 0) { - // Compression failed - return {}; - } - compressed.resize(compressed_size); - return compressed; -} - -std::vector<u8> DecompressData(const std::vector<u8>& compressed, std::size_t uncompressed_size) { - std::vector<u8> uncompressed(uncompressed_size); - const int size_check = LZ4_decompress_safe(reinterpret_cast<const char*>(compressed.data()), - reinterpret_cast<char*>(uncompressed.data()), - static_cast<int>(compressed.size()), - static_cast<int>(uncompressed.size())); - if (static_cast<int>(uncompressed_size) != size_check) { - // Decompression failed - return {}; - } - return uncompressed; -} - } // namespace ShaderDiskCacheRaw::ShaderDiskCacheRaw(u64 unique_identifier, Maxwell::ShaderProgram program_type, @@ -292,7 +259,7 @@ ShaderDiskCacheOpenGL::LoadPrecompiledFile(FileUtil::IOFile& file) { return {}; } - dump.binary = DecompressData(compressed_binary, binary_length); + dump.binary = Common::Compression::DecompressDataLZ4(compressed_binary, binary_length); if (dump.binary.empty()) { return {}; } @@ -321,7 +288,7 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn return {}; } - const std::vector<u8> code = DecompressData(compressed_code, code_size); + const std::vector<u8> code = Common::Compression::DecompressDataLZ4(compressed_code, code_size); if (code.empty()) { return {}; } @@ -507,7 +474,8 @@ void ShaderDiskCacheOpenGL::SaveDecompiled(u64 unique_identifier, const std::str if (!IsUsable()) return; - const std::vector<u8> compressed_code{CompressData(code.data(), code.size())}; + const std::vector<u8> compressed_code{Common::Compression::CompressDataLZ4HC( + reinterpret_cast<const u8*>(code.data()), code.size(), 9)}; if (compressed_code.empty()) { LOG_ERROR(Render_OpenGL, "Failed to compress GLSL code - skipping shader {:016x}", unique_identifier); @@ -537,7 +505,9 @@ void ShaderDiskCacheOpenGL::SaveDump(const ShaderDiskCacheUsage& usage, GLuint p std::vector<u8> binary(binary_length); glGetProgramBinary(program, binary_length, nullptr, &binary_format, binary.data()); - const std::vector<u8> compressed_binary = CompressData(binary.data(), binary.size()); + const std::vector<u8> compressed_binary = + Common::Compression::CompressDataLZ4HC(binary.data(), binary.size(), 9); + if (compressed_binary.empty()) { LOG_ERROR(Render_OpenGL, "Failed to compress binary program in shader={:016x}", usage.unique_identifier); diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 7d96649af..8763d9c71 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include <fmt/format.h> -#include "common/assert.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_opengl/gl_shader_decompiler.h" #include "video_core/renderer_opengl/gl_shader_gen.h" diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index fba8e681b..fad346b48 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h @@ -4,12 +4,9 @@ #pragma once -#include <array> -#include <string> #include <vector> #include "common/common_types.h" -#include "video_core/engines/shader_bytecode.h" #include "video_core/renderer_opengl/gl_shader_decompiler.h" #include "video_core/shader/shader_ir.h" diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 6a30c28d2..eaf3e03a0 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp @@ -2,15 +2,15 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "core/core.h" #include "video_core/renderer_opengl/gl_shader_manager.h" namespace OpenGL::GLShader { -void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage) { - const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); - const auto& regs = gpu.regs; - const auto& state = gpu.state; +using Tegra::Engines::Maxwell3D; + +void MaxwellUniformData::SetFromRegs(const Maxwell3D& maxwell, std::size_t shader_stage) { + const auto& regs = maxwell.regs; + const auto& state = maxwell.state; // TODO(bunnei): Support more than one viewport viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f; @@ -18,7 +18,7 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh u32 func = static_cast<u32>(regs.alpha_test_func); // Normalize the gl variants of opCompare to be the same as the normal variants - u32 op_gl_variant_base = static_cast<u32>(Tegra::Engines::Maxwell3D::Regs::ComparisonOp::Never); + const u32 op_gl_variant_base = static_cast<u32>(Maxwell3D::Regs::ComparisonOp::Never); if (func >= op_gl_variant_base) { func = func - op_gl_variant_base + 1U; } @@ -31,8 +31,9 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh // Assign in which stage the position has to be flipped // (the last stage before the fragment shader). - if (gpu.regs.shader_config[static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry)].enable) { - flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry); + constexpr u32 geometry_index = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry); + if (maxwell.regs.shader_config[geometry_index].enable) { + flip_stage = geometry_index; } else { flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB); } diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index 4970aafed..8eef2a920 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -12,14 +12,13 @@ namespace OpenGL::GLShader { -using Tegra::Engines::Maxwell3D; - /// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned -// NOTE: Always keep a vec4 at the end. The GL spec is not clear whether the alignment at -// the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not. -// Not following that rule will cause problems on some AMD drivers. +/// @note Always keep a vec4 at the end. The GL spec is not clear whether the alignment at +/// the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not. +/// Not following that rule will cause problems on some AMD drivers. struct MaxwellUniformData { - void SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage); + void SetFromRegs(const Tegra::Engines::Maxwell3D& maxwell, std::size_t shader_stage); + alignas(16) GLvec4 viewport_flip; struct alignas(16) { GLuint instance_id; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index a01efeb05..d69cba9c3 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -5,7 +5,6 @@ #include <algorithm> #include <cstddef> #include <cstdlib> -#include <cstring> #include <memory> #include <glad/glad.h> #include "common/assert.h" diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp new file mode 100644 index 000000000..08279e562 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -0,0 +1,210 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <array> +#include <limits> +#include <vector> + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/core.h" +#include "core/frontend/framebuffer_layout.h" +#include "video_core/renderer_vulkan/declarations.h" +#include "video_core/renderer_vulkan/vk_device.h" +#include "video_core/renderer_vulkan/vk_resource_manager.h" +#include "video_core/renderer_vulkan/vk_swapchain.h" + +namespace Vulkan { + +namespace { +vk::SurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector<vk::SurfaceFormatKHR>& formats) { + if (formats.size() == 1 && formats[0].format == vk::Format::eUndefined) { + return {vk::Format::eB8G8R8A8Unorm, vk::ColorSpaceKHR::eSrgbNonlinear}; + } + const auto& found = std::find_if(formats.begin(), formats.end(), [](const auto& format) { + return format.format == vk::Format::eB8G8R8A8Unorm && + format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear; + }); + return found != formats.end() ? *found : formats[0]; +} + +vk::PresentModeKHR ChooseSwapPresentMode(const std::vector<vk::PresentModeKHR>& modes) { + // Mailbox doesn't lock the application like fifo (vsync), prefer it + const auto& found = std::find_if(modes.begin(), modes.end(), [](const auto& mode) { + return mode == vk::PresentModeKHR::eMailbox; + }); + return found != modes.end() ? *found : vk::PresentModeKHR::eFifo; +} + +vk::Extent2D ChooseSwapExtent(const vk::SurfaceCapabilitiesKHR& capabilities, u32 width, + u32 height) { + constexpr auto undefined_size{std::numeric_limits<u32>::max()}; + if (capabilities.currentExtent.width != undefined_size) { + return capabilities.currentExtent; + } + vk::Extent2D extent = {width, height}; + extent.width = std::max(capabilities.minImageExtent.width, + std::min(capabilities.maxImageExtent.width, extent.width)); + extent.height = std::max(capabilities.minImageExtent.height, + std::min(capabilities.maxImageExtent.height, extent.height)); + return extent; +} +} // namespace + +VKSwapchain::VKSwapchain(vk::SurfaceKHR surface, const VKDevice& device) + : surface{surface}, device{device} {} + +VKSwapchain::~VKSwapchain() = default; + +void VKSwapchain::Create(u32 width, u32 height) { + const auto dev = device.GetLogical(); + const auto& dld = device.GetDispatchLoader(); + const auto physical_device = device.GetPhysical(); + + const vk::SurfaceCapabilitiesKHR capabilities{ + physical_device.getSurfaceCapabilitiesKHR(surface, dld)}; + if (capabilities.maxImageExtent.width == 0 || capabilities.maxImageExtent.height == 0) { + return; + } + + dev.waitIdle(dld); + Destroy(); + + CreateSwapchain(capabilities, width, height); + CreateSemaphores(); + CreateImageViews(); + + fences.resize(image_count, nullptr); +} + +void VKSwapchain::AcquireNextImage() { + const auto dev{device.GetLogical()}; + const auto& dld{device.GetDispatchLoader()}; + dev.acquireNextImageKHR(*swapchain, std::numeric_limits<u64>::max(), + *present_semaphores[frame_index], {}, &image_index, dld); + + if (auto& fence = fences[image_index]; fence) { + fence->Wait(); + fence->Release(); + fence = nullptr; + } +} + +bool VKSwapchain::Present(vk::Semaphore render_semaphore, VKFence& fence) { + const vk::Semaphore present_semaphore{*present_semaphores[frame_index]}; + const std::array<vk::Semaphore, 2> semaphores{present_semaphore, render_semaphore}; + const u32 wait_semaphore_count{render_semaphore ? 2U : 1U}; + const auto& dld{device.GetDispatchLoader()}; + const auto present_queue{device.GetPresentQueue()}; + bool recreated = false; + + const vk::PresentInfoKHR present_info(wait_semaphore_count, semaphores.data(), 1, + &swapchain.get(), &image_index, {}); + switch (const auto result = present_queue.presentKHR(&present_info, dld); result) { + case vk::Result::eSuccess: + break; + case vk::Result::eErrorOutOfDateKHR: + if (current_width > 0 && current_height > 0) { + Create(current_width, current_height); + recreated = true; + } + break; + default: + LOG_CRITICAL(Render_Vulkan, "Vulkan failed to present swapchain due to {}!", + vk::to_string(result)); + UNREACHABLE(); + } + + ASSERT(fences[image_index] == nullptr); + fences[image_index] = &fence; + frame_index = (frame_index + 1) % image_count; + return recreated; +} + +bool VKSwapchain::HasFramebufferChanged(const Layout::FramebufferLayout& framebuffer) const { + // TODO(Rodrigo): Handle framebuffer pixel format changes + return framebuffer.width != current_width || framebuffer.height != current_height; +} + +void VKSwapchain::CreateSwapchain(const vk::SurfaceCapabilitiesKHR& capabilities, u32 width, + u32 height) { + const auto dev{device.GetLogical()}; + const auto& dld{device.GetDispatchLoader()}; + const auto physical_device{device.GetPhysical()}; + + const std::vector<vk::SurfaceFormatKHR> formats{ + physical_device.getSurfaceFormatsKHR(surface, dld)}; + + const std::vector<vk::PresentModeKHR> present_modes{ + physical_device.getSurfacePresentModesKHR(surface, dld)}; + + const vk::SurfaceFormatKHR surface_format{ChooseSwapSurfaceFormat(formats)}; + const vk::PresentModeKHR present_mode{ChooseSwapPresentMode(present_modes)}; + extent = ChooseSwapExtent(capabilities, width, height); + + current_width = extent.width; + current_height = extent.height; + + u32 requested_image_count{capabilities.minImageCount + 1}; + if (capabilities.maxImageCount > 0 && requested_image_count > capabilities.maxImageCount) { + requested_image_count = capabilities.maxImageCount; + } + + vk::SwapchainCreateInfoKHR swapchain_ci( + {}, surface, requested_image_count, surface_format.format, surface_format.colorSpace, + extent, 1, vk::ImageUsageFlagBits::eColorAttachment, {}, {}, {}, + capabilities.currentTransform, vk::CompositeAlphaFlagBitsKHR::eOpaque, present_mode, false, + {}); + + const u32 graphics_family{device.GetGraphicsFamily()}; + const u32 present_family{device.GetPresentFamily()}; + const std::array<u32, 2> queue_indices{graphics_family, present_family}; + if (graphics_family != present_family) { + swapchain_ci.imageSharingMode = vk::SharingMode::eConcurrent; + swapchain_ci.queueFamilyIndexCount = static_cast<u32>(queue_indices.size()); + swapchain_ci.pQueueFamilyIndices = queue_indices.data(); + } else { + swapchain_ci.imageSharingMode = vk::SharingMode::eExclusive; + } + + swapchain = dev.createSwapchainKHRUnique(swapchain_ci, nullptr, dld); + + images = dev.getSwapchainImagesKHR(*swapchain, dld); + image_count = static_cast<u32>(images.size()); + image_format = surface_format.format; +} + +void VKSwapchain::CreateSemaphores() { + const auto dev{device.GetLogical()}; + const auto& dld{device.GetDispatchLoader()}; + + present_semaphores.resize(image_count); + for (std::size_t i = 0; i < image_count; i++) { + present_semaphores[i] = dev.createSemaphoreUnique({}, nullptr, dld); + } +} + +void VKSwapchain::CreateImageViews() { + const auto dev{device.GetLogical()}; + const auto& dld{device.GetDispatchLoader()}; + + image_views.resize(image_count); + for (std::size_t i = 0; i < image_count; i++) { + const vk::ImageViewCreateInfo image_view_ci({}, images[i], vk::ImageViewType::e2D, + image_format, {}, + {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}); + image_views[i] = dev.createImageViewUnique(image_view_ci, nullptr, dld); + } +} + +void VKSwapchain::Destroy() { + frame_index = 0; + present_semaphores.clear(); + framebuffers.clear(); + image_views.clear(); + swapchain.reset(); +} + +} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h new file mode 100644 index 000000000..2ad84f185 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_swapchain.h @@ -0,0 +1,92 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <vector> + +#include "common/common_types.h" +#include "video_core/renderer_vulkan/declarations.h" + +namespace Layout { +struct FramebufferLayout; +} + +namespace Vulkan { + +class VKDevice; +class VKFence; + +class VKSwapchain { +public: + explicit VKSwapchain(vk::SurfaceKHR surface, const VKDevice& device); + ~VKSwapchain(); + + /// Creates (or recreates) the swapchain with a given size. + void Create(u32 width, u32 height); + + /// Acquires the next image in the swapchain, waits as needed. + void AcquireNextImage(); + + /// Presents the rendered image to the swapchain. Returns true when the swapchains had to be + /// recreated. Takes responsability for the ownership of fence. + bool Present(vk::Semaphore render_semaphore, VKFence& fence); + + /// Returns true when the framebuffer layout has changed. + bool HasFramebufferChanged(const Layout::FramebufferLayout& framebuffer) const; + + const vk::Extent2D& GetSize() const { + return extent; + } + + u32 GetImageCount() const { + return image_count; + } + + u32 GetImageIndex() const { + return image_index; + } + + vk::Image GetImageIndex(u32 index) const { + return images[index]; + } + + vk::ImageView GetImageViewIndex(u32 index) const { + return *image_views[index]; + } + + vk::Format GetImageFormat() const { + return image_format; + } + +private: + void CreateSwapchain(const vk::SurfaceCapabilitiesKHR& capabilities, u32 width, u32 height); + void CreateSemaphores(); + void CreateImageViews(); + + void Destroy(); + + const vk::SurfaceKHR surface; + const VKDevice& device; + + UniqueSwapchainKHR swapchain; + + u32 image_count{}; + std::vector<vk::Image> images; + std::vector<UniqueImageView> image_views; + std::vector<UniqueFramebuffer> framebuffers; + std::vector<VKFence*> fences; + std::vector<UniqueSemaphore> present_semaphores; + + u32 image_index{}; + u32 frame_index{}; + + vk::Format image_format{}; + vk::Extent2D extent{}; + + u32 current_width{}; + u32 current_height{}; +}; + +} // namespace Vulkan diff --git a/src/yuzu/applets/profile_select.cpp b/src/yuzu/applets/profile_select.cpp index 730426c16..f95f7fe3c 100644 --- a/src/yuzu/applets/profile_select.cpp +++ b/src/yuzu/applets/profile_select.cpp @@ -58,10 +58,7 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent) scroll_area = new QScrollArea; - buttons = new QDialogButtonBox; - buttons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole); - buttons->addButton(tr("OK"), QDialogButtonBox::AcceptRole); - + buttons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); connect(buttons, &QDialogButtonBox::accepted, this, &QtProfileSelectionDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &QtProfileSelectionDialog::reject); diff --git a/src/yuzu/applets/software_keyboard.cpp b/src/yuzu/applets/software_keyboard.cpp index eddc9c941..f3eb29b25 100644 --- a/src/yuzu/applets/software_keyboard.cpp +++ b/src/yuzu/applets/software_keyboard.cpp @@ -75,13 +75,13 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog( length_label->setText(QStringLiteral("%1/%2").arg(text.size()).arg(parameters.max_length)); }); - buttons = new QDialogButtonBox; - buttons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole); - buttons->addButton(parameters.submit_text.empty() - ? tr("OK") - : QString::fromStdU16String(parameters.submit_text), - QDialogButtonBox::AcceptRole); - + buttons = new QDialogButtonBox(QDialogButtonBox::Cancel); + if (parameters.submit_text.empty()) { + buttons->addButton(QDialogButtonBox::Ok); + } else { + buttons->addButton(QString::fromStdU16String(parameters.submit_text), + QDialogButtonBox::AcceptRole); + } connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::reject); layout->addWidget(header_label); diff --git a/src/yuzu/debugger/profiler.cpp b/src/yuzu/debugger/profiler.cpp index 8b30e0a85..86e03e46d 100644 --- a/src/yuzu/debugger/profiler.cpp +++ b/src/yuzu/debugger/profiler.cpp @@ -7,6 +7,7 @@ #include <QMouseEvent> #include <QPainter> #include <QString> +#include <QTimer> #include "common/common_types.h" #include "common/microprofile.h" #include "yuzu/debugger/profiler.h" diff --git a/src/yuzu/debugger/profiler.h b/src/yuzu/debugger/profiler.h index eae1e9e3c..8e69fdb06 100644 --- a/src/yuzu/debugger/profiler.h +++ b/src/yuzu/debugger/profiler.h @@ -4,10 +4,11 @@ #pragma once -#include <QAbstractItemModel> -#include <QDockWidget> -#include <QTimer> -#include "common/microprofile.h" +#include <QWidget> + +class QAction; +class QHideEvent; +class QShowEvent; class MicroProfileDialog : public QWidget { Q_OBJECT diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index c0e3c5fa9..4422a572b 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -329,6 +329,8 @@ void GameList::PopupContextMenu(const QPoint& menu_location) { QMenu context_menu; QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location")); QAction* open_lfs_location = context_menu.addAction(tr("Open Mod Data Location")); + QAction* open_transferable_shader_cache = + context_menu.addAction(tr("Open Transferable Shader Cache")); context_menu.addSeparator(); QAction* dump_romfs = context_menu.addAction(tr("Dump RomFS")); QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard")); @@ -344,6 +346,8 @@ void GameList::PopupContextMenu(const QPoint& menu_location) { [&]() { emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData); }); connect(open_lfs_location, &QAction::triggered, [&]() { emit OpenFolderRequested(program_id, GameListOpenTarget::ModData); }); + connect(open_transferable_shader_cache, &QAction::triggered, + [&]() { emit OpenTransferableShaderCacheRequested(program_id); }); connect(dump_romfs, &QAction::triggered, [&]() { emit DumpRomFSRequested(program_id, path); }); connect(copy_tid, &QAction::triggered, [&]() { emit CopyTIDRequested(program_id); }); connect(navigate_to_gamedb_entry, &QAction::triggered, diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index b317eb2fc..8ea5cbaaa 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -66,6 +66,7 @@ signals: void GameChosen(QString game_path); void ShouldCancelWorker(); void OpenFolderRequested(u64 program_id, GameListOpenTarget target); + void OpenTransferableShaderCacheRequested(u64 program_id); void DumpRomFSRequested(u64 program_id, const std::string& game_path); void CopyTIDRequested(u64 program_id); void NavigateToGamedbEntryRequested(u64 program_id, diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 41ba3c4c6..2b9db69a3 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -37,14 +37,20 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include <glad/glad.h> #define QT_NO_OPENGL +#include <QClipboard> +#include <QDesktopServices> #include <QDesktopWidget> #include <QDialogButtonBox> #include <QFile> #include <QFileDialog> +#include <QInputDialog> #include <QMessageBox> +#include <QProgressBar> +#include <QProgressDialog> +#include <QShortcut> +#include <QStatusBar> #include <QtConcurrent/QtConcurrent> -#include <QtGui> -#include <QtWidgets> + #include <fmt/format.h> #include "common/common_paths.h" #include "common/detached_tasks.h" @@ -55,11 +61,9 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "common/microprofile.h" #include "common/scm_rev.h" #include "common/scope_exit.h" -#include "common/string_util.h" #include "common/telemetry.h" #include "core/core.h" #include "core/crypto/key_manager.h" -#include "core/file_sys/bis_factory.h" #include "core/file_sys/card_image.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/control_metadata.h" @@ -71,7 +75,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "core/frontend/applets/software_keyboard.h" #include "core/hle/kernel/process.h" #include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/filesystem/fsp_ldr.h" #include "core/hle/service/nfp/nfp.h" #include "core/hle/service/sm/sm.h" #include "core/loader/loader.h" @@ -648,6 +651,8 @@ void GMainWindow::RestoreUIState() { void GMainWindow::ConnectWidgetEvents() { connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile); connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder); + connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this, + &GMainWindow::OnTransferableShaderCacheOpenFile); connect(game_list, &GameList::DumpRomFSRequested, this, &GMainWindow::OnGameListDumpRomFS); connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID); connect(game_list, &GameList::NavigateToGamedbEntryRequested, this, @@ -1082,6 +1087,39 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); } +void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { + ASSERT(program_id != 0); + + const QString tranferable_shader_cache_folder_path = + QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir)) + "opengl" + + DIR_SEP + "transferable"; + + const QString transferable_shader_cache_file_path = + tranferable_shader_cache_folder_path + DIR_SEP + + QString::fromStdString(fmt::format("{:016X}.bin", program_id)); + + if (!QFile::exists(transferable_shader_cache_file_path)) { + QMessageBox::warning(this, tr("Error Opening Transferable Shader Cache"), + tr("A shader cache for this title does not exist.")); + return; + } + + // Windows supports opening a folder with selecting a specified file in explorer. On every other + // OS we just open the transferable shader cache folder without preselecting the transferable + // shader cache file for the selected game. +#if defined(Q_OS_WIN) + const QString explorer = QStringLiteral("explorer"); + QStringList param; + if (!QFileInfo(transferable_shader_cache_file_path).isDir()) { + param << QStringLiteral("/select,"); + } + param << QDir::toNativeSeparators(transferable_shader_cache_file_path); + QProcess::startDetached(explorer, param); +#else + QDesktopServices::openUrl(QUrl::fromLocalFile(tranferable_shader_cache_folder_path)); +#endif +} + static std::size_t CalculateRomFSEntrySize(const FileSys::VirtualDir& dir, bool full) { std::size_t out = 0; diff --git a/src/yuzu/main.h b/src/yuzu/main.h index e07c892cf..7f3aa998e 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -176,6 +176,7 @@ private slots: /// Called whenever a user selects a game in the game list widget. void OnGameListLoadFile(QString game_path); void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target); + void OnTransferableShaderCacheOpenFile(u64 program_id); void OnGameListDumpRomFS(u64 program_id, const std::string& game_path); void OnGameListCopyTID(u64 program_id); void OnGameListNavigateToGamedbEntry(u64 program_id, |