From 19291ba4655a9dac59a0222efe0e019b7e56fe3b Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Tue, 11 Sep 2018 14:34:18 -0400 Subject: [PATCH 001/102] LLE Mapped Buffer: Add unmapping, zero-size, and multiple page handling --- src/core/hle/kernel/ipc.cpp | 49 ++++++++++++++++++++++++-------- src/core/hle/kernel/vm_manager.h | 3 ++ 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/core/hle/kernel/ipc.cpp b/src/core/hle/kernel/ipc.cpp index 8db9d241f..8a6214409 100644 --- a/src/core/hle/kernel/ipc.cpp +++ b/src/core/hle/kernel/ipc.cpp @@ -128,7 +128,11 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtr> Memory::PAGE_BITS; - ASSERT(num_pages >= 1); + // Skip when the size is zero + if (size == 0) { + i += 1; + break; + } if (reply) { // TODO(Subv): Scan the target's command buffer to make sure that there was a @@ -139,13 +143,23 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtrvm_manager.UnmapRange( + page_start, num_pages * Memory::PAGE_SIZE); + ASSERT(result == RESULT_SUCCESS); + } else { + const auto vma_iter = src_process->vm_manager.vma_map.find(source_address); + const auto& vma = vma_iter->second; + const VAddr dest_address = vma.originating_buffer_address; + + auto buffer = std::make_shared>(size); + Memory::ReadBlock(*src_process, source_address, buffer->data(), size); + Memory::WriteBlock(*dst_process, dest_address, buffer->data(), size); + ResultCode result = src_process->vm_manager.UnmapRange( page_start, num_pages * Memory::PAGE_SIZE); ASSERT(result == RESULT_SUCCESS); } - ASSERT_MSG(permissions == IPC::MappedBufferPermissions::R, - "Unmapping Write MappedBuffers is unimplemented"); i += 1; break; } @@ -156,19 +170,13 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtr src_thread, SharedPtr(buffer->size()), Kernel::MemoryState::Shared) .Unwrap(); + } else { + auto buffer = std::make_shared>(num_pages * Memory::PAGE_SIZE); + Memory::ReadBlock(*src_process, source_address, buffer->data() + page_offset, size); + + // Map the pages into the target process' address space. + target_address = + dst_process->vm_manager + .MapMemoryBlockToBase(Memory::IPC_MAPPING_VADDR + Memory::PAGE_SIZE, + Memory::IPC_MAPPING_SIZE - Memory::PAGE_SIZE, buffer, + 0, static_cast(buffer->size()), + Kernel::MemoryState::Shared) + .Unwrap(); } + // Save the original address we copied the buffer from so that we can copy the modified + // buffer back, if needed + auto vma_iter = dst_process->vm_manager.vma_map.find(target_address + page_offset); + auto& vma = vma_iter->second; + vma.originating_buffer_address = source_address; cmd_buf[i++] = target_address + page_offset; break; diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 7ac5c3b01..fcb107c06 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -86,6 +86,9 @@ struct VirtualMemoryArea { PAddr paddr = 0; Memory::MMIORegionPointer mmio_handler = nullptr; + /// Originating address of the IPC mapped buffer + VAddr originating_buffer_address = 0; + /// Tests if this area can be merged to the right with `next`. bool CanBeMergedWith(const VirtualMemoryArea& next) const; }; From 51d53a62815dfb8fd20655403af58aed357e2637 Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Sun, 30 Sep 2018 21:21:51 -0400 Subject: [PATCH 002/102] LLE Mapped Buffer: addressed comments --- src/core/hle/kernel/ipc.cpp | 159 +++++++++++++++++-------------- src/core/hle/kernel/vm_manager.h | 3 - src/core/memory.cpp | 52 ++++++++++ src/core/memory.h | 2 + 4 files changed, 140 insertions(+), 76 deletions(-) diff --git a/src/core/hle/kernel/ipc.cpp b/src/core/hle/kernel/ipc.cpp index 8a6214409..070bb6619 100644 --- a/src/core/hle/kernel/ipc.cpp +++ b/src/core/hle/kernel/ipc.cpp @@ -33,6 +33,17 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtr cmd_buf; Memory::ReadBlock(*src_process, src_address, cmd_buf.data(), command_size * sizeof(u32)); + // Create a copy of the target's command buffer + IPC::Header dst_header; + Memory::ReadBlock(*dst_process, dst_address, &dst_header.raw, sizeof(dst_header.raw)); + + std::size_t dst_untranslated_size = 1u + dst_header.normal_params_size; + std::size_t dst_command_size = dst_untranslated_size + dst_header.translate_params_size; + + std::array dst_cmd_buf; + Memory::ReadBlock(*dst_process, dst_address, dst_cmd_buf.data(), + dst_command_size * sizeof(u32)); + std::size_t i = untranslated_size; while (i < command_size) { u32 descriptor = cmd_buf[i]; @@ -128,36 +139,63 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtr> Memory::PAGE_BITS; - // Skip when the size is zero + // Skip when the size is zero and num_pages == 0 if (size == 0) { - i += 1; + cmd_buf[i++] = 0; break; } + ASSERT(num_pages >= 1); if (reply) { - // TODO(Subv): Scan the target's command buffer to make sure that there was a - // MappedBuffer descriptor in the original request. The real kernel panics if you - // try to reply with an unsolicited MappedBuffer. + // Scan the target's command buffer for the matching mapped buffer + std::size_t j = dst_untranslated_size; + while (j < dst_command_size) { + u32 desc = dst_cmd_buf[j++]; - // Unmap the buffers. Readonly buffers do not need to be copied over to the target - // process again because they were (presumably) not modified. This behavior is - // consistent with the real kernel. - if (permissions == IPC::MappedBufferPermissions::R) { - ResultCode result = src_process->vm_manager.UnmapRange( - page_start, num_pages * Memory::PAGE_SIZE); - ASSERT(result == RESULT_SUCCESS); - } else { - const auto vma_iter = src_process->vm_manager.vma_map.find(source_address); - const auto& vma = vma_iter->second; - const VAddr dest_address = vma.originating_buffer_address; + if (IPC::GetDescriptorType(desc) == IPC::DescriptorType::MappedBuffer) { + IPC::MappedBufferDescInfo dest_descInfo{desc}; + VAddr dest_address = dst_cmd_buf[j]; - auto buffer = std::make_shared>(size); - Memory::ReadBlock(*src_process, source_address, buffer->data(), size); - Memory::WriteBlock(*dst_process, dest_address, buffer->data(), size); + u32 dest_size = static_cast(dest_descInfo.size); + IPC::MappedBufferPermissions dest_permissions = dest_descInfo.perms; - ResultCode result = src_process->vm_manager.UnmapRange( - page_start, num_pages * Memory::PAGE_SIZE); - ASSERT(result == RESULT_SUCCESS); + if (permissions == dest_permissions && size == dest_size) { + // Readonly buffers do not need to be copied over to the target + // process again because they were (presumably) not modified. This + // behavior is consistent with the real kernel. + if (permissions != IPC::MappedBufferPermissions::R) { + // Copy the modified buffer back into the target process + Memory::CopyBlock(*src_process, *dst_process, source_address, + dest_address, size); + } + + // Unmap the Reserved page before the buffer + ResultCode result = src_process->vm_manager.UnmapRange( + page_start - Memory::PAGE_SIZE, Memory::PAGE_SIZE); + ASSERT(result == RESULT_SUCCESS); + + // Unmap the buffer from the source process + result = src_process->vm_manager.UnmapRange( + page_start, num_pages * Memory::PAGE_SIZE); + ASSERT(result == RESULT_SUCCESS); + + // Check if this is the last mapped buffer + VAddr next_reserve = page_start + num_pages * Memory::PAGE_SIZE; + auto& vma = + src_process->vm_manager.FindVMA(next_reserve + Memory::PAGE_SIZE) + ->second; + if (vma.type == VMAType::Free) { + // Unmap the Reserved page after the last buffer + result = src_process->vm_manager.UnmapRange(next_reserve, + Memory::PAGE_SIZE); + ASSERT(result == RESULT_SUCCESS); + } + + break; + } + } + + j += 1; } i += 1; @@ -166,63 +204,38 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtr bool { - return (address & Memory::PAGE_MASK) == 0; - }; - // TODO(Subv): Perform permission checks. - // TODO(Subv): Leave a page of unmapped memory before the first page and after the last - // page. + // Reserve a page of memory before the mapped buffer + auto reserve_buffer = std::make_shared>(Memory::PAGE_SIZE); + dst_process->vm_manager.MapMemoryBlockToBase( + Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer, 0, + static_cast(reserve_buffer->size()), Kernel::MemoryState::Reserved); - if (num_pages == 1 && !IsPageAligned(source_address) && - !IsPageAligned(source_address + size)) { - // If the address of the source buffer is not page-aligned or if the buffer doesn't - // fill an entire page, then we have to allocate a page of memory in the target - // process and copy over the data from the input buffer. This allocated buffer will - // be copied back to the source process and deallocated when the server replies to - // the request via ReplyAndReceive. + auto buffer = std::make_shared>(num_pages * Memory::PAGE_SIZE); + Memory::ReadBlock(*src_process, source_address, buffer->data() + page_offset, size); - auto buffer = std::make_shared>(Memory::PAGE_SIZE); - - // Number of bytes until the next page. - std::size_t difference_to_page = - Common::AlignUp(source_address, Memory::PAGE_SIZE) - source_address; - // If the data fits in one page we can just copy the required size instead of the - // entire page. - std::size_t read_size = - num_pages == 1 ? static_cast(size) : difference_to_page; - - Memory::ReadBlock(*src_process, source_address, buffer->data() + page_offset, - read_size); - - // Map the page into the target process' address space. - target_address = - dst_process->vm_manager - .MapMemoryBlockToBase(Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, - buffer, 0, static_cast(buffer->size()), - Kernel::MemoryState::Shared) - .Unwrap(); - } else { - auto buffer = std::make_shared>(num_pages * Memory::PAGE_SIZE); - Memory::ReadBlock(*src_process, source_address, buffer->data() + page_offset, size); - - // Map the pages into the target process' address space. - target_address = - dst_process->vm_manager - .MapMemoryBlockToBase(Memory::IPC_MAPPING_VADDR + Memory::PAGE_SIZE, - Memory::IPC_MAPPING_SIZE - Memory::PAGE_SIZE, buffer, - 0, static_cast(buffer->size()), - Kernel::MemoryState::Shared) - .Unwrap(); - } - // Save the original address we copied the buffer from so that we can copy the modified - // buffer back, if needed - auto vma_iter = dst_process->vm_manager.vma_map.find(target_address + page_offset); - auto& vma = vma_iter->second; - vma.originating_buffer_address = source_address; + // Map the page(s) into the target process' address space. + target_address = dst_process->vm_manager + .MapMemoryBlockToBase( + Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, buffer, 0, + static_cast(buffer->size()), Kernel::MemoryState::Shared) + .Unwrap(); cmd_buf[i++] = target_address + page_offset; + + // Check if this is the last mapped buffer + if (i < command_size) { + u32 next_descriptor = cmd_buf[i]; + if (IPC::GetDescriptorType(next_descriptor) == IPC::DescriptorType::MappedBuffer) { + break; + } + } + + // Reserve a page of memory after the last mapped buffer + dst_process->vm_manager.MapMemoryBlockToBase( + Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer, 0, + static_cast(reserve_buffer->size()), Kernel::MemoryState::Reserved); break; } default: diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index fcb107c06..7ac5c3b01 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -86,9 +86,6 @@ struct VirtualMemoryArea { PAddr paddr = 0; Memory::MMIORegionPointer mmio_handler = nullptr; - /// Originating address of the IPC mapped buffer - VAddr originating_buffer_address = 0; - /// Tests if this area can be merged to the right with `next`. bool CanBeMergedWith(const VirtualMemoryArea& next) const; }; diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 26967ad36..70baef93a 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -700,6 +700,58 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, const std::size_t size) { CopyBlock(*Kernel::g_current_process, dest_addr, src_addr, size); } +void CopyBlock(const Kernel::Process& src_process, const Kernel::Process& dest_process, + VAddr src_addr, VAddr dest_addr, std::size_t size) { + auto& page_table = src_process.vm_manager.page_table; + std::size_t remaining_size = size; + std::size_t page_index = src_addr >> PAGE_BITS; + std::size_t page_offset = src_addr & PAGE_MASK; + + while (remaining_size > 0) { + const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size); + const VAddr current_vaddr = static_cast((page_index << PAGE_BITS) + page_offset); + + switch (page_table.attributes[page_index]) { + case PageType::Unmapped: { + LOG_ERROR(HW_Memory, + "unmapped CopyBlock @ 0x{:08X} (start address = 0x{:08X}, size = {})", + current_vaddr, src_addr, size); + ZeroBlock(dest_process, dest_addr, copy_amount); + break; + } + case PageType::Memory: { + DEBUG_ASSERT(page_table.pointers[page_index]); + const u8* src_ptr = page_table.pointers[page_index] + page_offset; + WriteBlock(dest_process, dest_addr, src_ptr, copy_amount); + break; + } + case PageType::Special: { + MMIORegionPointer handler = GetMMIOHandler(page_table, current_vaddr); + DEBUG_ASSERT(handler); + std::vector buffer(copy_amount); + handler->ReadBlock(current_vaddr, buffer.data(), buffer.size()); + WriteBlock(dest_process, dest_addr, buffer.data(), buffer.size()); + break; + } + case PageType::RasterizerCachedMemory: { + RasterizerFlushVirtualRegion(current_vaddr, static_cast(copy_amount), + FlushMode::Flush); + WriteBlock(dest_process, dest_addr, GetPointerFromVMA(src_process, current_vaddr), + copy_amount); + break; + } + default: + UNREACHABLE(); + } + + page_index++; + page_offset = 0; + dest_addr += static_cast(copy_amount); + src_addr += static_cast(copy_amount); + remaining_size -= copy_amount; + } +} + template <> u8 ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr) { return mmio_handler->Read8(addr); diff --git a/src/core/memory.h b/src/core/memory.h index 73dbe091c..e78754705 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -205,6 +205,8 @@ void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, const std::size_ void ZeroBlock(VAddr dest_addr, const std::size_t size); void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, std::size_t size); void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size); +void CopyBlock(const Kernel::Process& src_process, const Kernel::Process& dest_process, + VAddr src_addr, VAddr dest_addr, std::size_t size); u8* GetPointer(VAddr vaddr); From 32aecd42a2c7b011c7061889fa3343b0efe1862a Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Mon, 1 Oct 2018 21:07:25 -0400 Subject: [PATCH 003/102] LLE Mapped Buffer: Corrected behavior --- src/core/hle/kernel/ipc.cpp | 77 +++++++++++++++---------------------- 1 file changed, 30 insertions(+), 47 deletions(-) diff --git a/src/core/hle/kernel/ipc.cpp b/src/core/hle/kernel/ipc.cpp index 070bb6619..9875fc68a 100644 --- a/src/core/hle/kernel/ipc.cpp +++ b/src/core/hle/kernel/ipc.cpp @@ -39,6 +39,7 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtr dst_cmd_buf; Memory::ReadBlock(*dst_process, dst_address, dst_cmd_buf.data(), @@ -148,54 +149,44 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtr(dest_descInfo.size); IPC::MappedBufferPermissions dest_permissions = dest_descInfo.perms; - if (permissions == dest_permissions && size == dest_size) { - // Readonly buffers do not need to be copied over to the target - // process again because they were (presumably) not modified. This - // behavior is consistent with the real kernel. - if (permissions != IPC::MappedBufferPermissions::R) { - // Copy the modified buffer back into the target process - Memory::CopyBlock(*src_process, *dst_process, source_address, - dest_address, size); - } - - // Unmap the Reserved page before the buffer - ResultCode result = src_process->vm_manager.UnmapRange( - page_start - Memory::PAGE_SIZE, Memory::PAGE_SIZE); - ASSERT(result == RESULT_SUCCESS); - - // Unmap the buffer from the source process - result = src_process->vm_manager.UnmapRange( - page_start, num_pages * Memory::PAGE_SIZE); - ASSERT(result == RESULT_SUCCESS); - - // Check if this is the last mapped buffer - VAddr next_reserve = page_start + num_pages * Memory::PAGE_SIZE; - auto& vma = - src_process->vm_manager.FindVMA(next_reserve + Memory::PAGE_SIZE) - ->second; - if (vma.type == VMAType::Free) { - // Unmap the Reserved page after the last buffer - result = src_process->vm_manager.UnmapRange(next_reserve, - Memory::PAGE_SIZE); - ASSERT(result == RESULT_SUCCESS); - } - - break; + ASSERT(permissions == dest_permissions && size == dest_size); + // Readonly buffers do not need to be copied over to the target + // process again because they were (presumably) not modified. This + // behavior is consistent with the real kernel. + if (permissions != IPC::MappedBufferPermissions::R) { + // Copy the modified buffer back into the target process + Memory::CopyBlock(*src_process, *dst_process, source_address, + dest_address, size); } + + VAddr prev_reserve = page_start - Memory::PAGE_SIZE; + VAddr next_reserve = page_start + num_pages * Memory::PAGE_SIZE; + + auto& prev_vma = src_process->vm_manager.FindVMA(prev_reserve)->second; + auto& next_vma = src_process->vm_manager.FindVMA(next_reserve)->second; + ASSERT(prev_vma.meminfo_state == MemoryState::Reserved && + next_vma.meminfo_state == MemoryState::Reserved); + + // Unmap the buffer and guard pages from the source process + ResultCode result = src_process->vm_manager.UnmapRange( + page_start - Memory::PAGE_SIZE, (num_pages + 2) * Memory::PAGE_SIZE); + ASSERT(result == RESULT_SUCCESS); + + target_index += 1; + break; } - j += 1; + target_index += 1; } i += 1; @@ -224,15 +215,7 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtrvm_manager.MapMemoryBlockToBase( Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer, 0, static_cast(reserve_buffer->size()), Kernel::MemoryState::Reserved); From 25a370ef191572c9eeba44fc2f8b75658dbcc884 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sat, 13 Oct 2018 11:57:21 -0400 Subject: [PATCH 004/102] only redefine 64 bit file operation for MSVC MinGW provides POSIX functions --- src/common/file_util.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 40ea885b8..b2f9b8d7e 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -14,21 +14,24 @@ #ifdef _WIN32 #include // windows.h needs to be included before other windows headers -#include // for GetSaveFileName -#include // getcwd +#include // getcwd #include #include #include // for SHGetFolderPath #include #include "common/string_util.h" -// 64 bit offsets for windows +#ifdef _MSC_VER +// 64 bit offsets for MSVC #define fseeko _fseeki64 #define ftello _ftelli64 -#define atoll _atoi64 +#define fileno _fileno +#endif + +// 64 bit offsets for MSVC and MinGW. MinGW also needs this for using _wstat64 #define stat _stat64 #define fstat _fstat64 -#define fileno _fileno + #else #ifdef __APPLE__ #include From 380b83e9bd50270f76175b718245ab83879ef2b2 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Tue, 16 Oct 2018 13:23:07 -0400 Subject: [PATCH 005/102] cmake: mingw also needs _FILE_OFFSET_BITS=64 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08f6ce2fb..b0078e408 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,7 +170,7 @@ endif() # On modern Unixes, this is typically already the case. The lone exception is # glibc, which may default to 32 bits. glibc allows this to be configured # by setting _FILE_OFFSET_BITS. -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") +if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW) add_definitions(-D_FILE_OFFSET_BITS=64) endif() From 1849e8b09c8d3852b8f9de8151b8206ecb64e859 Mon Sep 17 00:00:00 2001 From: B3n30 Date: Wed, 17 Oct 2018 16:07:11 +0200 Subject: [PATCH 006/102] HW::AES: add generator_constant --- src/core/hw/aes/key.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/core/hw/aes/key.cpp b/src/core/hw/aes/key.cpp index 99e1b7fb5..b69aad977 100644 --- a/src/core/hw/aes/key.cpp +++ b/src/core/hw/aes/key.cpp @@ -19,7 +19,14 @@ namespace AES { namespace { -std::optional generator_constant; +// The generator constant was calculated using the 0x39 KeyX and KeyY retrieved from a 3DS and the +// normal key dumped from a Wii U solving the equation: +// NormalKey = (((KeyX ROL 2) XOR KeyY) + constant) ROL 87 +// On a real 3DS the generation for the normal key is hardware based, and thus the constant can't +// get dumped . generated normal keys are also not accesible on a 3DS. The used formula for +// calculating the constant is a software implementation of what the hardware generator does. +constexpr AESKey generator_constant = {{0x1F, 0xF9, 0xE9, 0xAA, 0xC5, 0xFE, 0x04, 0x08, 0x02, 0x45, + 0x91, 0xDC, 0x5D, 0x52, 0x76, 0x8A}}; struct KeyDesc { char key_type; @@ -48,8 +55,8 @@ struct KeySlot { } void GenerateNormalKey() { - if (x && y && generator_constant) { - normal = Lrot128(Add128(Xor128(Lrot128(*x, 2), *y), *generator_constant), 87); + if (x && y) { + normal = Lrot128(Add128(Xor128(Lrot128(*x, 2), *y), generator_constant), 87); } else { normal = {}; } @@ -181,11 +188,6 @@ void LoadPresetKeys() { continue; } - if (name == "generator") { - generator_constant = key; - continue; - } - std::size_t common_key_index; if (std::sscanf(name.c_str(), "common%zd", &common_key_index) == 1) { if (common_key_index >= common_key_y_slots.size()) { @@ -236,10 +238,6 @@ void InitKeys() { initialized = true; } -void SetGeneratorConstant(const AESKey& key) { - generator_constant = key; -} - void SetKeyX(std::size_t slot_id, const AESKey& key) { key_slots.at(slot_id).SetKeyX(key); } From 15c9db08835cac26e17c3d0657fae400401fff6d Mon Sep 17 00:00:00 2001 From: B3n30 Date: Sun, 14 Oct 2018 00:06:39 +0200 Subject: [PATCH 007/102] Load keys from the o3DS save mode native firm --- src/core/hw/aes/key.cpp | 65 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/src/core/hw/aes/key.cpp b/src/core/hw/aes/key.cpp index b69aad977..eb0518111 100644 --- a/src/core/hw/aes/key.cpp +++ b/src/core/hw/aes/key.cpp @@ -11,6 +11,8 @@ #include "common/file_util.h" #include "common/logging/log.h" #include "common/string_util.h" +#include "core/file_sys/archive_ncch.h" +#include "core/hle/service/fs/archive.h" #include "core/hw/aes/arithmetic128.h" #include "core/hw/aes/key.h" @@ -85,6 +87,14 @@ AESKey HexToKey(const std::string& hex) { return key; } +std::string KeyToString(AESKey& key) { + std::string s; + for (auto pos : key) { + s += fmt::format("{:02X}", pos); + } + return s; +} + void LoadBootromKeys() { constexpr std::array keys = { {{'X', 0x2C, false}, {'X', 0x2D, true}, {'X', 0x2E, true}, {'X', 0x2F, true}, @@ -137,11 +147,8 @@ void LoadBootromKeys() { } } - std::string s; - for (auto pos : new_key) { - s += fmt::format("{:02X}", pos); - } - LOG_DEBUG(HW_AES, "Loaded Slot{:#02x} Key{}: {}", key.slot_id, key.key_type, s); + LOG_DEBUG(HW_AES, "Loaded Slot{:#02x} Key{}: {}", key.slot_id, key.key_type, + KeyToString(new_key)); switch (key.key_type) { case 'X': @@ -160,6 +167,52 @@ void LoadBootromKeys() { } } +void LoadNativeFirmKeysOld3DS() { + // Use the save mode native firm instead of the normal mode since there are only 2 version of it + // and thus we can use fixed offsets + constexpr u64_le save_mode_native_firm_id_low = 0x0004013800000003; + + FileSys::NCCHArchive archive(save_mode_native_firm_id_low, Service::FS::MediaType::NAND); + std::array exefs_filepath = {'.', 'f', 'i', 'r', 'm', 0, 0, 0}; + FileSys::Path file_path = FileSys::MakeNCCHFilePath( + FileSys::NCCHFileOpenType::NCCHData, 0, FileSys::NCCHFilePathType::ExeFS, exefs_filepath); + FileSys::Mode open_mode = {}; + open_mode.read_flag.Assign(1); + auto file_result = archive.OpenFile(file_path, open_mode); + if (file_result.Failed()) + return; + + auto firm = std::move(file_result).Unwrap(); + const std::size_t size = firm->GetSize(); + if (size != 843776) { + LOG_ERROR(HW_AES, "save mode native firm has wrong size {}", size); + return; + } + std::vector firm_buffer(size); + firm->Read(0, firm_buffer.size(), firm_buffer.data()); + firm->Close(); + + AESKey key; + constexpr std::size_t SLOT_0x31_KEY_Y_OFFSET = 817672; + std::memcpy(key.data(), firm_buffer.data() + SLOT_0x31_KEY_Y_OFFSET, sizeof(key)); + key_slots.at(0x31).SetKeyY(key); + LOG_DEBUG(HW_AES, "Loaded Slot0x31 KeyY: {}", KeyToString(key)); + + auto LoadCommonKey = [&firm_buffer](std::size_t key_slot) -> AESKey { + constexpr std::size_t START_OFFSET = 836533; + constexpr std::size_t OFFSET = 0x14; // 0x10 bytes for key + 4 bytes between keys + AESKey key; + std::memcpy(key.data(), firm_buffer.data() + START_OFFSET + OFFSET * key_slot, sizeof(key)); + return key; + }; + + for (std::size_t key_slot{0}; key_slot < 6; ++key_slot) { + AESKey key = LoadCommonKey(key_slot); + common_key_y_slots[key_slot] = key; + LOG_DEBUG(HW_AES, "Loaded common key{}: {}", key_slot, KeyToString(key)); + } +} + void LoadPresetKeys() { const std::string filepath = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir) + AES_KEYS; FileUtil::CreateFullPath(filepath); // Create path if not already created @@ -234,6 +287,8 @@ void InitKeys() { if (initialized) return; LoadBootromKeys(); + LoadNativeFirmKeysOld3DS(); + // TODO(B3N30): Load new_3ds save_native_firm LoadPresetKeys(); initialized = true; } From be3bd18c4252a55af703b77f771e88fb5eb967cb Mon Sep 17 00:00:00 2001 From: B3n30 Date: Wed, 17 Oct 2018 13:21:02 +0200 Subject: [PATCH 008/102] Load keys from new3DS native firm --- src/common/common_paths.h | 1 + src/core/hw/aes/key.cpp | 180 +++++++++++++++++++++++++++++++++++--- 2 files changed, 170 insertions(+), 11 deletions(-) diff --git a/src/common/common_paths.h b/src/common/common_paths.h index 1db4d7c3d..80aa4b5a0 100644 --- a/src/common/common_paths.h +++ b/src/common/common_paths.h @@ -51,3 +51,4 @@ #define SHARED_FONT "shared_font.bin" #define AES_KEYS "aes_keys.txt" #define BOOTROM9 "boot9.bin" +#define SECRET_SECTOR "sector0x96.bin" diff --git a/src/core/hw/aes/key.cpp b/src/core/hw/aes/key.cpp index eb0518111..0a1ab6eee 100644 --- a/src/core/hw/aes/key.cpp +++ b/src/core/hw/aes/key.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include "common/common_paths.h" #include "common/file_util.h" @@ -37,6 +39,19 @@ struct KeyDesc { bool same_as_before; }; +AESKey HexToKey(const std::string& hex) { + if (hex.size() < 32) { + throw std::invalid_argument("hex string is too short"); + } + + AESKey key; + for (std::size_t i = 0; i < key.size(); ++i) { + key[i] = static_cast(std::stoi(hex.substr(i * 2, 2), 0, 16)); + } + + return key; +} + struct KeySlot { std::optional x; std::optional y; @@ -74,18 +89,39 @@ struct KeySlot { std::array key_slots; std::array, 6> common_key_y_slots; -AESKey HexToKey(const std::string& hex) { - if (hex.size() < 32) { - throw std::invalid_argument("hex string is too short"); - } +enum class FirmwareType : u32 { + ARM9 = 0, // uses NDMA + ARM11 = 1, // uses XDMA +}; - AESKey key; - for (std::size_t i = 0; i < key.size(); ++i) { - key[i] = static_cast(std::stoi(hex.substr(i * 2, 2), 0, 16)); - } +struct FirmwareSectionHeader { + u32_le offset; + u32_le phys_address; + u32_le size; + enum_le firmware_type; + std::array hash; // SHA-256 hash +}; - return key; -} +struct FIRM_Header { + u32_le magic; // FIRM + u32_le boot_priority; // Usually 0 + u32_le arm11_entrypoint; + u32_le arm9_entrypoint; + INSERT_PADDING_BYTES(0x30); // Reserved + std::array section_headers; // 1st ARM11?, 3rd ARM9 + std::array signature; // RSA-2048 signature of the FIRM header's hash +}; + +struct ARM9_HEADER { + AESKey enc_key_x; + AESKey key_y; + AESKey CTR; + std::array size; // in ASCII + INSERT_PADDING_BYTES(8); // Unknown + std::array control_block; + std::array hardware_debug_info; + std::array enc_key_x_slot_16; +}; std::string KeyToString(AESKey& key) { std::string s; @@ -170,8 +206,11 @@ void LoadBootromKeys() { void LoadNativeFirmKeysOld3DS() { // Use the save mode native firm instead of the normal mode since there are only 2 version of it // and thus we can use fixed offsets + constexpr u64_le save_mode_native_firm_id_low = 0x0004013800000003; + // TODO(B3N30): Add the 0x25 KeyX that gets initalized by native_firm + FileSys::NCCHArchive archive(save_mode_native_firm_id_low, Service::FS::MediaType::NAND); std::array exefs_filepath = {'.', 'f', 'i', 'r', 'm', 0, 0, 0}; FileSys::Path file_path = FileSys::MakeNCCHFilePath( @@ -213,6 +252,125 @@ void LoadNativeFirmKeysOld3DS() { } } +void LoadNativeFirmKeysNew3DS() { + // The first 0x10 bytes of the secret_sector are used as a key to decrypt a KeyX from the + // native_firm + const std::string filepath = + FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir) + SECRET_SECTOR; + auto secret = FileUtil::IOFile(filepath, "rb"); + if (!secret) { + return; + } + ASSERT(secret.GetSize() > 0x10); + + AESKey secret_key; + secret.ReadArray(secret_key.data(), secret_key.size()); + + // Use the save mode native firm instead of the normal mode since there are only 1 version of it + // and thus we can use fixed offsets + constexpr u64_le save_mode_native_firm_id_low = 0x0004013820000003; + + // TODO(B3N30): Add the 0x25 KeyX that gets initalized by native_firm + + // TODO(B3N30): Add the 0x18 - 0x1F KeyX that gets initalized by native_firm. This probably + // requires the normal native firm with version > 9.6.0-X + + FileSys::NCCHArchive archive(save_mode_native_firm_id_low, Service::FS::MediaType::NAND); + std::array exefs_filepath = {'.', 'f', 'i', 'r', 'm', 0, 0, 0}; + FileSys::Path file_path = FileSys::MakeNCCHFilePath( + FileSys::NCCHFileOpenType::NCCHData, 0, FileSys::NCCHFilePathType::ExeFS, exefs_filepath); + FileSys::Mode open_mode = {}; + open_mode.read_flag.Assign(1); + auto file_result = archive.OpenFile(file_path, open_mode); + if (file_result.Failed()) + return; + + auto firm = std::move(file_result).Unwrap(); + std::vector firm_buffer(firm->GetSize()); + firm->Read(0, firm_buffer.size(), firm_buffer.data()); + firm->Close(); + + FIRM_Header header; + std::memcpy(&header, firm_buffer.data(), sizeof(header)); + + auto MakeMagic = [](char a, char b, char c, char d) -> u32 { + return a | b << 8 | c << 16 | d << 24; + }; + if (MakeMagic('F', 'I', 'R', 'M') != header.magic) { + LOG_ERROR(HW_AES, "N3DS SAVE MODE Native Firm has wrong header {}", header.magic); + return; + } + + u32 arm9_offset(0); + u32 arm9_size(0); + for (auto section_header : header.section_headers) { + if (section_header.firmware_type == FirmwareType::ARM9) { + arm9_offset = section_header.offset; + arm9_size = section_header.size; + break; + } + } + + if (arm9_offset != 0x66800) { + LOG_ERROR(HW_AES, "ARM9 binary at wrong offset: {}", arm9_offset); + return; + } + if (arm9_size != 0x8BA00) { + LOG_ERROR(HW_AES, "ARM9 binary has wrong size: {}", arm9_size); + return; + } + + ARM9_HEADER arm9_header; + std::memcpy(&arm9_header, firm_buffer.data() + arm9_offset, sizeof(arm9_header)); + + AESKey keyX_slot0x15; + CryptoPP::ECB_Mode::Decryption d; + d.SetKey(secret_key.data(), secret_key.size()); + d.ProcessData(keyX_slot0x15.data(), arm9_header.enc_key_x.data(), arm9_header.enc_key_x.size()); + + key_slots.at(0x15).SetKeyX(keyX_slot0x15); + key_slots.at(0x15).SetKeyY(arm9_header.key_y); + auto normal_key_slot0x15 = key_slots.at(0x15).normal; + if (!normal_key_slot0x15) { + LOG_ERROR(HW_AES, "Failed to get normal key for slot id 0x15"); + return; + } + + constexpr u32 ARM9_BINARY_OFFSET = 0x800; // From the beginning of the ARM9 section + std::vector enc_arm9_binary; + enc_arm9_binary.resize(arm9_size - ARM9_BINARY_OFFSET); + ASSERT(enc_arm9_binary.size() + arm9_offset + ARM9_BINARY_OFFSET < firm_buffer.size()); + std::memcpy(enc_arm9_binary.data(), firm_buffer.data() + arm9_offset + ARM9_BINARY_OFFSET, + enc_arm9_binary.size()); + + std::vector arm9_binary; + arm9_binary.resize(enc_arm9_binary.size()); + CryptoPP::CTR_Mode::Decryption d2; + d2.SetKeyWithIV(normal_key_slot0x15->data(), normal_key_slot0x15->size(), + arm9_header.CTR.data(), arm9_header.CTR.size()); + d2.ProcessData(arm9_binary.data(), enc_arm9_binary.data(), enc_arm9_binary.size()); + + AESKey key; + constexpr std::size_t SLOT_0x31_KEY_Y_OFFSET = 517368; + std::memcpy(key.data(), arm9_binary.data() + SLOT_0x31_KEY_Y_OFFSET, sizeof(key)); + key_slots.at(0x31).SetKeyY(key); + LOG_DEBUG(HW_AES, "Loaded Slot0x31 KeyY: {}", KeyToString(key)); + + auto LoadCommonKey = [&arm9_binary](std::size_t key_slot) -> AESKey { + constexpr std::size_t START_OFFSET = 541065; + constexpr std::size_t OFFSET = 0x14; // 0x10 bytes for key + 4 bytes between keys + AESKey key; + std::memcpy(key.data(), arm9_binary.data() + START_OFFSET + OFFSET * key_slot, sizeof(key)); + return key; + }; + + for (std::size_t key_slot{0}; key_slot < 6; ++key_slot) { + AESKey key = LoadCommonKey(key_slot); + common_key_y_slots[key_slot] = key; + LOG_DEBUG(HW_AES, "Loaded common key{}: {}", key_slot, KeyToString(key)); + } +} + void LoadPresetKeys() { const std::string filepath = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir) + AES_KEYS; FileUtil::CreateFullPath(filepath); // Create path if not already created @@ -288,7 +446,7 @@ void InitKeys() { return; LoadBootromKeys(); LoadNativeFirmKeysOld3DS(); - // TODO(B3N30): Load new_3ds save_native_firm + LoadNativeFirmKeysNew3DS(); LoadPresetKeys(); initialized = true; } From ad232efbf07c5819019da2b1ba388db1d7f64a80 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Wed, 17 Oct 2018 18:03:27 +0200 Subject: [PATCH 009/102] apply fixes --- src/core/hw/aes/key.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core/hw/aes/key.cpp b/src/core/hw/aes/key.cpp index 0a1ab6eee..7f034f9a3 100644 --- a/src/core/hw/aes/key.cpp +++ b/src/core/hw/aes/key.cpp @@ -112,7 +112,7 @@ struct FIRM_Header { std::array signature; // RSA-2048 signature of the FIRM header's hash }; -struct ARM9_HEADER { +struct ARM9_Header { AESKey enc_key_x; AESKey key_y; AESKey CTR; @@ -207,11 +207,11 @@ void LoadNativeFirmKeysOld3DS() { // Use the save mode native firm instead of the normal mode since there are only 2 version of it // and thus we can use fixed offsets - constexpr u64_le save_mode_native_firm_id_low = 0x0004013800000003; + constexpr u64 save_mode_native_firm_id = 0x00040138'00000003; // TODO(B3N30): Add the 0x25 KeyX that gets initalized by native_firm - FileSys::NCCHArchive archive(save_mode_native_firm_id_low, Service::FS::MediaType::NAND); + FileSys::NCCHArchive archive(save_mode_native_firm_id, Service::FS::MediaType::NAND); std::array exefs_filepath = {'.', 'f', 'i', 'r', 'm', 0, 0, 0}; FileSys::Path file_path = FileSys::MakeNCCHFilePath( FileSys::NCCHFileOpenType::NCCHData, 0, FileSys::NCCHFilePathType::ExeFS, exefs_filepath); @@ -268,14 +268,14 @@ void LoadNativeFirmKeysNew3DS() { // Use the save mode native firm instead of the normal mode since there are only 1 version of it // and thus we can use fixed offsets - constexpr u64_le save_mode_native_firm_id_low = 0x0004013820000003; + constexpr u64 save_mode_native_firm_id = 0x00040138'20000003; // TODO(B3N30): Add the 0x25 KeyX that gets initalized by native_firm // TODO(B3N30): Add the 0x18 - 0x1F KeyX that gets initalized by native_firm. This probably // requires the normal native firm with version > 9.6.0-X - FileSys::NCCHArchive archive(save_mode_native_firm_id_low, Service::FS::MediaType::NAND); + FileSys::NCCHArchive archive(save_mode_native_firm_id, Service::FS::MediaType::NAND); std::array exefs_filepath = {'.', 'f', 'i', 'r', 'm', 0, 0, 0}; FileSys::Path file_path = FileSys::MakeNCCHFilePath( FileSys::NCCHFileOpenType::NCCHData, 0, FileSys::NCCHFilePathType::ExeFS, exefs_filepath); @@ -320,7 +320,7 @@ void LoadNativeFirmKeysNew3DS() { return; } - ARM9_HEADER arm9_header; + ARM9_Header arm9_header; std::memcpy(&arm9_header, firm_buffer.data() + arm9_offset, sizeof(arm9_header)); AESKey keyX_slot0x15; From f446fd1fe51edbbd76d9e4ec84b5e11682f47d88 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 11 Oct 2018 14:49:52 -0400 Subject: [PATCH 010/102] Kernel: add KernelSystem class --- src/core/core.cpp | 12 ++++++++++-- src/core/core.h | 12 ++++++++++++ src/core/hle/kernel/kernel.cpp | 4 ++-- src/core/hle/kernel/kernel.h | 10 +++++----- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 4f7a5e908..d5445b438 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -196,7 +196,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { archive_manager = std::make_unique(); HW::Init(); - Kernel::Init(system_mode); + kernel = std::make_unique(system_mode); Service::Init(*this, service_manager); GDBStub::Init(); @@ -230,6 +230,14 @@ const Service::FS::ArchiveManager& System::ArchiveManager() const { return *archive_manager; } +Kernel::KernelSystem& System::Kernel() { + return *kernel; +} + +const Kernel::KernelSystem& System::Kernel() const { + return *kernel; +} + void System::RegisterSoftwareKeyboard(std::shared_ptr swkbd) { registered_swkbd = std::move(swkbd); } @@ -248,7 +256,7 @@ void System::Shutdown() { GDBStub::Shutdown(); VideoCore::Shutdown(); Service::Shutdown(); - Kernel::Shutdown(); + kernel.reset(); HW::Shutdown(); telemetry_session.reset(); #ifdef ENABLE_SCRIPTING diff --git a/src/core/core.h b/src/core/core.h index cecd29896..9341f79a4 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -36,6 +36,10 @@ class ArchiveManager; } } // namespace Service +namespace Kernel { +class KernelSystem; +} + namespace Core { class System { @@ -167,6 +171,12 @@ public: /// Gets a const reference to the archive manager const Service::FS::ArchiveManager& ArchiveManager() const; + /// Gets a reference to the kernel + Kernel::KernelSystem& Kernel(); + + /// Gets a const reference to the kernel + const Kernel::KernelSystem& Kernel() const; + PerfStats perf_stats; FrameLimiter frame_limiter; @@ -241,6 +251,8 @@ private: std::unique_ptr archive_manager; + std::unique_ptr kernel; + static System s_instance; ResultStatus status = ResultStatus::Success; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index d494914e3..7991f77cf 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -17,7 +17,7 @@ namespace Kernel { std::atomic Object::next_object_id{0}; /// Initialize the kernel -void Init(u32 system_mode) { +KernelSystem::KernelSystem(u32 system_mode) { ConfigMem::Init(); Kernel::MemoryInit(system_mode); @@ -33,7 +33,7 @@ void Init(u32 system_mode) { } /// Shutdown the kernel -void Shutdown() { +KernelSystem::~KernelSystem() { g_handle_table.Clear(); // Free all kernel objects Kernel::ThreadingShutdown(); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 2bc45d7db..c19cdc92d 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -8,10 +8,10 @@ namespace Kernel { -/// Initialize the kernel with the specified system mode. -void Init(u32 system_mode); - -/// Shutdown the kernel -void Shutdown(); +class KernelSystem { +public: + explicit KernelSystem(u32 system_mode); + ~KernelSystem(); +}; } // namespace Kernel From 734be98966d07645811f216a6df34ceeb9457edf Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 11 Oct 2018 15:19:45 -0400 Subject: [PATCH 011/102] Kernel: pass Kernel reference into AddressArbiter --- src/core/hle/kernel/address_arbiter.cpp | 7 ++++--- src/core/hle/kernel/address_arbiter.h | 12 +++--------- src/core/hle/kernel/kernel.h | 15 +++++++++++++++ src/core/hle/kernel/object.h | 7 +------ src/core/hle/kernel/svc.cpp | 2 +- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 1dc005554..ad2805cbf 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -7,6 +7,7 @@ #include "common/logging/log.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/errors.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" #include "core/memory.h" @@ -64,11 +65,11 @@ SharedPtr AddressArbiter::ResumeHighestPriorityThread(VAddr address) { return thread; } -AddressArbiter::AddressArbiter() {} +AddressArbiter::AddressArbiter(KernelSystem& kernel) {} AddressArbiter::~AddressArbiter() {} -SharedPtr AddressArbiter::Create(std::string name) { - SharedPtr address_arbiter(new AddressArbiter); +SharedPtr KernelSystem::CreateAddressArbiter(std::string name) { + SharedPtr address_arbiter(new AddressArbiter(*this)); address_arbiter->name = std::move(name); diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index cf2761819..cdfa64ec2 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -31,14 +31,6 @@ enum class ArbitrationType : u32 { class AddressArbiter final : public Object { public: - /** - * Creates an address arbiter. - * - * @param name Optional name used for debugging. - * @returns The created AddressArbiter. - */ - static SharedPtr Create(std::string name = "Unknown"); - std::string GetTypeName() const override { return "Arbiter"; } @@ -57,7 +49,7 @@ public: s32 value, u64 nanoseconds); private: - AddressArbiter(); + explicit AddressArbiter(KernelSystem& kernel); ~AddressArbiter() override; /// Puts the thread to wait on the specified arbitration address under this address arbiter. @@ -72,6 +64,8 @@ private: /// Threads waiting for the address arbiter to be signaled. std::vector> waiting_threads; + + friend class KernelSystem; }; } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index c19cdc92d..12a5a8cef 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -4,14 +4,29 @@ #pragma once +#include +#include #include "common/common_types.h" namespace Kernel { +class AddressArbiter; + +template +using SharedPtr = boost::intrusive_ptr; + class KernelSystem { public: explicit KernelSystem(u32 system_mode); ~KernelSystem(); + + /** + * Creates an address arbiter. + * + * @param name Optional name used for debugging. + * @returns The created AddressArbiter. + */ + SharedPtr CreateAddressArbiter(std::string name = "Unknown"); }; } // namespace Kernel diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index fbacf9359..6bc6fe00d 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -6,10 +6,8 @@ #include #include - -#include - #include "common/common_types.h" +#include "core/hle/kernel/kernel.h" namespace Kernel { @@ -88,9 +86,6 @@ inline void intrusive_ptr_release(Object* object) { } } -template -using SharedPtr = boost::intrusive_ptr; - /** * Attempts to downcast the given Object pointer to a pointer to T. * @return Derived pointer to the object, or `nullptr` if `object` isn't of type T. diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index a5889d6c8..dcfca5c53 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -615,7 +615,7 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ /// Create an address arbiter (to allocate access to shared resources) static ResultCode CreateAddressArbiter(Handle* out_handle) { - SharedPtr arbiter = AddressArbiter::Create(); + SharedPtr arbiter = Core::System::GetInstance().Kernel().CreateAddressArbiter(); CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(arbiter))); LOG_TRACE(Kernel_SVC, "returned handle=0x{:08X}", *out_handle); return RESULT_SUCCESS; From eec11a94cb9997210f34b762985b62c81112e03f Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 11 Oct 2018 15:48:16 -0400 Subject: [PATCH 012/102] Kernel: pass Kernel ref in Event --- src/core/hle/kernel/event.cpp | 8 ++++---- src/core/hle/kernel/event.h | 11 +++-------- src/core/hle/kernel/hle_ipc.cpp | 4 +++- src/core/hle/kernel/kernel.h | 14 ++++++++++++++ src/core/hle/kernel/object.h | 6 ------ src/core/hle/kernel/svc.cpp | 4 ++-- src/core/hle/service/apt/applet_manager.cpp | 4 ++-- src/core/hle/service/boss/boss.cpp | 7 ++++--- src/core/hle/service/boss/boss.h | 2 +- src/core/hle/service/cam/cam.cpp | 11 ++++++----- src/core/hle/service/cam/cam.h | 2 +- src/core/hle/service/cecd/cecd.cpp | 9 +++++---- src/core/hle/service/cecd/cecd.h | 2 +- src/core/hle/service/dsp/dsp_dsp.cpp | 7 ++++--- src/core/hle/service/dsp/dsp_dsp.h | 2 +- src/core/hle/service/hid/hid.cpp | 10 +++++----- src/core/hle/service/ir/ir.cpp | 4 ++-- src/core/hle/service/ir/ir_rst.cpp | 5 +++-- src/core/hle/service/ir/ir_rst.h | 2 +- src/core/hle/service/ir/ir_user.cpp | 9 +++++---- src/core/hle/service/ir/ir_user.h | 2 +- src/core/hle/service/mic_u.cpp | 13 +++++++++---- src/core/hle/service/mic_u.h | 2 +- src/core/hle/service/nfc/nfc.cpp | 8 ++++---- src/core/hle/service/nfc/nfc.h | 2 +- src/core/hle/service/nim/nim.cpp | 2 +- src/core/hle/service/nim/nim_u.cpp | 5 +++-- src/core/hle/service/nim/nim_u.h | 6 +++++- src/core/hle/service/nwm/nwm_uds.cpp | 8 ++++---- src/core/hle/service/nwm/nwm_uds.h | 2 ++ src/core/hle/service/y2r_u.cpp | 6 +++--- src/core/hle/service/y2r_u.h | 2 +- src/tests/core/hle/kernel/hle_ipc.cpp | 3 ++- 33 files changed, 104 insertions(+), 80 deletions(-) diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 6c93719e3..d2acee21b 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -7,16 +7,16 @@ #include #include "common/assert.h" #include "core/hle/kernel/event.h" -#include "core/hle/kernel/object.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" namespace Kernel { -Event::Event() {} +Event::Event(KernelSystem& kernel) {} Event::~Event() {} -SharedPtr Event::Create(ResetType reset_type, std::string name) { - SharedPtr evt(new Event); +SharedPtr KernelSystem::CreateEvent(ResetType reset_type, std::string name) { + SharedPtr evt(new Event(*this)); evt->signaled = false; evt->reset_type = reset_type; diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index 53679810e..09c21587d 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h @@ -12,13 +12,6 @@ namespace Kernel { class Event final : public WaitObject { public: - /** - * Creates an event - * @param reset_type ResetType describing how to create event - * @param name Optional name of event - */ - static SharedPtr Create(ResetType reset_type, std::string name = "Unknown"); - std::string GetTypeName() const override { return "Event"; } @@ -47,13 +40,15 @@ public: void Clear(); private: - Event(); + explicit Event(KernelSystem& kernel); ~Event() override; ResetType reset_type; ///< Current ResetType bool signaled; ///< Whether the event has already been signaled std::string name; ///< Name of event (optional) + + friend class KernelSystem; }; } // namespace Kernel diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index cb63fe5e3..1da7c8a81 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -6,6 +6,7 @@ #include #include "common/assert.h" #include "common/common_types.h" +#include "core/core.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" @@ -55,7 +56,8 @@ SharedPtr HLERequestContext::SleepClientThread(SharedPtr thread, cmd_buff.size() * sizeof(u32)); }; - auto event = Kernel::Event::Create(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason); + auto event = Core::System::GetInstance().Kernel().CreateEvent(Kernel::ResetType::OneShot, + "HLE Pause Event: " + reason); thread->status = ThreadStatus::WaitHleEvent; thread->wait_objects = {event}; event->AddWaitingThread(thread); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 12a5a8cef..94e2b60f6 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -11,6 +11,13 @@ namespace Kernel { class AddressArbiter; +class Event; + +enum class ResetType { + OneShot, + Sticky, + Pulse, +}; template using SharedPtr = boost::intrusive_ptr; @@ -27,6 +34,13 @@ public: * @returns The created AddressArbiter. */ SharedPtr CreateAddressArbiter(std::string name = "Unknown"); + + /** + * Creates an event + * @param reset_type ResetType describing how to create event + * @param name Optional name of event + */ + SharedPtr CreateEvent(ResetType reset_type, std::string name = "Unknown"); }; } // namespace Kernel diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index 6bc6fe00d..6d05a30ea 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -35,12 +35,6 @@ enum { DEFAULT_STACK_SIZE = 0x4000, }; -enum class ResetType { - OneShot, - Sticky, - Pulse, -}; - class Object : NonCopyable { public: virtual ~Object(); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index dcfca5c53..2c81b75fd 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -942,8 +942,8 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32 /// Create an event static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { - SharedPtr evt = Event::Create(static_cast(reset_type), - fmt::format("event-{:08x}", Core::CPU().GetReg(14))); + SharedPtr evt = Core::System::GetInstance().Kernel().CreateEvent( + static_cast(reset_type), fmt::format("event-{:08x}", Core::CPU().GetReg(14))); CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(evt))); LOG_TRACE(Kernel_SVC, "called reset_type=0x{:08X} : created handle=0x{:08X}", reset_type, diff --git a/src/core/hle/service/apt/applet_manager.cpp b/src/core/hle/service/apt/applet_manager.cpp index 1abf1e521..bc02c5eb6 100644 --- a/src/core/hle/service/apt/applet_manager.cpp +++ b/src/core/hle/service/apt/applet_manager.cpp @@ -572,9 +572,9 @@ AppletManager::AppletManager(Core::System& system) : system(system) { slot_data.registered = false; slot_data.loaded = false; slot_data.notification_event = - Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Notification"); + system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "APT:Notification"); slot_data.parameter_event = - Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Parameter"); + system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "APT:Parameter"); } HLE::Applets::Init(); } diff --git a/src/core/hle/service/boss/boss.cpp b/src/core/hle/service/boss/boss.cpp index 8dd21ab3b..63df57427 100644 --- a/src/core/hle/service/boss/boss.cpp +++ b/src/core/hle/service/boss/boss.cpp @@ -903,15 +903,16 @@ void Module::Interface::GetNsDataNewFlagPrivileged(Kernel::HLERequestContext& ct Module::Interface::Interface(std::shared_ptr boss, const char* name, u32 max_session) : ServiceFramework(name, max_session), boss(std::move(boss)) {} -Module::Module() { +Module::Module(Core::System& system) { using namespace Kernel; // TODO: verify ResetType - task_finish_event = Event::Create(Kernel::ResetType::OneShot, "BOSS::task_finish_event"); + task_finish_event = + system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "BOSS::task_finish_event"); } void InstallInterfaces(Core::System& system) { auto& service_manager = system.ServiceManager(); - auto boss = std::make_shared(); + auto boss = std::make_shared(system); std::make_shared(boss)->InstallAsService(service_manager); std::make_shared(boss)->InstallAsService(service_manager); } diff --git a/src/core/hle/service/boss/boss.h b/src/core/hle/service/boss/boss.h index 222f88066..15a41746e 100644 --- a/src/core/hle/service/boss/boss.h +++ b/src/core/hle/service/boss/boss.h @@ -15,7 +15,7 @@ namespace Service::BOSS { class Module final { public: - Module(); + explicit Module(Core::System& system); ~Module() = default; class Interface : public ServiceFramework { diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp index 99dad6980..21ae00f49 100644 --- a/src/core/hle/service/cam/cam.cpp +++ b/src/core/hle/service/cam/cam.cpp @@ -1019,14 +1019,15 @@ void Module::Interface::DriverFinalize(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_CAM, "called"); } -Module::Module() { +Module::Module(Core::System& system) { using namespace Kernel; for (PortConfig& port : ports) { - port.completion_event = Event::Create(ResetType::Sticky, "CAM::completion_event"); + port.completion_event = + system.Kernel().CreateEvent(ResetType::Sticky, "CAM::completion_event"); port.buffer_error_interrupt_event = - Event::Create(ResetType::OneShot, "CAM::buffer_error_interrupt_event"); + system.Kernel().CreateEvent(ResetType::OneShot, "CAM::buffer_error_interrupt_event"); port.vsync_interrupt_event = - Event::Create(ResetType::OneShot, "CAM::vsync_interrupt_event"); + system.Kernel().CreateEvent(ResetType::OneShot, "CAM::vsync_interrupt_event"); } completion_event_callback = CoreTiming::RegisterEvent( "CAM::CompletionEventCallBack", @@ -1061,7 +1062,7 @@ std::shared_ptr GetModule(Core::System& system) { void InstallInterfaces(Core::System& system) { auto& service_manager = system.ServiceManager(); - auto cam = std::make_shared(); + auto cam = std::make_shared(system); std::make_shared(cam)->InstallAsService(service_manager); std::make_shared(cam)->InstallAsService(service_manager); diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h index 401a2a203..4f608fc8e 100644 --- a/src/core/hle/service/cam/cam.h +++ b/src/core/hle/service/cam/cam.h @@ -241,7 +241,7 @@ static_assert(sizeof(PackageParameterWithContextDetail) == 28, class Module final { public: - Module(); + explicit Module(Core::System& system); ~Module(); void ReloadCameraDevices(); diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index 451a5ce84..f2759e7fc 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -1351,10 +1351,11 @@ Module::SessionData::~SessionData() { Module::Interface::Interface(std::shared_ptr cecd, const char* name, u32 max_session) : ServiceFramework(name, max_session), cecd(std::move(cecd)) {} -Module::Module() { +Module::Module(Core::System& system) { using namespace Kernel; - cecinfo_event = Event::Create(Kernel::ResetType::OneShot, "CECD::cecinfo_event"); - change_state_event = Event::Create(Kernel::ResetType::OneShot, "CECD::change_state_event"); + cecinfo_event = system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "CECD::cecinfo_event"); + change_state_event = + system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "CECD::change_state_event"); std::string nand_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); FileSys::ArchiveFactory_SystemSaveData systemsavedata_factory(nand_directory); @@ -1433,7 +1434,7 @@ Module::~Module() = default; void InstallInterfaces(Core::System& system) { auto& service_manager = system.ServiceManager(); - auto cecd = std::make_shared(); + auto cecd = std::make_shared(system); std::make_shared(cecd)->InstallAsService(service_manager); std::make_shared(cecd)->InstallAsService(service_manager); std::make_shared(cecd)->InstallAsService(service_manager); diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index 929f0f397..3102bc318 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -23,7 +23,7 @@ namespace Service::CECD { class Module final { public: - Module(); + explicit Module(Core::System& system); ~Module(); enum class CecCommand : u32 { diff --git a/src/core/hle/service/dsp/dsp_dsp.cpp b/src/core/hle/service/dsp/dsp_dsp.cpp index fa1ddd4c9..b15e670d3 100644 --- a/src/core/hle/service/dsp/dsp_dsp.cpp +++ b/src/core/hle/service/dsp/dsp_dsp.cpp @@ -350,7 +350,7 @@ bool DSP_DSP::HasTooManyEventsRegistered() const { return number >= max_number_of_interrupt_events; } -DSP_DSP::DSP_DSP() : ServiceFramework("dsp::DSP", DefaultMaxSessions) { +DSP_DSP::DSP_DSP(Core::System& system) : ServiceFramework("dsp::DSP", DefaultMaxSessions) { static const FunctionInfo functions[] = { // clang-format off {0x00010040, &DSP_DSP::RecvData, "RecvData"}, @@ -391,7 +391,8 @@ DSP_DSP::DSP_DSP() : ServiceFramework("dsp::DSP", DefaultMaxSessions) { RegisterHandlers(functions); - semaphore_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "DSP_DSP::semaphore_event"); + semaphore_event = + system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "DSP_DSP::semaphore_event"); } DSP_DSP::~DSP_DSP() { @@ -401,7 +402,7 @@ DSP_DSP::~DSP_DSP() { void InstallInterfaces(Core::System& system) { auto& service_manager = system.ServiceManager(); - auto dsp = std::make_shared(); + auto dsp = std::make_shared(system); dsp->InstallAsService(service_manager); Core::DSP().SetServiceToInterrupt(std::move(dsp)); } diff --git a/src/core/hle/service/dsp/dsp_dsp.h b/src/core/hle/service/dsp/dsp_dsp.h index 506a1f9f4..7226aeeac 100644 --- a/src/core/hle/service/dsp/dsp_dsp.h +++ b/src/core/hle/service/dsp/dsp_dsp.h @@ -17,7 +17,7 @@ namespace Service::DSP { class DSP_DSP final : public ServiceFramework { public: - DSP_DSP(); + explicit DSP_DSP(Core::System& system); ~DSP_DSP(); /// There are three types of interrupts diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index b9876012e..322a0b193 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -364,11 +364,11 @@ Module::Module(Core::System& system) : system(system) { 0, MemoryRegion::BASE, "HID:SharedMemory"); // Create event handles - event_pad_or_touch_1 = Event::Create(ResetType::OneShot, "HID:EventPadOrTouch1"); - event_pad_or_touch_2 = Event::Create(ResetType::OneShot, "HID:EventPadOrTouch2"); - event_accelerometer = Event::Create(ResetType::OneShot, "HID:EventAccelerometer"); - event_gyroscope = Event::Create(ResetType::OneShot, "HID:EventGyroscope"); - event_debug_pad = Event::Create(ResetType::OneShot, "HID:EventDebugPad"); + event_pad_or_touch_1 = system.Kernel().CreateEvent(ResetType::OneShot, "HID:EventPadOrTouch1"); + event_pad_or_touch_2 = system.Kernel().CreateEvent(ResetType::OneShot, "HID:EventPadOrTouch2"); + event_accelerometer = system.Kernel().CreateEvent(ResetType::OneShot, "HID:EventAccelerometer"); + event_gyroscope = system.Kernel().CreateEvent(ResetType::OneShot, "HID:EventGyroscope"); + event_debug_pad = system.Kernel().CreateEvent(ResetType::OneShot, "HID:EventDebugPad"); // Register update callbacks pad_update_event = diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp index 0869941f2..5d99908cc 100644 --- a/src/core/hle/service/ir/ir.cpp +++ b/src/core/hle/service/ir/ir.cpp @@ -16,10 +16,10 @@ void InstallInterfaces(Core::System& system) { auto& service_manager = system.ServiceManager(); std::make_shared()->InstallAsService(service_manager); - auto ir_user = std::make_shared(); + auto ir_user = std::make_shared(system); ir_user->InstallAsService(service_manager); - auto ir_rst = std::make_shared(); + auto ir_rst = std::make_shared(system); ir_rst->InstallAsService(service_manager); } diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp index 3dbf04722..eb62ddb6c 100644 --- a/src/core/hle/service/ir/ir_rst.cpp +++ b/src/core/hle/service/ir/ir_rst.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/core.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" @@ -144,14 +145,14 @@ void IR_RST::Shutdown(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_IR, "called"); } -IR_RST::IR_RST() : ServiceFramework("ir:rst", 1) { +IR_RST::IR_RST(Core::System& system) : ServiceFramework("ir:rst", 1) { using namespace Kernel; // Note: these two kernel objects are even available before Initialize service function is // called. shared_memory = SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read, 0, MemoryRegion::BASE, "IRRST:SharedMemory"); - update_event = Event::Create(ResetType::OneShot, "IRRST:UpdateEvent"); + update_event = system.Kernel().CreateEvent(ResetType::OneShot, "IRRST:UpdateEvent"); update_callback_id = CoreTiming::RegisterEvent("IRRST:UpdateCallBack", [this](u64 userdata, s64 cycles_late) { diff --git a/src/core/hle/service/ir/ir_rst.h b/src/core/hle/service/ir/ir_rst.h index 0ba5ea8f7..821fb0b2f 100644 --- a/src/core/hle/service/ir/ir_rst.h +++ b/src/core/hle/service/ir/ir_rst.h @@ -39,7 +39,7 @@ union PadState { /// Interface to "ir:rst" service class IR_RST final : public ServiceFramework { public: - IR_RST(); + explicit IR_RST(Core::System& system); ~IR_RST(); void ReloadInputDevices(); diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp index 2edf11c48..e0158f67e 100644 --- a/src/core/hle/service/ir/ir_user.cpp +++ b/src/core/hle/service/ir/ir_user.cpp @@ -6,6 +6,7 @@ #include #include "common/string_util.h" #include "common/swap.h" +#include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" @@ -380,7 +381,7 @@ void IR_USER::ReleaseReceivedData(Kernel::HLERequestContext& ctx) { LOG_TRACE(Service_IR, "called, count={}", count); } -IR_USER::IR_USER() : ServiceFramework("ir:USER", 1) { +IR_USER::IR_USER(Core::System& system) : ServiceFramework("ir:USER", 1) { const FunctionInfo functions[] = { {0x00010182, nullptr, "InitializeIrNop"}, {0x00020000, &IR_USER::FinalizeIrNop, "FinalizeIrNop"}, @@ -413,9 +414,9 @@ IR_USER::IR_USER() : ServiceFramework("ir:USER", 1) { using namespace Kernel; - conn_status_event = Event::Create(ResetType::OneShot, "IR:ConnectionStatusEvent"); - send_event = Event::Create(ResetType::OneShot, "IR:SendEvent"); - receive_event = Event::Create(ResetType::OneShot, "IR:ReceiveEvent"); + conn_status_event = system.Kernel().CreateEvent(ResetType::OneShot, "IR:ConnectionStatusEvent"); + send_event = system.Kernel().CreateEvent(ResetType::OneShot, "IR:SendEvent"); + receive_event = system.Kernel().CreateEvent(ResetType::OneShot, "IR:ReceiveEvent"); extra_hid = std::make_unique([this](const std::vector& data) { PutToReceive(data); }); diff --git a/src/core/hle/service/ir/ir_user.h b/src/core/hle/service/ir/ir_user.h index 207a54058..fea0794bc 100644 --- a/src/core/hle/service/ir/ir_user.h +++ b/src/core/hle/service/ir/ir_user.h @@ -55,7 +55,7 @@ private: /// Interface to "ir:USER" service class IR_USER final : public ServiceFramework { public: - IR_USER(); + explicit IR_USER(Core::System& system); ~IR_USER(); void ReloadInputDevices(); diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp index 34e68099f..b2c24bd17 100644 --- a/src/core/hle/service/mic_u.cpp +++ b/src/core/hle/service/mic_u.cpp @@ -29,6 +29,11 @@ enum class SampleRate : u8 { }; struct MIC_U::Impl { + explicit Impl(Core::System& system) { + buffer_full_event = + system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "MIC_U::buffer_full_event"); + } + void MapSharedMem(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx, 0x01, 1, 2}; const u32 size = rp.Pop(); @@ -187,8 +192,7 @@ struct MIC_U::Impl { } u32 client_version = 0; - Kernel::SharedPtr buffer_full_event = - Kernel::Event::Create(Kernel::ResetType::OneShot, "MIC_U::buffer_full_event"); + Kernel::SharedPtr buffer_full_event; Kernel::SharedPtr shared_memory; u8 mic_gain = 0; bool mic_power = false; @@ -266,7 +270,8 @@ void MIC_U::SetClientVersion(Kernel::HLERequestContext& ctx) { impl->SetClientVersion(ctx); } -MIC_U::MIC_U() : ServiceFramework{"mic:u", 1}, impl{std::make_unique()} { +MIC_U::MIC_U(Core::System& system) + : ServiceFramework{"mic:u", 1}, impl{std::make_unique(system)} { static const FunctionInfo functions[] = { {0x00010042, &MIC_U::MapSharedMem, "MapSharedMem"}, {0x00020000, &MIC_U::UnmapSharedMem, "UnmapSharedMem"}, @@ -293,7 +298,7 @@ MIC_U::~MIC_U() = default; void InstallInterfaces(Core::System& system) { auto& service_manager = system.ServiceManager(); - std::make_shared()->InstallAsService(service_manager); + std::make_shared(system)->InstallAsService(service_manager); } } // namespace Service::MIC diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic_u.h index 8fd835f0a..bc4933229 100644 --- a/src/core/hle/service/mic_u.h +++ b/src/core/hle/service/mic_u.h @@ -16,7 +16,7 @@ namespace Service::MIC { class MIC_U final : public ServiceFramework { public: - MIC_U(); + explicit MIC_U(Core::System& system); ~MIC_U(); private: diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index 80bd6aa72..e76c7b3ee 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp @@ -140,18 +140,18 @@ Module::Interface::Interface(std::shared_ptr nfc, const char* name, u32 Module::Interface::~Interface() = default; -Module::Module() { +Module::Module(Core::System& system) { tag_in_range_event = - Kernel::Event::Create(Kernel::ResetType::OneShot, "NFC::tag_in_range_event"); + system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "NFC::tag_in_range_event"); tag_out_of_range_event = - Kernel::Event::Create(Kernel::ResetType::OneShot, "NFC::tag_out_range_event"); + system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "NFC::tag_out_range_event"); } Module::~Module() = default; void InstallInterfaces(Core::System& system) { auto& service_manager = system.ServiceManager(); - auto nfc = std::make_shared(); + auto nfc = std::make_shared(system); std::make_shared(nfc)->InstallAsService(service_manager); std::make_shared(nfc)->InstallAsService(service_manager); } diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h index d942e4b63..bafdcf0fa 100644 --- a/src/core/hle/service/nfc/nfc.h +++ b/src/core/hle/service/nfc/nfc.h @@ -41,7 +41,7 @@ enum class CommunicationStatus : u8 { class Module final { public: - Module(); + explicit Module(Core::System& system); ~Module(); class Interface : public ServiceFramework { diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index 25dafaa6e..a0b84bd03 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp @@ -14,7 +14,7 @@ void InstallInterfaces(Core::System& system) { auto& service_manager = system.ServiceManager(); std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); - std::make_shared()->InstallAsService(service_manager); + std::make_shared(system)->InstallAsService(service_manager); } } // namespace Service::NIM diff --git a/src/core/hle/service/nim/nim_u.cpp b/src/core/hle/service/nim/nim_u.cpp index acf29cfe0..dd0e4d31c 100644 --- a/src/core/hle/service/nim/nim_u.cpp +++ b/src/core/hle/service/nim/nim_u.cpp @@ -2,13 +2,14 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/service/nim/nim_u.h" namespace Service::NIM { -NIM_U::NIM_U() : ServiceFramework("nim:u", 2) { +NIM_U::NIM_U(Core::System& system) : ServiceFramework("nim:u", 2) { const FunctionInfo functions[] = { {0x00010000, nullptr, "StartSysUpdate"}, {0x00020000, nullptr, "GetUpdateDownloadProgress"}, @@ -20,7 +21,7 @@ NIM_U::NIM_U() : ServiceFramework("nim:u", 2) { }; RegisterHandlers(functions); nim_system_update_event = - Kernel::Event::Create(Kernel::ResetType::OneShot, "NIM System Update Event"); + system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "NIM System Update Event"); } NIM_U::~NIM_U() = default; diff --git a/src/core/hle/service/nim/nim_u.h b/src/core/hle/service/nim/nim_u.h index 610688fc2..0f4338f16 100644 --- a/src/core/hle/service/nim/nim_u.h +++ b/src/core/hle/service/nim/nim_u.h @@ -6,11 +6,15 @@ #include "core/hle/service/service.h" +namespace Core { +class System; +} + namespace Service::NIM { class NIM_U final : public ServiceFramework { public: - NIM_U(); + explicit NIM_U(Core::System& system); ~NIM_U(); private: diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp index fe9d09b98..4072aac09 100644 --- a/src/core/hle/service/nwm/nwm_uds.cpp +++ b/src/core/hle/service/nwm/nwm_uds.cpp @@ -839,8 +839,8 @@ void NWM_UDS::Bind(Kernel::HLERequestContext& ctx) { } // Create a new event for this bind node. - auto event = Kernel::Event::Create(Kernel::ResetType::OneShot, - "NWM::BindNodeEvent" + std::to_string(bind_node_id)); + auto event = system.Kernel().CreateEvent(Kernel::ResetType::OneShot, + "NWM::BindNodeEvent" + std::to_string(bind_node_id)); std::lock_guard lock(connection_status_mutex); ASSERT(channel_data.find(data_channel) == channel_data.end()); @@ -1355,7 +1355,7 @@ static void BeaconBroadcastCallback(u64 userdata, s64 cycles_late) { beacon_broadcast_event, 0); } -NWM_UDS::NWM_UDS(Core::System& system) : ServiceFramework("nwm::UDS") { +NWM_UDS::NWM_UDS(Core::System& system) : ServiceFramework("nwm::UDS"), system(system) { static const FunctionInfo functions[] = { {0x000102C2, nullptr, "Initialize (deprecated)"}, {0x00020000, nullptr, "Scrap"}, @@ -1388,7 +1388,7 @@ NWM_UDS::NWM_UDS(Core::System& system) : ServiceFramework("nwm::UDS") { {0x00220402, nullptr, "ScanOnConnection"}, }; connection_status_event = - Kernel::Event::Create(Kernel::ResetType::OneShot, "NWM::connection_status_event"); + system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "NWM::connection_status_event"); RegisterHandlers(functions); diff --git a/src/core/hle/service/nwm/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h index 2c79aa674..b6cac1ee0 100644 --- a/src/core/hle/service/nwm/nwm_uds.h +++ b/src/core/hle/service/nwm/nwm_uds.h @@ -112,6 +112,8 @@ public: ~NWM_UDS(); private: + Core::System& system; + void UpdateNetworkAttribute(Kernel::HLERequestContext& ctx); /** diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index cd20b57bd..0de5cf8d5 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp @@ -632,7 +632,7 @@ void Y2R_U::GetPackageParameter(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Y2R, "called"); } -Y2R_U::Y2R_U() : ServiceFramework("y2r:u", 1) { +Y2R_U::Y2R_U(Core::System& system) : ServiceFramework("y2r:u", 1) { static const FunctionInfo functions[] = { {0x00010040, &Y2R_U::SetInputFormat, "SetInputFormat"}, {0x00020000, &Y2R_U::GetInputFormat, "GetInputFormat"}, @@ -682,14 +682,14 @@ Y2R_U::Y2R_U() : ServiceFramework("y2r:u", 1) { }; RegisterHandlers(functions); - completion_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "Y2R:Completed"); + completion_event = system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "Y2R:Completed"); } Y2R_U::~Y2R_U() = default; void InstallInterfaces(Core::System& system) { auto& service_manager = system.ServiceManager(); - std::make_shared()->InstallAsService(service_manager); + std::make_shared(system)->InstallAsService(service_manager); } } // namespace Service::Y2R diff --git a/src/core/hle/service/y2r_u.h b/src/core/hle/service/y2r_u.h index e32763925..007782dd5 100644 --- a/src/core/hle/service/y2r_u.h +++ b/src/core/hle/service/y2r_u.h @@ -149,7 +149,7 @@ static_assert(sizeof(ConversionParameters) == 12, "ConversionParameters struct h class Y2R_U final : public ServiceFramework { public: - Y2R_U(); + explicit Y2R_U(Core::System& system); ~Y2R_U() override; private: diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp index d0bf44a58..f9b705f20 100644 --- a/src/tests/core/hle/kernel/hle_ipc.cpp +++ b/src/tests/core/hle/kernel/hle_ipc.cpp @@ -15,7 +15,8 @@ namespace Kernel { static SharedPtr MakeObject() { - return Event::Create(ResetType::OneShot); + static Kernel::KernelSystem kernel(0); + return kernel.CreateEvent(ResetType::OneShot); } TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") { From 7449ba85a6aeaec14af9535cd80e362548ea3f15 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 11 Oct 2018 16:00:09 -0400 Subject: [PATCH 013/102] Kernel: pass ref in Mutex --- src/core/hle/kernel/kernel.h | 9 +++++++++ src/core/hle/kernel/mutex.cpp | 6 +++--- src/core/hle/kernel/mutex.h | 12 +++--------- src/core/hle/kernel/svc.cpp | 2 +- src/core/hle/service/am/am.cpp | 6 +++--- src/core/hle/service/am/am.h | 2 +- src/core/hle/service/apt/apt.cpp | 2 +- src/core/hle/service/csnd/csnd_snd.cpp | 6 +++--- src/core/hle/service/csnd/csnd_snd.h | 4 +++- 9 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 94e2b60f6..28bad6efa 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -12,6 +12,7 @@ namespace Kernel { class AddressArbiter; class Event; +class Mutex; enum class ResetType { OneShot, @@ -41,6 +42,14 @@ public: * @param name Optional name of event */ SharedPtr CreateEvent(ResetType reset_type, std::string name = "Unknown"); + + /** + * Creates a mutex. + * @param initial_locked Specifies if the mutex should be locked initially + * @param name Optional name of mutex + * @return Pointer to new Mutex object + */ + SharedPtr CreateMutex(bool initial_locked, std::string name = "Unknown"); }; } // namespace Kernel diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 02cbf613c..dc4a55d35 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -24,11 +24,11 @@ void ReleaseThreadMutexes(Thread* thread) { thread->held_mutexes.clear(); } -Mutex::Mutex() {} +Mutex::Mutex(KernelSystem& kernel) {} Mutex::~Mutex() {} -SharedPtr Mutex::Create(bool initial_locked, std::string name) { - SharedPtr mutex(new Mutex); +SharedPtr KernelSystem::CreateMutex(bool initial_locked, std::string name) { + SharedPtr mutex(new Mutex(*this)); mutex->lock_count = 0; mutex->name = std::move(name); diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index 3afb99c59..ec0e3f794 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -16,14 +16,6 @@ class Thread; class Mutex final : public WaitObject { public: - /** - * Creates a mutex. - * @param initial_locked Specifies if the mutex should be locked initially - * @param name Optional name of mutex - * @return Pointer to new Mutex object - */ - static SharedPtr Create(bool initial_locked, std::string name = "Unknown"); - std::string GetTypeName() const override { return "Mutex"; } @@ -61,8 +53,10 @@ public: ResultCode Release(Thread* thread); private: - Mutex(); + explicit Mutex(KernelSystem& kernel); ~Mutex() override; + + friend class KernelSystem; }; /** diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 2c81b75fd..8ea242e6d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -828,7 +828,7 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { /// Create a mutex static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { - SharedPtr mutex = Mutex::Create(initial_locked != 0); + SharedPtr mutex = Core::System::GetInstance().Kernel().CreateMutex(initial_locked != 0); mutex->name = fmt::format("mutex-{:08x}", Core::CPU().GetReg(14)); CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(mutex))); diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 35e3c0ad9..e9f0c6227 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1455,16 +1455,16 @@ void Module::Interface::GetMetaDataFromCia(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(output_buffer); } -Module::Module() { +Module::Module(Core::System& system) { ScanForAllTitles(); - system_updater_mutex = Kernel::Mutex::Create(false, "AM::SystemUpdaterMutex"); + system_updater_mutex = system.Kernel().CreateMutex(false, "AM::SystemUpdaterMutex"); } Module::~Module() = default; void InstallInterfaces(Core::System& system) { auto& service_manager = system.ServiceManager(); - auto am = std::make_shared(); + auto am = std::make_shared(system); std::make_shared(am)->InstallAsService(service_manager); std::make_shared(am)->InstallAsService(service_manager); std::make_shared(am)->InstallAsService(service_manager); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 543dbd8fe..792225113 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -149,7 +149,7 @@ std::string GetMediaTitlePath(Service::FS::MediaType media_type); class Module final { public: - Module(); + explicit Module(Core::System& system); ~Module(); class Interface : public ServiceFramework { diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index a673fe97e..752e65c2c 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -859,7 +859,7 @@ Module::Module(Core::System& system) : system(system) { MemoryPermission::ReadWrite, MemoryPermission::Read, 0, Kernel::MemoryRegion::SYSTEM, "APT:SharedFont"); - lock = Kernel::Mutex::Create(false, "APT_U:Lock"); + lock = system.Kernel().CreateMutex(false, "APT_U:Lock"); } Module::~Module() {} diff --git a/src/core/hle/service/csnd/csnd_snd.cpp b/src/core/hle/service/csnd/csnd_snd.cpp index 6e0488b3a..8fc4f11f4 100644 --- a/src/core/hle/service/csnd/csnd_snd.cpp +++ b/src/core/hle/service/csnd/csnd_snd.cpp @@ -19,7 +19,7 @@ void CSND_SND::Initialize(Kernel::HLERequestContext& ctx) { const u32 offset3 = rp.Pop(); using Kernel::MemoryPermission; - mutex = Kernel::Mutex::Create(false, "CSND:mutex"); + mutex = system.Kernel().CreateMutex(false, "CSND:mutex"); shared_memory = Kernel::SharedMemory::Create(nullptr, size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, 0, Kernel::MemoryRegion::BASE, "CSND:SharedMemory"); @@ -173,7 +173,7 @@ void CSND_SND::Reset(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_CSND, "(STUBBED) called"); } -CSND_SND::CSND_SND() : ServiceFramework("csnd:SND", 4) { +CSND_SND::CSND_SND(Core::System& system) : ServiceFramework("csnd:SND", 4), system(system) { static const FunctionInfo functions[] = { // clang-format off {0x00010140, &CSND_SND::Initialize, "Initialize"}, @@ -196,7 +196,7 @@ CSND_SND::CSND_SND() : ServiceFramework("csnd:SND", 4) { void InstallInterfaces(Core::System& system) { auto& service_manager = system.ServiceManager(); - std::make_shared()->InstallAsService(service_manager); + std::make_shared(system)->InstallAsService(service_manager); } } // namespace Service::CSND diff --git a/src/core/hle/service/csnd/csnd_snd.h b/src/core/hle/service/csnd/csnd_snd.h index 909034e6d..94b1bf3bb 100644 --- a/src/core/hle/service/csnd/csnd_snd.h +++ b/src/core/hle/service/csnd/csnd_snd.h @@ -16,7 +16,7 @@ namespace Service::CSND { class CSND_SND final : public ServiceFramework { public: - CSND_SND(); + explicit CSND_SND(Core::System& system); ~CSND_SND() = default; private: @@ -174,6 +174,8 @@ private: }; static_assert(sizeof(Type0Command) == 0x20, "Type0Command structure size is wrong"); + Core::System& system; + Kernel::SharedPtr mutex = nullptr; Kernel::SharedPtr shared_memory = nullptr; From 213b259cf18396c3bd80ba167f0bace0c128e2e8 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Fri, 12 Oct 2018 15:21:32 -0400 Subject: [PATCH 014/102] kernel: pass ref in CodeSet --- src/core/hle/kernel/kernel.h | 3 ++ src/core/hle/kernel/process.cpp | 6 ++-- src/core/hle/kernel/process.h | 6 ++-- src/core/loader/3dsx.cpp | 2 +- src/core/loader/elf.cpp | 3 +- src/core/loader/ncch.cpp | 3 +- src/tests/core/arm/arm_test_common.cpp | 8 +++++- src/tests/core/arm/arm_test_common.h | 4 ++- src/tests/core/hle/kernel/hle_ipc.cpp | 38 ++++++++++++++++---------- src/tests/core/memory/memory.cpp | 13 ++++++--- 10 files changed, 56 insertions(+), 30 deletions(-) diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 28bad6efa..0717eb225 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -13,6 +13,7 @@ namespace Kernel { class AddressArbiter; class Event; class Mutex; +class CodeSet; enum class ResetType { OneShot, @@ -50,6 +51,8 @@ public: * @return Pointer to new Mutex object */ SharedPtr CreateMutex(bool initial_locked, std::string name = "Unknown"); + + SharedPtr CreateCodeSet(std::string name, u64 program_id); }; } // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 8f3efe5d9..ac0908913 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -20,8 +20,8 @@ namespace Kernel { // Lists all processes that exist in the current session. static std::vector> process_list; -SharedPtr CodeSet::Create(std::string name, u64 program_id) { - SharedPtr codeset(new CodeSet); +SharedPtr KernelSystem::CreateCodeSet(std::string name, u64 program_id) { + SharedPtr codeset(new CodeSet(*this)); codeset->name = std::move(name); codeset->program_id = program_id; @@ -29,7 +29,7 @@ SharedPtr CodeSet::Create(std::string name, u64 program_id) { return codeset; } -CodeSet::CodeSet() {} +CodeSet::CodeSet(KernelSystem& system) {} CodeSet::~CodeSet() {} u32 Process::next_process_id; diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 1081be063..3d6979598 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -62,8 +62,6 @@ struct CodeSet final : public Object { u32 size = 0; }; - static SharedPtr Create(std::string name, u64 program_id); - std::string GetTypeName() const override { return "CodeSet"; } @@ -111,8 +109,10 @@ struct CodeSet final : public Object { u64 program_id; private: - CodeSet(); + explicit CodeSet(KernelSystem& kernel); ~CodeSet() override; + + friend class KernelSystem; }; class Process final : public Object { diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index d791c085c..20adb1ac4 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp @@ -217,7 +217,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, } // Create the CodeSet - SharedPtr code_set = CodeSet::Create("", 0); + SharedPtr code_set = Core::System::GetInstance().Kernel().CreateCodeSet("", 0); code_set->CodeSegment().offset = loadinfo.seg_ptrs[0] - program_image.data(); code_set->CodeSegment().addr = loadinfo.seg_addrs[0]; diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index fd2bb23b3..9064abff1 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -8,6 +8,7 @@ #include "common/common_types.h" #include "common/file_util.h" #include "common/logging/log.h" +#include "core/core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/loader/elf.h" @@ -299,7 +300,7 @@ SharedPtr ElfReader::LoadInto(u32 vaddr) { std::vector program_image(total_image_size); std::size_t current_image_position = 0; - SharedPtr codeset = CodeSet::Create("", 0); + SharedPtr codeset = Core::System::GetInstance().Kernel().CreateCodeSet("", 0); for (unsigned int i = 0; i < header->e_phnum; ++i) { Elf32_Phdr* p = &segments[i]; diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 9fa1d05f1..c609eb9bd 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -75,7 +75,8 @@ ResultStatus AppLoader_NCCH::LoadExec(Kernel::SharedPtr& proces std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( (const char*)overlay_ncch->exheader_header.codeset_info.name, 8); - SharedPtr codeset = CodeSet::Create(process_name, program_id); + SharedPtr codeset = + Core::System::GetInstance().Kernel().CreateCodeSet(process_name, program_id); codeset->CodeSegment().offset = 0; codeset->CodeSegment().addr = overlay_ncch->exheader_header.codeset_info.text.address; diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp index 23c0411e7..fd6f43aff 100644 --- a/src/tests/core/arm/arm_test_common.cpp +++ b/src/tests/core/arm/arm_test_common.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "core/core.h" +#include "core/core_timing.h" #include "core/hle/kernel/process.h" #include "core/memory.h" #include "core/memory_setup.h" @@ -15,7 +16,10 @@ static Memory::PageTable* page_table = nullptr; TestEnvironment::TestEnvironment(bool mutable_memory_) : mutable_memory(mutable_memory_), test_memory(std::make_shared(this)) { - Kernel::g_current_process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0)); + CoreTiming::Init(); + kernel = std::make_unique(0); + + Kernel::g_current_process = Kernel::Process::Create(kernel->CreateCodeSet("", 0)); page_table = &Kernel::g_current_process->vm_manager.page_table; page_table->pointers.fill(nullptr); @@ -30,6 +34,8 @@ TestEnvironment::TestEnvironment(bool mutable_memory_) TestEnvironment::~TestEnvironment() { Memory::UnmapRegion(*page_table, 0x80000000, 0x80000000); Memory::UnmapRegion(*page_table, 0x00000000, 0x80000000); + + CoreTiming::Shutdown(); } void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) { diff --git a/src/tests/core/arm/arm_test_common.h b/src/tests/core/arm/arm_test_common.h index 44c63818a..4f396416f 100644 --- a/src/tests/core/arm/arm_test_common.h +++ b/src/tests/core/arm/arm_test_common.h @@ -5,8 +5,8 @@ #include #include #include - #include "common/common_types.h" +#include "core/hle/kernel/kernel.h" #include "core/mmio.h" namespace ArmTests { @@ -79,6 +79,8 @@ private: bool mutable_memory; std::shared_ptr test_memory; std::vector write_records; + + std::unique_ptr kernel; }; } // namespace ArmTests diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp index f9b705f20..d9596c397 100644 --- a/src/tests/core/hle/kernel/hle_ipc.cpp +++ b/src/tests/core/hle/kernel/hle_ipc.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include "core/core_timing.h" #include "core/hle/ipc.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" @@ -14,16 +15,17 @@ namespace Kernel { -static SharedPtr MakeObject() { - static Kernel::KernelSystem kernel(0); +static SharedPtr MakeObject(Kernel::KernelSystem& kernel) { return kernel.CreateEvent(ResetType::OneShot); } TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") { + CoreTiming::Init(); + Kernel::KernelSystem kernel(0); auto session = std::get>(ServerSession::CreateSessionPair()); HLERequestContext context(std::move(session)); - auto process = Process::Create(CodeSet::Create("", 0)); + auto process = Process::Create(kernel.CreateCodeSet("", 0)); HandleTable handle_table; SECTION("works with empty cmdbuf") { @@ -53,7 +55,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel } SECTION("translates move handles") { - auto a = MakeObject(); + auto a = MakeObject(kernel); Handle a_handle = handle_table.Create(a).Unwrap(); const u32_le input[]{ IPC::MakeHeader(0, 0, 2), @@ -69,7 +71,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel } SECTION("translates copy handles") { - auto a = MakeObject(); + auto a = MakeObject(kernel); Handle a_handle = handle_table.Create(a).Unwrap(); const u32_le input[]{ IPC::MakeHeader(0, 0, 2), @@ -85,9 +87,9 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel } SECTION("translates multi-handle descriptors") { - auto a = MakeObject(); - auto b = MakeObject(); - auto c = MakeObject(); + auto a = MakeObject(kernel); + auto b = MakeObject(kernel); + auto c = MakeObject(kernel); const u32_le input[]{ IPC::MakeHeader(0, 0, 5), IPC::MoveHandleDesc(2), handle_table.Create(a).Unwrap(), handle_table.Create(b).Unwrap(), @@ -191,7 +193,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel buffer_mapped->size(), MemoryState::Private); REQUIRE(result.Code() == RESULT_SUCCESS); - auto a = MakeObject(); + auto a = MakeObject(kernel); const u32_le input[]{ IPC::MakeHeader(0, 2, 8), 0x12345678, @@ -223,13 +225,17 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel REQUIRE(process->vm_manager.UnmapRange(target_address_mapped, buffer_mapped->size()) == RESULT_SUCCESS); } + + CoreTiming::Shutdown(); } TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { + CoreTiming::Init(); + Kernel::KernelSystem kernel(0); auto session = std::get>(ServerSession::CreateSessionPair()); HLERequestContext context(std::move(session)); - auto process = Process::Create(CodeSet::Create("", 0)); + auto process = Process::Create(kernel.CreateCodeSet("", 0)); HandleTable handle_table; auto* input = context.CommandBuffer(); u32_le output[IPC::COMMAND_BUFFER_LENGTH]; @@ -256,8 +262,8 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { } SECTION("translates move/copy handles") { - auto a = MakeObject(); - auto b = MakeObject(); + auto a = MakeObject(kernel); + auto b = MakeObject(kernel); input[0] = IPC::MakeHeader(0, 0, 4); input[1] = IPC::MoveHandleDesc(1); input[2] = context.AddOutgoingHandle(a); @@ -282,9 +288,9 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { } SECTION("translates multi-handle descriptors") { - auto a = MakeObject(); - auto b = MakeObject(); - auto c = MakeObject(); + auto a = MakeObject(kernel); + auto b = MakeObject(kernel); + auto c = MakeObject(kernel); input[0] = IPC::MakeHeader(0, 0, 5); input[1] = IPC::MoveHandleDesc(2); input[2] = context.AddOutgoingHandle(a); @@ -362,6 +368,8 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { REQUIRE(process->vm_manager.UnmapRange(target_address, output_buffer->size()) == RESULT_SUCCESS); } + + CoreTiming::Shutdown(); } } // namespace Kernel diff --git a/src/tests/core/memory/memory.cpp b/src/tests/core/memory/memory.cpp index c69340865..89dcd9c9a 100644 --- a/src/tests/core/memory/memory.cpp +++ b/src/tests/core/memory/memory.cpp @@ -3,14 +3,17 @@ // Refer to the license.txt file included. #include +#include "core/core_timing.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/process.h" #include "core/hle/shared_page.h" #include "core/memory.h" TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { + CoreTiming::Init(); + Kernel::KernelSystem kernel(0); SECTION("these regions should not be mapped on an empty process") { - auto process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0)); + auto process = Kernel::Process::Create(kernel.CreateCodeSet("", 0)); CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false); CHECK(Memory::IsValidVirtualAddress(*process, Memory::HEAP_VADDR) == false); CHECK(Memory::IsValidVirtualAddress(*process, Memory::LINEAR_HEAP_VADDR) == false); @@ -21,14 +24,14 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { } SECTION("CONFIG_MEMORY_VADDR and SHARED_PAGE_VADDR should be valid after mapping them") { - auto process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0)); + auto process = Kernel::Process::Create(kernel.CreateCodeSet("", 0)); Kernel::MapSharedPages(process->vm_manager); CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true); CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true); } SECTION("special regions should be valid after mapping them") { - auto process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0)); + auto process = Kernel::Process::Create(kernel.CreateCodeSet("", 0)); SECTION("VRAM") { Kernel::HandleSpecialMapping(process->vm_manager, {Memory::VRAM_VADDR, Memory::VRAM_SIZE, false, false}); @@ -43,9 +46,11 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { } SECTION("Unmapping a VAddr should make it invalid") { - auto process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0)); + auto process = Kernel::Process::Create(kernel.CreateCodeSet("", 0)); Kernel::MapSharedPages(process->vm_manager); process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE); CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false); } + + CoreTiming::Shutdown(); } From 9565091fc2d1e66c613306ba798e6c6b8739d81f Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Fri, 12 Oct 2018 15:33:36 -0400 Subject: [PATCH 015/102] kernel: pass ref in Process --- src/core/hle/kernel/kernel.h | 3 +++ src/core/hle/kernel/process.cpp | 6 +++--- src/core/hle/kernel/process.h | 7 ++++--- src/core/loader/3dsx.cpp | 2 +- src/core/loader/elf.cpp | 2 +- src/core/loader/ncch.cpp | 2 +- src/tests/core/arm/arm_test_common.cpp | 2 +- src/tests/core/hle/kernel/hle_ipc.cpp | 4 ++-- src/tests/core/memory/memory.cpp | 8 ++++---- 9 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 0717eb225..9e29868ca 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -14,6 +14,7 @@ class AddressArbiter; class Event; class Mutex; class CodeSet; +class Process; enum class ResetType { OneShot, @@ -53,6 +54,8 @@ public: SharedPtr CreateMutex(bool initial_locked, std::string name = "Unknown"); SharedPtr CreateCodeSet(std::string name, u64 program_id); + + SharedPtr CreateProcess(SharedPtr code_set); }; } // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index ac0908913..3e95cc6f7 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -34,8 +34,8 @@ CodeSet::~CodeSet() {} u32 Process::next_process_id; -SharedPtr Process::Create(SharedPtr code_set) { - SharedPtr process(new Process); +SharedPtr KernelSystem::CreateProcess(SharedPtr code_set) { + SharedPtr process(new Process(*this)); process->codeset = std::move(code_set); process->flags.raw = 0; @@ -304,7 +304,7 @@ ResultCode Process::LinearFree(VAddr target, u32 size) { return RESULT_SUCCESS; } -Kernel::Process::Process() {} +Kernel::Process::Process(KernelSystem& kernel) : kernel(kernel) {} Kernel::Process::~Process() {} void ClearProcessList() { diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 3d6979598..edf4928ff 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -117,8 +117,6 @@ private: class Process final : public Object { public: - static SharedPtr Create(SharedPtr code_set); - std::string GetTypeName() const override { return "Process"; } @@ -201,8 +199,11 @@ public: ResultCode LinearFree(VAddr target, u32 size); private: - Process(); + explicit Process(Kernel::KernelSystem& kernel); ~Process() override; + + friend class KernelSystem; + KernelSystem& kernel; }; void ClearProcessList(); diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index 20adb1ac4..486270a59 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp @@ -267,7 +267,7 @@ ResultStatus AppLoader_THREEDSX::Load(Kernel::SharedPtr& proces return ResultStatus::Error; codeset->name = filename; - process = Kernel::Process::Create(std::move(codeset)); + process = Core::System::GetInstance().Kernel().CreateProcess(std::move(codeset)); process->svc_access_mask.set(); process->address_mappings = default_address_mappings; diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 9064abff1..86abd7763 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -396,7 +396,7 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr& process) { SharedPtr codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); codeset->name = filename; - process = Kernel::Process::Create(std::move(codeset)); + process = Core::System::GetInstance().Kernel().CreateProcess(std::move(codeset)); process->svc_access_mask.set(); process->address_mappings = default_address_mappings; diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index c609eb9bd..10260591a 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -104,7 +104,7 @@ ResultStatus AppLoader_NCCH::LoadExec(Kernel::SharedPtr& proces codeset->entrypoint = codeset->CodeSegment().addr; codeset->memory = std::make_shared>(std::move(code)); - process = Kernel::Process::Create(std::move(codeset)); + process = Core::System::GetInstance().Kernel().CreateProcess(std::move(codeset)); // Attach a resource limit to the process based on the resource limit category process->resource_limit = diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp index fd6f43aff..4706c2512 100644 --- a/src/tests/core/arm/arm_test_common.cpp +++ b/src/tests/core/arm/arm_test_common.cpp @@ -19,7 +19,7 @@ TestEnvironment::TestEnvironment(bool mutable_memory_) CoreTiming::Init(); kernel = std::make_unique(0); - Kernel::g_current_process = Kernel::Process::Create(kernel->CreateCodeSet("", 0)); + Kernel::g_current_process = kernel->CreateProcess(kernel->CreateCodeSet("", 0)); page_table = &Kernel::g_current_process->vm_manager.page_table; page_table->pointers.fill(nullptr); diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp index d9596c397..bb4c3b6ad 100644 --- a/src/tests/core/hle/kernel/hle_ipc.cpp +++ b/src/tests/core/hle/kernel/hle_ipc.cpp @@ -25,7 +25,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel auto session = std::get>(ServerSession::CreateSessionPair()); HLERequestContext context(std::move(session)); - auto process = Process::Create(kernel.CreateCodeSet("", 0)); + auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); HandleTable handle_table; SECTION("works with empty cmdbuf") { @@ -235,7 +235,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { auto session = std::get>(ServerSession::CreateSessionPair()); HLERequestContext context(std::move(session)); - auto process = Process::Create(kernel.CreateCodeSet("", 0)); + auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); HandleTable handle_table; auto* input = context.CommandBuffer(); u32_le output[IPC::COMMAND_BUFFER_LENGTH]; diff --git a/src/tests/core/memory/memory.cpp b/src/tests/core/memory/memory.cpp index 89dcd9c9a..d5f96e1f2 100644 --- a/src/tests/core/memory/memory.cpp +++ b/src/tests/core/memory/memory.cpp @@ -13,7 +13,7 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { CoreTiming::Init(); Kernel::KernelSystem kernel(0); SECTION("these regions should not be mapped on an empty process") { - auto process = Kernel::Process::Create(kernel.CreateCodeSet("", 0)); + auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false); CHECK(Memory::IsValidVirtualAddress(*process, Memory::HEAP_VADDR) == false); CHECK(Memory::IsValidVirtualAddress(*process, Memory::LINEAR_HEAP_VADDR) == false); @@ -24,14 +24,14 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { } SECTION("CONFIG_MEMORY_VADDR and SHARED_PAGE_VADDR should be valid after mapping them") { - auto process = Kernel::Process::Create(kernel.CreateCodeSet("", 0)); + auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); Kernel::MapSharedPages(process->vm_manager); CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true); CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true); } SECTION("special regions should be valid after mapping them") { - auto process = Kernel::Process::Create(kernel.CreateCodeSet("", 0)); + auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); SECTION("VRAM") { Kernel::HandleSpecialMapping(process->vm_manager, {Memory::VRAM_VADDR, Memory::VRAM_SIZE, false, false}); @@ -46,7 +46,7 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { } SECTION("Unmapping a VAddr should make it invalid") { - auto process = Kernel::Process::Create(kernel.CreateCodeSet("", 0)); + auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); Kernel::MapSharedPages(process->vm_manager); process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE); CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false); From d940293d324984d0a75f1eaaef2c916c776cb1a4 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Fri, 12 Oct 2018 15:47:06 -0400 Subject: [PATCH 016/102] Kernel: pass ref to thread --- src/core/hle/kernel/kernel.h | 17 +++++++++++++++++ src/core/hle/kernel/process.cpp | 2 +- src/core/hle/kernel/svc.cpp | 6 +++--- src/core/hle/kernel/thread.cpp | 18 ++++++++++-------- src/core/hle/kernel/thread.h | 23 ++++++----------------- 5 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 9e29868ca..aca8a5fab 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -7,6 +7,7 @@ #include #include #include "common/common_types.h" +#include "core/hle/result.h" namespace Kernel { @@ -15,6 +16,7 @@ class Event; class Mutex; class CodeSet; class Process; +class Thread; enum class ResetType { OneShot, @@ -56,6 +58,21 @@ public: SharedPtr CreateCodeSet(std::string name, u64 program_id); SharedPtr CreateProcess(SharedPtr code_set); + + /** + * Creates and returns a new thread. The new thread is immediately scheduled + * @param name The friendly name desired for the thread + * @param entry_point The address at which the thread should start execution + * @param priority The thread's priority + * @param arg User data to pass to the thread + * @param processor_id The ID(s) of the processors on which the thread is desired to be run + * @param stack_top The address of the thread's stack top + * @param owner_process The parent process for the thread + * @return A shared pointer to the newly created thread + */ + ResultVal> CreateThread(std::string name, VAddr entry_point, u32 priority, + u32 arg, s32 processor_id, VAddr stack_top, + SharedPtr owner_process); }; } // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 3e95cc6f7..5d1b9389a 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -155,7 +155,7 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { status = ProcessStatus::Running; vm_manager.LogLayout(Log::Level::Debug); - Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority, this); + Kernel::SetupMainThread(kernel, codeset->entrypoint, main_thread_priority, this); } VAddr Process::GetLinearHeapAreaAddress() const { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 8ea242e6d..e61bf53b0 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -761,9 +761,9 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point break; } - CASCADE_RESULT(SharedPtr thread, - Thread::Create(name, entry_point, priority, arg, processor_id, stack_top, - g_current_process)); + CASCADE_RESULT(SharedPtr thread, Core::System::GetInstance().Kernel().CreateThread( + name, entry_point, priority, arg, processor_id, + stack_top, g_current_process)); thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO); // 0x03C00000 diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 50fa061c4..bf7a18685 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -60,7 +60,7 @@ inline static u32 const NewThreadId() { return next_thread_id++; } -Thread::Thread() : context(Core::CPU().NewContext()) {} +Thread::Thread(KernelSystem&) : context(Core::CPU().NewContext()) {} Thread::~Thread() {} Thread* GetCurrentThread() { @@ -320,9 +320,10 @@ static void ResetThreadContext(const std::unique_ptrSetCpsr(USER32MODE | ((entry_point & 1) << 5)); // Usermode and THUMB mode } -ResultVal> Thread::Create(std::string name, VAddr entry_point, u32 priority, - u32 arg, s32 processor_id, VAddr stack_top, - SharedPtr owner_process) { +ResultVal> KernelSystem::CreateThread(std::string name, VAddr entry_point, + u32 priority, u32 arg, s32 processor_id, + VAddr stack_top, + SharedPtr owner_process) { // Check if priority is in ranged. Lowest priority -> highest priority id. if (priority > ThreadPrioLowest) { LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); @@ -343,7 +344,7 @@ ResultVal> Thread::Create(std::string name, VAddr entry_point, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } - SharedPtr thread(new Thread); + SharedPtr thread(new Thread(*this)); thread_list.push_back(thread); ready_queue.prepare(priority); @@ -443,11 +444,12 @@ void Thread::BoostPriority(u32 priority) { current_priority = priority; } -SharedPtr SetupMainThread(u32 entry_point, u32 priority, SharedPtr owner_process) { +SharedPtr SetupMainThread(KernelSystem& kernel, u32 entry_point, u32 priority, + SharedPtr owner_process) { // Initialize new "main" thread auto thread_res = - Thread::Create("main", entry_point, priority, 0, owner_process->ideal_processor, - Memory::HEAP_VADDR_END, owner_process); + kernel.CreateThread("main", entry_point, priority, 0, owner_process->ideal_processor, + Memory::HEAP_VADDR_END, owner_process); SharedPtr thread = std::move(thread_res).Unwrap(); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 3fd72563f..9e6a22759 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -55,21 +55,6 @@ enum class ThreadWakeupReason { class Thread final : public WaitObject { public: - /** - * Creates and returns a new thread. The new thread is immediately scheduled - * @param name The friendly name desired for the thread - * @param entry_point The address at which the thread should start execution - * @param priority The thread's priority - * @param arg User data to pass to the thread - * @param processor_id The ID(s) of the processors on which the thread is desired to be run - * @param stack_top The address of the thread's stack top - * @param owner_process The parent process for the thread - * @return A shared pointer to the newly created thread - */ - static ResultVal> Create(std::string name, VAddr entry_point, u32 priority, - u32 arg, s32 processor_id, VAddr stack_top, - SharedPtr owner_process); - std::string GetName() const override { return name; } @@ -225,18 +210,22 @@ public: std::function wakeup_callback; private: - Thread(); + explicit Thread(KernelSystem&); ~Thread() override; + + friend class KernelSystem; }; /** * Sets up the primary application thread + * @param kernel The kernel instance on which the thread is created * @param entry_point The address at which the thread should start execution * @param priority The priority to give the main thread * @param owner_process The parent process for the main thread * @return A shared pointer to the main thread */ -SharedPtr SetupMainThread(u32 entry_point, u32 priority, SharedPtr owner_process); +SharedPtr SetupMainThread(KernelSystem& kernel, u32 entry_point, u32 priority, + SharedPtr owner_process); /** * Returns whether there are any threads that are ready to run. From 181646679c414ce4dd4bfb1e7d9c1a335c8073d9 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Fri, 12 Oct 2018 16:11:51 -0400 Subject: [PATCH 017/102] ServiceManager: pass down core reference --- src/core/core.cpp | 2 +- src/core/hle/service/service.cpp | 4 ++-- src/core/hle/service/service.h | 2 +- src/core/hle/service/sm/sm.cpp | 9 +++++---- src/core/hle/service/sm/sm.h | 6 +++++- src/core/hle/service/sm/srv.cpp | 10 +++++----- src/core/hle/service/sm/srv.h | 8 ++++++-- 7 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index d5445b438..6ae8345d4 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -197,7 +197,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { HW::Init(); kernel = std::make_unique(system_mode); - Service::Init(*this, service_manager); + Service::Init(*this); GDBStub::Init(); ResultStatus result = VideoCore::Init(emu_window); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 5755d0335..459629975 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -235,8 +235,8 @@ static bool AttemptLLE(const ServiceModuleInfo& service_module) { } /// Initialize ServiceManager -void Init(Core::System& core, std::shared_ptr& sm) { - SM::ServiceManager::InstallInterfaces(sm); +void Init(Core::System& core) { + SM::ServiceManager::InstallInterfaces(core); for (const auto& service_module : service_module_map) { if (!AttemptLLE(service_module) && service_module.init_function != nullptr) diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 3a8634251..dbe6e207c 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -184,7 +184,7 @@ private: }; /// Initialize ServiceManager -void Init(Core::System& system, std::shared_ptr& sm); +void Init(Core::System& system); /// Shutdown ServiceManager void Shutdown(); diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 588de7daa..cd3b4ee30 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -4,6 +4,7 @@ #include #include "common/assert.h" +#include "core/core.h" #include "core/hle/kernel/client_session.h" #include "core/hle/result.h" #include "core/hle/service/sm/sm.h" @@ -21,12 +22,12 @@ static ResultCode ValidateServiceName(const std::string& name) { return RESULT_SUCCESS; } -void ServiceManager::InstallInterfaces(std::shared_ptr self) { - ASSERT(self->srv_interface.expired()); +void ServiceManager::InstallInterfaces(Core::System& system) { + ASSERT(system.ServiceManager().srv_interface.expired()); - auto srv = std::make_shared(self); + auto srv = std::make_shared(system); srv->InstallAsNamedPort(); - self->srv_interface = srv; + system.ServiceManager().srv_interface = srv; } ResultVal> ServiceManager::RegisterService( diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 9e9164a66..c0666aeec 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -14,6 +14,10 @@ #include "core/hle/result.h" #include "core/hle/service/service.h" +namespace Core { +class System; +} + namespace Kernel { class ClientSession; class SessionRequestHandler; @@ -39,7 +43,7 @@ constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorDescription::AlreadyExists, Err class ServiceManager { public: - static void InstallInterfaces(std::shared_ptr self); + static void InstallInterfaces(Core::System& system); ResultVal> RegisterService(std::string name, unsigned int max_sessions); diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp index ca723745f..83fb94418 100644 --- a/src/core/hle/service/sm/srv.cpp +++ b/src/core/hle/service/sm/srv.cpp @@ -5,6 +5,7 @@ #include #include "common/common_types.h" #include "common/logging/log.h" +#include "core/core.h" #include "core/hle/ipc.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/client_port.h" @@ -103,7 +104,7 @@ void SRV::GetServiceHandle(Kernel::HLERequestContext& ctx) { Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) { LOG_ERROR(Service_SRV, "called service={} wakeup", name); - auto client_port = service_manager->GetServicePort(name); + auto client_port = system.ServiceManager().GetServicePort(name); auto session = client_port.Unwrap()->Connect(); if (session.Succeeded()) { @@ -122,7 +123,7 @@ void SRV::GetServiceHandle(Kernel::HLERequestContext& ctx) { } }; - auto client_port = service_manager->GetServicePort(name); + auto client_port = system.ServiceManager().GetServicePort(name); if (client_port.Failed()) { if (wait_until_available && client_port.Code() == ERR_SERVICE_NOT_REGISTERED) { LOG_INFO(Service_SRV, "called service={} delayed", name); @@ -223,7 +224,7 @@ void SRV::RegisterService(Kernel::HLERequestContext& ctx) { std::string name(name_buf.data(), std::min(name_len, name_buf.size())); - auto port = service_manager->RegisterService(name, max_sessions); + auto port = system.ServiceManager().RegisterService(name, max_sessions); if (port.Failed()) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); @@ -243,8 +244,7 @@ void SRV::RegisterService(Kernel::HLERequestContext& ctx) { rb.PushMoveObjects(port.Unwrap()); } -SRV::SRV(std::shared_ptr service_manager) - : ServiceFramework("srv:", 4), service_manager(std::move(service_manager)) { +SRV::SRV(Core::System& system) : ServiceFramework("srv:", 4), system(system) { static const FunctionInfo functions[] = { {0x00010002, &SRV::RegisterClient, "RegisterClient"}, {0x00020000, &SRV::EnableNotification, "EnableNotification"}, diff --git a/src/core/hle/service/sm/srv.h b/src/core/hle/service/sm/srv.h index 066d00eac..02d72ec49 100644 --- a/src/core/hle/service/sm/srv.h +++ b/src/core/hle/service/sm/srv.h @@ -8,6 +8,10 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/service/service.h" +namespace Core { +class System; +} + namespace Kernel { class HLERequestContext; class Semaphore; @@ -18,7 +22,7 @@ namespace Service::SM { /// Interface to "srv:" service class SRV final : public ServiceFramework { public: - explicit SRV(std::shared_ptr service_manager); + explicit SRV(Core::System& system); ~SRV(); private: @@ -30,7 +34,7 @@ private: void PublishToSubscriber(Kernel::HLERequestContext& ctx); void RegisterService(Kernel::HLERequestContext& ctx); - std::shared_ptr service_manager; + Core::System& system; Kernel::SharedPtr notification_semaphore; std::unordered_map> get_service_handle_delayed_map; From 247249d5d3a4974a5bf7d8e712fe23048925bbdf Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Fri, 12 Oct 2018 16:12:08 -0400 Subject: [PATCH 018/102] Kernel: pass ref to sempahore --- src/core/hle/kernel/kernel.h | 11 +++++++++++ src/core/hle/kernel/semaphore.cpp | 8 ++++---- src/core/hle/kernel/semaphore.h | 14 +++----------- src/core/hle/kernel/svc.cpp | 3 ++- src/core/hle/service/sm/srv.cpp | 2 +- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index aca8a5fab..beff0c31a 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -17,6 +17,7 @@ class Mutex; class CodeSet; class Process; class Thread; +class Semaphore; enum class ResetType { OneShot, @@ -73,6 +74,16 @@ public: ResultVal> CreateThread(std::string name, VAddr entry_point, u32 priority, u32 arg, s32 processor_id, VAddr stack_top, SharedPtr owner_process); + + /** + * Creates a semaphore. + * @param initial_count Number of slots reserved for other threads + * @param max_count Maximum number of slots the semaphore can have + * @param name Optional name of semaphore + * @return The created semaphore + */ + ResultVal> CreateSemaphore(s32 initial_count, s32 max_count, + std::string name = "Unknown"); }; } // namespace Kernel diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 4ec1669ba..afe770a64 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -10,16 +10,16 @@ namespace Kernel { -Semaphore::Semaphore() {} +Semaphore::Semaphore(KernelSystem& kernel) {} Semaphore::~Semaphore() {} -ResultVal> Semaphore::Create(s32 initial_count, s32 max_count, - std::string name) { +ResultVal> KernelSystem::CreateSemaphore(s32 initial_count, s32 max_count, + std::string name) { if (initial_count > max_count) return ERR_INVALID_COMBINATION_KERNEL; - SharedPtr semaphore(new Semaphore); + SharedPtr semaphore(new Semaphore(*this)); // When the semaphore is created, some slots are reserved for other threads, // and the rest is reserved for the caller thread diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h index 6019b09a2..7303ee7d1 100644 --- a/src/core/hle/kernel/semaphore.h +++ b/src/core/hle/kernel/semaphore.h @@ -15,16 +15,6 @@ namespace Kernel { class Semaphore final : public WaitObject { public: - /** - * Creates a semaphore. - * @param initial_count Number of slots reserved for other threads - * @param max_count Maximum number of slots the semaphore can have - * @param name Optional name of semaphore - * @return The created semaphore - */ - static ResultVal> Create(s32 initial_count, s32 max_count, - std::string name = "Unknown"); - std::string GetTypeName() const override { return "Semaphore"; } @@ -52,8 +42,10 @@ public: ResultVal Release(s32 release_count); private: - Semaphore(); + explicit Semaphore(KernelSystem& kernel); ~Semaphore() override; + + friend class KernelSystem; }; } // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index e61bf53b0..228e12ee8 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -891,7 +891,8 @@ static ResultCode GetThreadId(u32* thread_id, Handle handle) { /// Creates a semaphore static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) { - CASCADE_RESULT(SharedPtr semaphore, Semaphore::Create(initial_count, max_count)); + CASCADE_RESULT(SharedPtr semaphore, + Core::System::GetInstance().Kernel().CreateSemaphore(initial_count, max_count)); semaphore->name = fmt::format("semaphore-{:08x}", Core::CPU().GetReg(14)); CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(semaphore))); diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp index 83fb94418..07b47ea9b 100644 --- a/src/core/hle/service/sm/srv.cpp +++ b/src/core/hle/service/sm/srv.cpp @@ -63,7 +63,7 @@ void SRV::EnableNotification(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x2, 0, 0); notification_semaphore = - Kernel::Semaphore::Create(0, MAX_PENDING_NOTIFICATIONS, "SRV:Notification").Unwrap(); + system.Kernel().CreateSemaphore(0, MAX_PENDING_NOTIFICATIONS, "SRV:Notification").Unwrap(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(RESULT_SUCCESS); From c141657d83ecdfb99da76768c6bfc7d915b7238b Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Fri, 12 Oct 2018 16:26:23 -0400 Subject: [PATCH 019/102] Kernel: pass ref to timer --- src/core/hle/kernel/kernel.h | 9 +++++++++ src/core/hle/kernel/svc.cpp | 4 ++-- src/core/hle/kernel/timer.cpp | 6 +++--- src/core/hle/kernel/timer.h | 12 +++--------- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index beff0c31a..fbf1c338c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -18,6 +18,7 @@ class CodeSet; class Process; class Thread; class Semaphore; +class Timer; enum class ResetType { OneShot, @@ -84,6 +85,14 @@ public: */ ResultVal> CreateSemaphore(s32 initial_count, s32 max_count, std::string name = "Unknown"); + + /** + * Creates a timer + * @param reset_type ResetType describing how to create the timer + * @param name Optional name of timer + * @return The created Timer + */ + SharedPtr CreateTimer(ResetType reset_type, std::string name = "Unknown"); }; } // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 228e12ee8..99df081b2 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -986,8 +986,8 @@ static ResultCode ClearEvent(Handle handle) { /// Creates a timer static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { - SharedPtr timer = Timer::Create(static_cast(reset_type), - fmt ::format("timer-{:08x}", Core::CPU().GetReg(14))); + SharedPtr timer = Core::System::GetInstance().Kernel().CreateTimer( + static_cast(reset_type), fmt ::format("timer-{:08x}", Core::CPU().GetReg(14))); CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(timer))); LOG_TRACE(Kernel_SVC, "called reset_type=0x{:08X} : created handle=0x{:08X}", reset_type, diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index f1965365c..b229a94af 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -19,11 +19,11 @@ static CoreTiming::EventType* timer_callback_event_type = nullptr; // us to simply use a pool index or similar. static Kernel::HandleTable timer_callback_handle_table; -Timer::Timer() {} +Timer::Timer(KernelSystem& kernel) {} Timer::~Timer() {} -SharedPtr Timer::Create(ResetType reset_type, std::string name) { - SharedPtr timer(new Timer); +SharedPtr KernelSystem::CreateTimer(ResetType reset_type, std::string name) { + SharedPtr timer(new Timer(*this)); timer->reset_type = reset_type; timer->signaled = false; diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h index 6607f6058..c039bb4f1 100644 --- a/src/core/hle/kernel/timer.h +++ b/src/core/hle/kernel/timer.h @@ -12,14 +12,6 @@ namespace Kernel { class Timer final : public WaitObject { public: - /** - * Creates a timer - * @param reset_type ResetType describing how to create the timer - * @param name Optional name of timer - * @return The created Timer - */ - static SharedPtr Create(ResetType reset_type, std::string name = "Unknown"); - std::string GetTypeName() const override { return "Timer"; } @@ -68,7 +60,7 @@ public: void Signal(s64 cycles_late); private: - Timer(); + explicit Timer(KernelSystem& kernel); ~Timer() override; ResetType reset_type; ///< The ResetType of this timer @@ -81,6 +73,8 @@ private: /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. Handle callback_handle; + + friend class KernelSystem; }; /// Initializes the required variables for timers From 1213a298df9e130bdb453707939e6709d1689a91 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Fri, 12 Oct 2018 19:00:16 -0400 Subject: [PATCH 020/102] Kernel: pass ref to port --- src/core/core.cpp | 2 +- src/core/hle/kernel/client_port.cpp | 2 +- src/core/hle/kernel/client_port.h | 4 +++- src/core/hle/kernel/kernel.h | 12 ++++++++++++ src/core/hle/kernel/server_port.cpp | 8 ++++---- src/core/hle/kernel/server_port.h | 14 +++----------- src/core/hle/kernel/svc.cpp | 2 +- src/core/hle/service/err_f.cpp | 2 +- src/core/hle/service/service.cpp | 4 ++-- src/core/hle/service/service.h | 3 ++- src/core/hle/service/sm/sm.cpp | 6 ++++-- src/core/hle/service/sm/sm.h | 3 +++ 12 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 6ae8345d4..6212347e2 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -191,7 +191,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { rpc_server = std::make_unique(); #endif - service_manager = std::make_shared(); + service_manager = std::make_shared(*this); shared_page_handler = std::make_shared(); archive_manager = std::make_unique(); diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index e45494db2..f70b84ae2 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -13,7 +13,7 @@ namespace Kernel { -ClientPort::ClientPort() = default; +ClientPort::ClientPort(KernelSystem& kernel) {} ClientPort::~ClientPort() = default; ResultVal> ClientPort::Connect() { diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index 46227347e..2dda05f15 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -48,13 +48,15 @@ public: void ConnectionClosed(); private: - ClientPort(); + explicit ClientPort(KernelSystem& kernel); ~ClientPort() override; SharedPtr server_port; ///< ServerPort associated with this client port. u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have u32 active_sessions = 0; ///< Number of currently open sessions to this port std::string name; ///< Name of client port (optional) + + friend class KernelSystem; }; } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index fbf1c338c..79b939c07 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -19,6 +19,8 @@ class Process; class Thread; class Semaphore; class Timer; +class ClientPort; +class ServerPort; enum class ResetType { OneShot, @@ -93,6 +95,16 @@ public: * @return The created Timer */ SharedPtr CreateTimer(ResetType reset_type, std::string name = "Unknown"); + + /** + * Creates a pair of ServerPort and an associated ClientPort. + * + * @param max_sessions Maximum number of sessions to the port + * @param name Optional name of the ports + * @return The created port tuple + */ + std::tuple, SharedPtr> CreatePortPair( + u32 max_sessions, std::string name = "UnknownPort"); }; } // namespace Kernel diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 7b6211fd8..44a5ca841 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -13,7 +13,7 @@ namespace Kernel { -ServerPort::ServerPort() {} +ServerPort::ServerPort(KernelSystem& kernel) {} ServerPort::~ServerPort() {} ResultVal> ServerPort::Accept() { @@ -35,11 +35,11 @@ void ServerPort::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); } -std::tuple, SharedPtr> ServerPort::CreatePortPair( +std::tuple, SharedPtr> KernelSystem::CreatePortPair( u32 max_sessions, std::string name) { - SharedPtr server_port(new ServerPort); - SharedPtr client_port(new ClientPort); + SharedPtr server_port(new ServerPort(*this)); + SharedPtr client_port(new ClientPort(*this)); server_port->name = name + "_Server"; client_port->name = name + "_Client"; diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index 6d458b188..ee09efba1 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -20,16 +20,6 @@ class SessionRequestHandler; class ServerPort final : public WaitObject { public: - /** - * Creates a pair of ServerPort and an associated ClientPort. - * - * @param max_sessions Maximum number of sessions to the port - * @param name Optional name of the ports - * @return The created port tuple - */ - static std::tuple, SharedPtr> CreatePortPair( - u32 max_sessions, std::string name = "UnknownPort"); - std::string GetTypeName() const override { return "ServerPort"; } @@ -69,8 +59,10 @@ public: void Acquire(Thread* thread) override; private: - ServerPort(); + explicit ServerPort(KernelSystem& kernel); ~ServerPort() override; + + friend class KernelSystem; }; } // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 99df081b2..0c2e0c160 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1119,7 +1119,7 @@ static ResultCode CreatePort(Handle* server_port, Handle* client_port, VAddr nam // TODO(Subv): Implement named ports. ASSERT_MSG(name_address == 0, "Named ports are currently unimplemented"); - auto ports = ServerPort::CreatePortPair(max_sessions); + auto ports = Core::System::GetInstance().Kernel().CreatePortPair(max_sessions); CASCADE_RESULT(*client_port, g_handle_table.Create(std::move(std::get>(ports)))); // Note: The 3DS kernel also leaks the client port handle if the server port handle fails to be diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp index 9a914ee7b..13b2c7e46 100644 --- a/src/core/hle/service/err_f.cpp +++ b/src/core/hle/service/err_f.cpp @@ -244,7 +244,7 @@ ERR_F::~ERR_F() = default; void InstallInterfaces(Core::System& system) { auto errf = std::make_shared(system); - errf->InstallAsNamedPort(); + errf->InstallAsNamedPort(system.Kernel()); } } // namespace Service::ERR diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 459629975..6bdafd0e8 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -143,11 +143,11 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) port->SetHleHandler(shared_from_this()); } -void ServiceFrameworkBase::InstallAsNamedPort() { +void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelSystem& kernel) { ASSERT(port == nullptr); SharedPtr server_port; SharedPtr client_port; - std::tie(server_port, client_port) = ServerPort::CreatePortPair(max_sessions, service_name); + std::tie(server_port, client_port) = kernel.CreatePortPair(max_sessions, service_name); server_port->SetHleHandler(shared_from_this()); AddNamedPort(service_name, std::move(client_port)); } diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index dbe6e207c..5cb4fbf23 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -20,6 +20,7 @@ class System; } namespace Kernel { +class KernelSystem; class ClientPort; class ServerPort; class ServerSession; @@ -59,7 +60,7 @@ public: /// Creates a port pair and registers this service with the given ServiceManager. void InstallAsService(SM::ServiceManager& service_manager); /// Creates a port pair and registers it on the kernel's global port registry. - void InstallAsNamedPort(); + void InstallAsNamedPort(Kernel::KernelSystem& kernel); void HandleSyncRequest(Kernel::SharedPtr server_session) override; diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index cd3b4ee30..81819c9bd 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -22,11 +22,13 @@ static ResultCode ValidateServiceName(const std::string& name) { return RESULT_SUCCESS; } +ServiceManager::ServiceManager(Core::System& system) : system(system) {} + void ServiceManager::InstallInterfaces(Core::System& system) { ASSERT(system.ServiceManager().srv_interface.expired()); auto srv = std::make_shared(system); - srv->InstallAsNamedPort(); + srv->InstallAsNamedPort(system.Kernel()); system.ServiceManager().srv_interface = srv; } @@ -40,7 +42,7 @@ ResultVal> ServiceManager::RegisterService Kernel::SharedPtr server_port; Kernel::SharedPtr client_port; - std::tie(server_port, client_port) = Kernel::ServerPort::CreatePortPair(max_sessions, name); + std::tie(server_port, client_port) = system.Kernel().CreatePortPair(max_sessions, name); registered_services.emplace(std::move(name), std::move(client_port)); return MakeResult>(std::move(server_port)); diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index c0666aeec..f3cf40756 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -45,6 +45,8 @@ class ServiceManager { public: static void InstallInterfaces(Core::System& system); + explicit ServiceManager(Core::System& system); + ResultVal> RegisterService(std::string name, unsigned int max_sessions); ResultVal> GetServicePort(const std::string& name); @@ -67,6 +69,7 @@ public: } private: + Core::System& system; std::weak_ptr srv_interface; /// Map of registered services, retrieved using GetServicePort or ConnectToService. From 13c26b43719977cc18b6f4a913b63142637514be Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sat, 13 Oct 2018 16:11:20 -0400 Subject: [PATCH 021/102] Kernel: pass ref to session pair --- src/core/core.cpp | 2 +- src/core/hle/kernel/client_port.cpp | 4 ++-- src/core/hle/kernel/client_port.h | 1 + src/core/hle/kernel/client_session.cpp | 2 +- src/core/hle/kernel/client_session.h | 5 ++--- src/core/hle/kernel/kernel.h | 11 +++++++++++ src/core/hle/kernel/server_session.cpp | 14 +++++++------- src/core/hle/kernel/server_session.h | 19 ++++++------------- src/core/hle/kernel/svc.cpp | 2 +- src/core/hle/service/am/am.cpp | 10 +++++----- src/core/hle/service/am/am.h | 1 + src/core/hle/service/fs/archive.cpp | 4 ++-- src/core/hle/service/fs/archive.h | 9 ++++++++- src/core/hle/service/fs/file.cpp | 12 +++++++----- src/core/hle/service/fs/file.h | 9 ++++++++- src/core/hle/service/fs/fs_user.cpp | 7 ++++--- src/core/hle/service/fs/fs_user.h | 3 ++- src/tests/core/hle/kernel/hle_ipc.cpp | 4 ++-- 18 files changed, 71 insertions(+), 48 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 6212347e2..4d4379299 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -193,7 +193,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { service_manager = std::make_shared(*this); shared_page_handler = std::make_shared(); - archive_manager = std::make_unique(); + archive_manager = std::make_unique(*this); HW::Init(); kernel = std::make_unique(system_mode); diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index f70b84ae2..bfbfc3720 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -13,7 +13,7 @@ namespace Kernel { -ClientPort::ClientPort(KernelSystem& kernel) {} +ClientPort::ClientPort(KernelSystem& kernel) : kernel(kernel) {} ClientPort::~ClientPort() = default; ResultVal> ClientPort::Connect() { @@ -26,7 +26,7 @@ ResultVal> ClientPort::Connect() { active_sessions++; // Create a new session pair, let the created sessions inherit the parent port's HLE handler. - auto sessions = ServerSession::CreateSessionPair(server_port->GetName(), this); + auto sessions = kernel.CreateSessionPair(server_port->GetName(), this); if (server_port->hle_handler) server_port->hle_handler->ClientConnected(std::get>(sessions)); diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index 2dda05f15..149ca77a1 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -51,6 +51,7 @@ private: explicit ClientPort(KernelSystem& kernel); ~ClientPort() override; + KernelSystem& kernel; SharedPtr server_port; ///< ServerPort associated with this client port. u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have u32 active_sessions = 0; ///< Number of currently open sessions to this port diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 17f4c12d3..c2c3634ba 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -13,7 +13,7 @@ namespace Kernel { -ClientSession::ClientSession() = default; +ClientSession::ClientSession(KernelSystem& kernel) {} ClientSession::~ClientSession() { // This destructor will be called automatically when the last ClientSession handle is closed by // the emulated application. diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index 9c6b47927..5d5a2d9cd 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -12,13 +12,12 @@ namespace Kernel { -class ServerSession; class Session; class Thread; class ClientSession final : public Object { public: - friend class ServerSession; + friend class KernelSystem; std::string GetTypeName() const override { return "ClientSession"; @@ -46,7 +45,7 @@ public: std::shared_ptr parent; private: - ClientSession(); + explicit ClientSession(KernelSystem& kernel); ~ClientSession() override; }; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 79b939c07..9ff8504e0 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -21,6 +21,8 @@ class Semaphore; class Timer; class ClientPort; class ServerPort; +class ClientSession; +class ServerSession; enum class ResetType { OneShot, @@ -105,6 +107,15 @@ public: */ std::tuple, SharedPtr> CreatePortPair( u32 max_sessions, std::string name = "UnknownPort"); + + /** + * Creates a pair of ServerSession and an associated ClientSession. + * @param name Optional name of the ports. + * @param client_port Optional The ClientPort that spawned this session. + * @return The created session tuple + */ + std::tuple, SharedPtr> CreateSessionPair( + const std::string& name = "Unknown", SharedPtr client_port = nullptr); }; } // namespace Kernel diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 71f702b9e..3382abae3 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -13,7 +13,7 @@ namespace Kernel { -ServerSession::ServerSession() = default; +ServerSession::ServerSession(KernelSystem& kernel) {} ServerSession::~ServerSession() { // This destructor will be called automatically when the last ServerSession handle is closed by // the emulated application. @@ -28,8 +28,8 @@ ServerSession::~ServerSession() { parent->server = nullptr; } -ResultVal> ServerSession::Create(std::string name) { - SharedPtr server_session(new ServerSession); +ResultVal> ServerSession::Create(KernelSystem& kernel, std::string name) { + SharedPtr server_session(new ServerSession(kernel)); server_session->name = std::move(name); server_session->parent = nullptr; @@ -100,10 +100,10 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr thread) { return RESULT_SUCCESS; } -ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& name, - SharedPtr port) { - auto server_session = ServerSession::Create(name + "_Server").Unwrap(); - SharedPtr client_session(new ClientSession); +std::tuple, SharedPtr> KernelSystem::CreateSessionPair( + const std::string& name, SharedPtr port) { + auto server_session = ServerSession::Create(*this, name + "_Server").Unwrap(); + SharedPtr client_session(new ClientSession(*this)); client_session->name = name + "_Client"; std::shared_ptr parent(new Session); diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index c739bae5e..18411e417 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -48,17 +48,6 @@ public: return HANDLE_TYPE; } - using SessionPair = std::tuple, SharedPtr>; - - /** - * Creates a pair of ServerSession and an associated ClientSession. - * @param name Optional name of the ports. - * @param client_port Optional The ClientPort that spawned this session. - * @return The created session tuple - */ - static SessionPair CreateSessionPair(const std::string& name = "Unknown", - SharedPtr client_port = nullptr); - /** * Sets the HLE handler for the session. This handler will be called to service IPC requests * instead of the regular IPC machinery. (The regular IPC machinery is currently not @@ -95,16 +84,20 @@ public: SharedPtr currently_handling; private: - ServerSession(); + explicit ServerSession(KernelSystem& kernel); ~ServerSession() override; /** * Creates a server session. The server session can have an optional HLE handler, * which will be invoked to handle the IPC requests that this session receives. + * @param kernel The kernel instance to create the server session on * @param name Optional name of the server session. * @return The created server session */ - static ResultVal> Create(std::string name = "Unknown"); + static ResultVal> Create(KernelSystem& kernel, + std::string name = "Unknown"); + + friend class KernelSystem; }; } // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 0c2e0c160..632d2e539 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1142,7 +1142,7 @@ static ResultCode CreateSessionToPort(Handle* out_client_session, Handle client_ } static ResultCode CreateSession(Handle* server_session, Handle* client_session) { - auto sessions = ServerSession::CreateSessionPair(); + auto sessions = Core::System::GetInstance().Kernel().CreateSessionPair(); auto& server = std::get>(sessions); CASCADE_RESULT(*server_session, g_handle_table.Create(std::move(server))); diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index e9f0c6227..972c826a9 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1026,8 +1026,8 @@ void Module::Interface::BeginImportProgram(Kernel::HLERequestContext& ctx) { // Create our CIAFile handle for the app to write to, and while the app writes // Citra will store contents out to sdmc/nand const FileSys::Path cia_path = {}; - auto file = - std::make_shared(std::make_unique(media_type), cia_path); + auto file = std::make_shared( + am->system, std::make_unique(media_type), cia_path); am->cia_installing = true; @@ -1053,8 +1053,8 @@ void Module::Interface::BeginImportProgramTemporarily(Kernel::HLERequestContext& // Create our CIAFile handle for the app to write to, and while the app writes Citra will store // contents out to sdmc/nand const FileSys::Path cia_path = {}; - auto file = std::make_shared(std::make_unique(FS::MediaType::NAND), - cia_path); + auto file = std::make_shared( + am->system, std::make_unique(FS::MediaType::NAND), cia_path); am->cia_installing = true; @@ -1455,7 +1455,7 @@ void Module::Interface::GetMetaDataFromCia(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(output_buffer); } -Module::Module(Core::System& system) { +Module::Module(Core::System& system) : system(system) { ScanForAllTitles(); system_updater_mutex = system.Kernel().CreateMutex(false, "AM::SystemUpdaterMutex"); } diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 792225113..e00e16abd 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -573,6 +573,7 @@ private: */ void ScanForAllTitles(); + Core::System& system; bool cia_installing = false; std::array, 3> am_title_list; Kernel::SharedPtr system_updater_mutex; diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 0f2375124..4322f6653 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -87,7 +87,7 @@ ResultVal> ArchiveManager::OpenFileFromArchive(ArchiveHand if (backend.Failed()) return backend.Code(); - auto file = std::shared_ptr(new File(std::move(backend).Unwrap(), path)); + auto file = std::shared_ptr(new File(system, std::move(backend).Unwrap(), path)); return MakeResult>(std::move(file)); } @@ -348,7 +348,7 @@ void ArchiveManager::RegisterSelfNCCH(Loader::AppLoader& app_loader) { factory->Register(app_loader); } -ArchiveManager::ArchiveManager() { +ArchiveManager::ArchiveManager(Core::System& system) : system(system) { RegisterArchiveTypes(); } diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index ef9b9efc2..f335f650d 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -24,6 +24,10 @@ namespace Loader { class AppLoader; } +namespace Core { +class System; +} + namespace Service::FS { /// Supported archive types @@ -50,7 +54,8 @@ using FileSys::ArchiveFactory; class ArchiveManager { public: - ArchiveManager(); + explicit ArchiveManager(Core::System& system); + /** * Opens an archive * @param id_code IdCode of the archive to open @@ -224,6 +229,8 @@ public: void RegisterSelfNCCH(Loader::AppLoader& app_loader); private: + Core::System& system; + /** * Registers an Archive type, instances of which can later be opened using its IdCode. * @param factory File system backend interface to the archive diff --git a/src/core/hle/service/fs/file.cpp b/src/core/hle/service/fs/file.cpp index d2f1f2a85..59635cab8 100644 --- a/src/core/hle/service/fs/file.cpp +++ b/src/core/hle/service/fs/file.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "common/logging/log.h" +#include "core/core.h" #include "core/file_sys/errors.h" #include "core/file_sys/file_backend.h" #include "core/hle/ipc_helpers.h" @@ -14,8 +15,9 @@ namespace Service::FS { -File::File(std::unique_ptr&& backend, const FileSys::Path& path) - : ServiceFramework("", 1), path(path), backend(std::move(backend)) { +File::File(Core::System& system, std::unique_ptr&& backend, + const FileSys::Path& path) + : ServiceFramework("", 1), path(path), backend(std::move(backend)), system(system) { static const FunctionInfo functions[] = { {0x08010100, &File::OpenSubFile, "OpenSubFile"}, {0x080200C2, &File::Read, "Read"}, @@ -195,7 +197,7 @@ void File::OpenLinkFile(Kernel::HLERequestContext& ctx) { using Kernel::SharedPtr; IPC::RequestParser rp(ctx, 0x080C, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - auto sessions = ServerSession::CreateSessionPair(GetName()); + auto sessions = system.Kernel().CreateSessionPair(GetName()); auto server = std::get>(sessions); ClientConnected(server); @@ -243,7 +245,7 @@ void File::OpenSubFile(Kernel::HLERequestContext& ctx) { using Kernel::ClientSession; using Kernel::ServerSession; using Kernel::SharedPtr; - auto sessions = ServerSession::CreateSessionPair(GetName()); + auto sessions = system.Kernel().CreateSessionPair(GetName()); auto server = std::get>(sessions); ClientConnected(server); @@ -258,7 +260,7 @@ void File::OpenSubFile(Kernel::HLERequestContext& ctx) { } Kernel::SharedPtr File::Connect() { - auto sessions = Kernel::ServerSession::CreateSessionPair(GetName()); + auto sessions = system.Kernel().CreateSessionPair(GetName()); auto server = std::get>(sessions); ClientConnected(server); diff --git a/src/core/hle/service/fs/file.h b/src/core/hle/service/fs/file.h index 2de9add98..b946491b8 100644 --- a/src/core/hle/service/fs/file.h +++ b/src/core/hle/service/fs/file.h @@ -8,6 +8,10 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/service/service.h" +namespace Core { +class System; +} + namespace Service::FS { struct FileSessionSlot : public Kernel::SessionRequestHandler::SessionDataBase { @@ -21,7 +25,8 @@ struct FileSessionSlot : public Kernel::SessionRequestHandler::SessionDataBase { // Consider splitting ServiceFramework interface. class File final : public ServiceFramework { public: - File(std::unique_ptr&& backend, const FileSys::Path& path); + File(Core::System& system, std::unique_ptr&& backend, + const FileSys::Path& path); ~File() = default; std::string GetName() const { @@ -53,6 +58,8 @@ private: void GetPriority(Kernel::HLERequestContext& ctx); void OpenLinkFile(Kernel::HLERequestContext& ctx); void OpenSubFile(Kernel::HLERequestContext& ctx); + + Core::System& system; }; } // namespace Service::FS diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index e4a7c251d..7b1316e48 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -286,7 +286,7 @@ void FS_USER::OpenDirectory(Kernel::HLERequestContext& ctx) { rb.Push(dir_res.Code()); if (dir_res.Succeeded()) { std::shared_ptr directory = *dir_res; - auto sessions = ServerSession::CreateSessionPair(directory->GetName()); + auto sessions = system.Kernel().CreateSessionPair(directory->GetName()); directory->ClientConnected(std::get>(sessions)); rb.PushMoveObjects(std::get>(sessions)); } else { @@ -741,7 +741,8 @@ void FS_USER::GetSaveDataSecureValue(Kernel::HLERequestContext& ctx) { rb.Push(0); // the secure value } -FS_USER::FS_USER(ArchiveManager& archives) : ServiceFramework("fs:USER", 30), archives(archives) { +FS_USER::FS_USER(Core::System& system) + : ServiceFramework("fs:USER", 30), system(system), archives(system.ArchiveManager()) { static const FunctionInfo functions[] = { {0x000100C6, nullptr, "Dummy1"}, {0x040100C4, nullptr, "Control"}, @@ -860,6 +861,6 @@ FS_USER::FS_USER(ArchiveManager& archives) : ServiceFramework("fs:USER", 30), ar void InstallInterfaces(Core::System& system) { auto& service_manager = system.ServiceManager(); - std::make_shared(system.ArchiveManager())->InstallAsService(service_manager); + std::make_shared(system)->InstallAsService(service_manager); } } // namespace Service::FS diff --git a/src/core/hle/service/fs/fs_user.h b/src/core/hle/service/fs/fs_user.h index eb1b5af36..90c0ed7ec 100644 --- a/src/core/hle/service/fs/fs_user.h +++ b/src/core/hle/service/fs/fs_user.h @@ -17,7 +17,7 @@ class ArchiveManager; class FS_USER final : public ServiceFramework { public: - explicit FS_USER(ArchiveManager& archives); + explicit FS_USER(Core::System& system); private: void Initialize(Kernel::HLERequestContext& ctx); @@ -534,6 +534,7 @@ private: u32 priority = -1; ///< For SetPriority and GetPriority service functions + Core::System& system; ArchiveManager& archives; }; diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp index bb4c3b6ad..9e093f4e4 100644 --- a/src/tests/core/hle/kernel/hle_ipc.cpp +++ b/src/tests/core/hle/kernel/hle_ipc.cpp @@ -22,7 +22,7 @@ static SharedPtr MakeObject(Kernel::KernelSystem& kernel) { TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") { CoreTiming::Init(); Kernel::KernelSystem kernel(0); - auto session = std::get>(ServerSession::CreateSessionPair()); + auto session = std::get>(kernel.CreateSessionPair()); HLERequestContext context(std::move(session)); auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); @@ -232,7 +232,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { CoreTiming::Init(); Kernel::KernelSystem kernel(0); - auto session = std::get>(ServerSession::CreateSessionPair()); + auto session = std::get>(kernel.CreateSessionPair()); HLERequestContext context(std::move(session)); auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); From 2a411bb5019ea62ab2e7e114174b40c7af9dd5e0 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sat, 13 Oct 2018 16:41:34 -0400 Subject: [PATCH 022/102] Kernel: wrap resource limit state into kernel state; pass ref to resource limit --- src/core/hle/kernel/kernel.cpp | 11 ++++++++-- src/core/hle/kernel/kernel.h | 8 +++++++ src/core/hle/kernel/resource_limit.cpp | 22 +++++++++---------- src/core/hle/kernel/resource_limit.h | 30 +++++++++++++++----------- src/core/loader/3dsx.cpp | 4 ++-- src/core/loader/elf.cpp | 4 ++-- src/core/loader/ncch.cpp | 5 +++-- 7 files changed, 51 insertions(+), 33 deletions(-) diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 7991f77cf..8a8fa6709 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -22,7 +22,7 @@ KernelSystem::KernelSystem(u32 system_mode) { Kernel::MemoryInit(system_mode); - Kernel::ResourceLimitsInit(); + resource_limits = std::make_unique(*this); Kernel::ThreadingInit(); Kernel::TimersInit(); @@ -40,8 +40,15 @@ KernelSystem::~KernelSystem() { g_current_process = nullptr; Kernel::TimersShutdown(); - Kernel::ResourceLimitsShutdown(); Kernel::MemoryShutdown(); } +ResourceLimitList& KernelSystem::ResourceLimit() { + return *resource_limits; +} + +const ResourceLimitList& KernelSystem::ResourceLimit() const { + return *resource_limits; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 9ff8504e0..84a33d8e6 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include "common/common_types.h" @@ -23,6 +24,7 @@ class ClientPort; class ServerPort; class ClientSession; class ServerSession; +class ResourceLimitList; enum class ResetType { OneShot, @@ -116,6 +118,12 @@ public: */ std::tuple, SharedPtr> CreateSessionPair( const std::string& name = "Unknown", SharedPtr client_port = nullptr); + + ResourceLimitList& ResourceLimit(); + const ResourceLimitList& ResourceLimit() const; + +private: + std::unique_ptr resource_limits; }; } // namespace Kernel diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp index ffe9f5108..4aaf6be6b 100644 --- a/src/core/hle/kernel/resource_limit.cpp +++ b/src/core/hle/kernel/resource_limit.cpp @@ -9,19 +9,17 @@ namespace Kernel { -static SharedPtr resource_limits[4]; - -ResourceLimit::ResourceLimit() {} +ResourceLimit::ResourceLimit(KernelSystem& kernel) {} ResourceLimit::~ResourceLimit() {} -SharedPtr ResourceLimit::Create(std::string name) { - SharedPtr resource_limit(new ResourceLimit); +SharedPtr ResourceLimit::Create(KernelSystem& kernel, std::string name) { + SharedPtr resource_limit(new ResourceLimit(kernel)); resource_limit->name = std::move(name); return resource_limit; } -SharedPtr ResourceLimit::GetForCategory(ResourceLimitCategory category) { +SharedPtr ResourceLimitList::GetForCategory(ResourceLimitCategory category) { switch (category) { case ResourceLimitCategory::APPLICATION: case ResourceLimitCategory::SYS_APPLET: @@ -90,10 +88,10 @@ u32 ResourceLimit::GetMaxResourceValue(u32 resource) const { } } -void ResourceLimitsInit() { +ResourceLimitList::ResourceLimitList(KernelSystem& kernel) { // Create the four resource limits that the system uses // Create the APPLICATION resource limit - SharedPtr resource_limit = ResourceLimit::Create("Applications"); + SharedPtr resource_limit = ResourceLimit::Create(kernel, "Applications"); resource_limit->max_priority = 0x18; resource_limit->max_commit = 0x4000000; resource_limit->max_threads = 0x20; @@ -107,7 +105,7 @@ void ResourceLimitsInit() { resource_limits[static_cast(ResourceLimitCategory::APPLICATION)] = resource_limit; // Create the SYS_APPLET resource limit - resource_limit = ResourceLimit::Create("System Applets"); + resource_limit = ResourceLimit::Create(kernel, "System Applets"); resource_limit->max_priority = 0x4; resource_limit->max_commit = 0x5E00000; resource_limit->max_threads = 0x1D; @@ -121,7 +119,7 @@ void ResourceLimitsInit() { resource_limits[static_cast(ResourceLimitCategory::SYS_APPLET)] = resource_limit; // Create the LIB_APPLET resource limit - resource_limit = ResourceLimit::Create("Library Applets"); + resource_limit = ResourceLimit::Create(kernel, "Library Applets"); resource_limit->max_priority = 0x4; resource_limit->max_commit = 0x600000; resource_limit->max_threads = 0xE; @@ -135,7 +133,7 @@ void ResourceLimitsInit() { resource_limits[static_cast(ResourceLimitCategory::LIB_APPLET)] = resource_limit; // Create the OTHER resource limit - resource_limit = ResourceLimit::Create("Others"); + resource_limit = ResourceLimit::Create(kernel, "Others"); resource_limit->max_priority = 0x4; resource_limit->max_commit = 0x2180000; resource_limit->max_threads = 0xE1; @@ -149,6 +147,6 @@ void ResourceLimitsInit() { resource_limits[static_cast(ResourceLimitCategory::OTHER)] = resource_limit; } -void ResourceLimitsShutdown() {} +ResourceLimitList::~ResourceLimitList() = default; } // namespace Kernel diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h index 7d6e8611d..3b8b79d0c 100644 --- a/src/core/hle/kernel/resource_limit.h +++ b/src/core/hle/kernel/resource_limit.h @@ -4,6 +4,7 @@ #pragma once +#include #include "common/common_types.h" #include "core/hle/kernel/object.h" @@ -34,14 +35,7 @@ public: /** * Creates a resource limit object. */ - static SharedPtr Create(std::string name = "Unknown"); - - /** - * Retrieves the resource limit associated with the specified resource limit category. - * @param category The resource limit category - * @returns The resource limit associated with the category - */ - static SharedPtr GetForCategory(ResourceLimitCategory category); + static SharedPtr Create(KernelSystem& kernel, std::string name = "Unknown"); std::string GetTypeName() const override { return "ResourceLimit"; @@ -113,14 +107,24 @@ public: s32 current_cpu_time = 0; private: - ResourceLimit(); + explicit ResourceLimit(KernelSystem& kernel); ~ResourceLimit() override; }; -/// Initializes the resource limits -void ResourceLimitsInit(); +class ResourceLimitList { +public: + explicit ResourceLimitList(KernelSystem& kernel); + ~ResourceLimitList(); -// Destroys the resource limits -void ResourceLimitsShutdown(); + /** + * Retrieves the resource limit associated with the specified resource limit category. + * @param category The resource limit category + * @returns The resource limit associated with the category + */ + SharedPtr GetForCategory(ResourceLimitCategory category); + +private: + std::array, 4> resource_limits; +}; } // namespace Kernel diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index 486270a59..1b3905b02 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp @@ -272,8 +272,8 @@ ResultStatus AppLoader_THREEDSX::Load(Kernel::SharedPtr& proces process->address_mappings = default_address_mappings; // Attach the default resource limit (APPLICATION) to the process - process->resource_limit = - Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); + process->resource_limit = Core::System::GetInstance().Kernel().ResourceLimit().GetForCategory( + Kernel::ResourceLimitCategory::APPLICATION); process->Run(48, Kernel::DEFAULT_STACK_SIZE); diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 86abd7763..26470ff9d 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -401,8 +401,8 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr& process) { process->address_mappings = default_address_mappings; // Attach the default resource limit (APPLICATION) to the process - process->resource_limit = - Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); + process->resource_limit = Core::System::GetInstance().Kernel().ResourceLimit().GetForCategory( + Kernel::ResourceLimitCategory::APPLICATION); process->Run(48, Kernel::DEFAULT_STACK_SIZE); diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 10260591a..34f49663a 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -108,8 +108,9 @@ ResultStatus AppLoader_NCCH::LoadExec(Kernel::SharedPtr& proces // Attach a resource limit to the process based on the resource limit category process->resource_limit = - Kernel::ResourceLimit::GetForCategory(static_cast( - overlay_ncch->exheader_header.arm11_system_local_caps.resource_limit_category)); + Core::System::GetInstance().Kernel().ResourceLimit().GetForCategory( + static_cast( + overlay_ncch->exheader_header.arm11_system_local_caps.resource_limit_category)); // Set the default CPU core for this process process->ideal_processor = From 87426b29ffa4329c8a47ac8ee661b0074b3d5ee1 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sat, 13 Oct 2018 17:08:37 -0400 Subject: [PATCH 023/102] kernel: pass ref to shared memory --- src/core/hle/applets/erreula.cpp | 3 +- src/core/hle/applets/mii_selector.cpp | 3 +- src/core/hle/applets/mint.cpp | 3 +- src/core/hle/applets/swkbd.cpp | 3 +- src/core/hle/kernel/kernel.h | 55 ++++++++++++++++++++++++++ src/core/hle/kernel/process.h | 6 --- src/core/hle/kernel/shared_memory.cpp | 23 ++++++----- src/core/hle/kernel/shared_memory.h | 51 ++---------------------- src/core/hle/kernel/svc.cpp | 6 +-- src/core/hle/service/apt/apt.cpp | 6 +-- src/core/hle/service/csnd/csnd_snd.cpp | 6 +-- src/core/hle/service/gsp/gsp_gpu.cpp | 6 +-- src/core/hle/service/hid/hid.cpp | 6 +-- src/core/hle/service/ir/ir_rst.cpp | 6 +-- 14 files changed, 95 insertions(+), 88 deletions(-) diff --git a/src/core/hle/applets/erreula.cpp b/src/core/hle/applets/erreula.cpp index a8135a2ae..7b8cf1d02 100644 --- a/src/core/hle/applets/erreula.cpp +++ b/src/core/hle/applets/erreula.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "common/string_util.h" +#include "core/core.h" #include "core/hle/applets/erreula.h" #include "core/hle/service/apt/apt.h" @@ -30,7 +31,7 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param // Allocate a heap block of the required size for this applet. heap_memory = std::make_shared>(capture_info.size); // Create a SharedMemory that directly points to this heap block. - framebuffer_memory = Kernel::SharedMemory::CreateForApplet( + framebuffer_memory = Core::System::GetInstance().Kernel().CreateSharedMemoryForApplet( heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "ErrEula Memory"); diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp index cfe25b11d..dd57f0efd 100644 --- a/src/core/hle/applets/mii_selector.cpp +++ b/src/core/hle/applets/mii_selector.cpp @@ -7,6 +7,7 @@ #include "common/assert.h" #include "common/logging/log.h" #include "common/string_util.h" +#include "core/core.h" #include "core/hle/applets/mii_selector.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/shared_memory.h" @@ -37,7 +38,7 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p // Allocate a heap block of the required size for this applet. heap_memory = std::make_shared>(capture_info.size); // Create a SharedMemory that directly points to this heap block. - framebuffer_memory = Kernel::SharedMemory::CreateForApplet( + framebuffer_memory = Core::System::GetInstance().Kernel().CreateSharedMemoryForApplet( heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "MiiSelector Memory"); diff --git a/src/core/hle/applets/mint.cpp b/src/core/hle/applets/mint.cpp index d71cd7001..ee70ba615 100644 --- a/src/core/hle/applets/mint.cpp +++ b/src/core/hle/applets/mint.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "common/string_util.h" +#include "core/core.h" #include "core/hle/applets/mint.h" #include "core/hle/service/apt/apt.h" @@ -30,7 +31,7 @@ ResultCode Mint::ReceiveParameter(const Service::APT::MessageParameter& paramete // Allocate a heap block of the required size for this applet. heap_memory = std::make_shared>(capture_info.size); // Create a SharedMemory that directly points to this heap block. - framebuffer_memory = Kernel::SharedMemory::CreateForApplet( + framebuffer_memory = Core::System::GetInstance().Kernel().CreateSharedMemoryForApplet( heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "Mint Memory"); diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp index d13050002..cd8a9f57a 100644 --- a/src/core/hle/applets/swkbd.cpp +++ b/src/core/hle/applets/swkbd.cpp @@ -8,6 +8,7 @@ #include "common/assert.h" #include "common/logging/log.h" #include "common/string_util.h" +#include "core/core.h" #include "core/hle/applets/swkbd.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/shared_memory.h" @@ -41,7 +42,7 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con // Allocate a heap block of the required size for this applet. heap_memory = std::make_shared>(capture_info.size); // Create a SharedMemory that directly points to this heap block. - framebuffer_memory = Kernel::SharedMemory::CreateForApplet( + framebuffer_memory = Core::System::GetInstance().Kernel().CreateSharedMemoryForApplet( heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "SoftwareKeyboard Memory"); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 84a33d8e6..4d0390408 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -25,6 +25,7 @@ class ServerPort; class ClientSession; class ServerSession; class ResourceLimitList; +class SharedMemory; enum class ResetType { OneShot, @@ -32,6 +33,25 @@ enum class ResetType { Pulse, }; +/// Permissions for mapped shared memory blocks +enum class MemoryPermission : u32 { + None = 0, + Read = (1u << 0), + Write = (1u << 1), + ReadWrite = (Read | Write), + Execute = (1u << 2), + ReadExecute = (Read | Execute), + WriteExecute = (Write | Execute), + ReadWriteExecute = (Read | Write | Execute), + DontCare = (1u << 28) +}; + +enum class MemoryRegion : u16 { + APPLICATION = 1, + SYSTEM = 2, + BASE = 3, +}; + template using SharedPtr = boost::intrusive_ptr; @@ -122,6 +142,41 @@ public: ResourceLimitList& ResourceLimit(); const ResourceLimitList& ResourceLimit() const; + /** + * Creates a shared memory object. + * @param owner_process Process that created this shared memory object. + * @param size Size of the memory block. Must be page-aligned. + * @param permissions Permission restrictions applied to the process which created the block. + * @param other_permissions Permission restrictions applied to other processes mapping the + * block. + * @param address The address from which to map the Shared Memory. + * @param region If the address is 0, the shared memory will be allocated in this region of the + * linear heap. + * @param name Optional object name, used for debugging purposes. + */ + SharedPtr CreateSharedMemory(SharedPtr owner_process, u32 size, + MemoryPermission permissions, + MemoryPermission other_permissions, + VAddr address = 0, + MemoryRegion region = MemoryRegion::BASE, + std::string name = "Unknown"); + + /** + * Creates a shared memory object from a block of memory managed by an HLE applet. + * @param heap_block Heap block of the HLE applet. + * @param offset The offset into the heap block that the SharedMemory will map. + * @param size Size of the memory block. Must be page-aligned. + * @param permissions Permission restrictions applied to the process which created the block. + * @param other_permissions Permission restrictions applied to other processes mapping the + * block. + * @param name Optional object name, used for debugging purposes. + */ + SharedPtr CreateSharedMemoryForApplet(std::shared_ptr> heap_block, + u32 offset, u32 size, + MemoryPermission permissions, + MemoryPermission other_permissions, + std::string name = "Unknown Applet"); + private: std::unique_ptr resource_limits; }; diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index edf4928ff..a141dff4c 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -26,12 +26,6 @@ struct AddressMapping { bool unk_flag; }; -enum class MemoryRegion : u16 { - APPLICATION = 1, - SYSTEM = 2, - BASE = 3, -}; - union ProcessFlags { u16 raw; diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index f5b9dad2c..14a206c59 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -11,14 +11,15 @@ namespace Kernel { -SharedMemory::SharedMemory() {} +SharedMemory::SharedMemory(KernelSystem& system) {} SharedMemory::~SharedMemory() {} -SharedPtr SharedMemory::Create(SharedPtr owner_process, u32 size, - MemoryPermission permissions, - MemoryPermission other_permissions, VAddr address, - MemoryRegion region, std::string name) { - SharedPtr shared_memory(new SharedMemory); +SharedPtr KernelSystem::CreateSharedMemory(SharedPtr owner_process, u32 size, + MemoryPermission permissions, + MemoryPermission other_permissions, + VAddr address, MemoryRegion region, + std::string name) { + SharedPtr shared_memory(new SharedMemory(*this)); shared_memory->owner_process = owner_process; shared_memory->name = std::move(name); @@ -74,12 +75,10 @@ SharedPtr SharedMemory::Create(SharedPtr owner_process, u return shared_memory; } -SharedPtr SharedMemory::CreateForApplet(std::shared_ptr> heap_block, - u32 offset, u32 size, - MemoryPermission permissions, - MemoryPermission other_permissions, - std::string name) { - SharedPtr shared_memory(new SharedMemory); +SharedPtr KernelSystem::CreateSharedMemoryForApplet( + std::shared_ptr> heap_block, u32 offset, u32 size, MemoryPermission permissions, + MemoryPermission other_permissions, std::string name) { + SharedPtr shared_memory(new SharedMemory(*this)); shared_memory->owner_process = nullptr; shared_memory->name = std::move(name); diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 5ccd81572..d5d862927 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -12,55 +12,8 @@ namespace Kernel { -/// Permissions for mapped shared memory blocks -enum class MemoryPermission : u32 { - None = 0, - Read = (1u << 0), - Write = (1u << 1), - ReadWrite = (Read | Write), - Execute = (1u << 2), - ReadExecute = (Read | Execute), - WriteExecute = (Write | Execute), - ReadWriteExecute = (Read | Write | Execute), - DontCare = (1u << 28) -}; - class SharedMemory final : public Object { public: - /** - * Creates a shared memory object. - * @param owner_process Process that created this shared memory object. - * @param size Size of the memory block. Must be page-aligned. - * @param permissions Permission restrictions applied to the process which created the block. - * @param other_permissions Permission restrictions applied to other processes mapping the - * block. - * @param address The address from which to map the Shared Memory. - * @param region If the address is 0, the shared memory will be allocated in this region of the - * linear heap. - * @param name Optional object name, used for debugging purposes. - */ - static SharedPtr Create(SharedPtr owner_process, u32 size, - MemoryPermission permissions, - MemoryPermission other_permissions, VAddr address = 0, - MemoryRegion region = MemoryRegion::BASE, - std::string name = "Unknown"); - - /** - * Creates a shared memory object from a block of memory managed by an HLE applet. - * @param heap_block Heap block of the HLE applet. - * @param offset The offset into the heap block that the SharedMemory will map. - * @param size Size of the memory block. Must be page-aligned. - * @param permissions Permission restrictions applied to the process which created the block. - * @param other_permissions Permission restrictions applied to other processes mapping the - * block. - * @param name Optional object name, used for debugging purposes. - */ - static SharedPtr CreateForApplet(std::shared_ptr> heap_block, - u32 offset, u32 size, - MemoryPermission permissions, - MemoryPermission other_permissions, - std::string name = "Unknown Applet"); - std::string GetTypeName() const override { return "SharedMemory"; } @@ -125,8 +78,10 @@ public: std::string name; private: - SharedMemory(); + explicit SharedMemory(KernelSystem& kernel); ~SharedMemory() override; + + friend class KernelSystem; }; } // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 632d2e539..3e292bd3b 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1105,9 +1105,9 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 if (addr == 0 && g_current_process->flags.shared_device_mem) region = g_current_process->flags.memory_region; - shared_memory = - SharedMemory::Create(g_current_process, size, static_cast(my_permission), - static_cast(other_permission), addr, region); + shared_memory = Core::System::GetInstance().Kernel().CreateSharedMemory( + g_current_process, size, static_cast(my_permission), + static_cast(other_permission), addr, region); CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(shared_memory))); LOG_WARNING(Kernel_SVC, "called addr=0x{:08X}", addr); diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 752e65c2c..13c278158 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -855,9 +855,9 @@ Module::Module(Core::System& system) : system(system) { using Kernel::MemoryPermission; shared_font_mem = - Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB - MemoryPermission::ReadWrite, MemoryPermission::Read, 0, - Kernel::MemoryRegion::SYSTEM, "APT:SharedFont"); + system.Kernel().CreateSharedMemory(nullptr, 0x332000, // 3272 KB + MemoryPermission::ReadWrite, MemoryPermission::Read, 0, + Kernel::MemoryRegion::SYSTEM, "APT:SharedFont"); lock = system.Kernel().CreateMutex(false, "APT_U:Lock"); } diff --git a/src/core/hle/service/csnd/csnd_snd.cpp b/src/core/hle/service/csnd/csnd_snd.cpp index 8fc4f11f4..ec4f55c0d 100644 --- a/src/core/hle/service/csnd/csnd_snd.cpp +++ b/src/core/hle/service/csnd/csnd_snd.cpp @@ -20,9 +20,9 @@ void CSND_SND::Initialize(Kernel::HLERequestContext& ctx) { using Kernel::MemoryPermission; mutex = system.Kernel().CreateMutex(false, "CSND:mutex"); - shared_memory = Kernel::SharedMemory::Create(nullptr, size, MemoryPermission::ReadWrite, - MemoryPermission::ReadWrite, 0, - Kernel::MemoryRegion::BASE, "CSND:SharedMemory"); + shared_memory = system.Kernel().CreateSharedMemory( + nullptr, size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, 0, + Kernel::MemoryRegion::BASE, "CSND:SharedMemory"); IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/gsp/gsp_gpu.cpp b/src/core/hle/service/gsp/gsp_gpu.cpp index be2a7ca64..a6b4826e2 100644 --- a/src/core/hle/service/gsp/gsp_gpu.cpp +++ b/src/core/hle/service/gsp/gsp_gpu.cpp @@ -786,9 +786,9 @@ GSP_GPU::GSP_GPU(Core::System& system) : ServiceFramework("gsp::Gpu", 2), system RegisterHandlers(functions); using Kernel::MemoryPermission; - shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, - MemoryPermission::ReadWrite, 0, - Kernel::MemoryRegion::BASE, "GSP:SharedMemory"); + shared_memory = system.Kernel().CreateSharedMemory( + nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, 0, + Kernel::MemoryRegion::BASE, "GSP:SharedMemory"); first_initialization = true; }; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 322a0b193..205d7860e 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -359,9 +359,9 @@ std::shared_ptr Module::Interface::GetModule() const { Module::Module(Core::System& system) : system(system) { using namespace Kernel; - shared_mem = - SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read, - 0, MemoryRegion::BASE, "HID:SharedMemory"); + shared_mem = system.Kernel().CreateSharedMemory(nullptr, 0x1000, MemoryPermission::ReadWrite, + MemoryPermission::Read, 0, MemoryRegion::BASE, + "HID:SharedMemory"); // Create event handles event_pad_or_touch_1 = system.Kernel().CreateEvent(ResetType::OneShot, "HID:EventPadOrTouch1"); diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp index eb62ddb6c..147c91861 100644 --- a/src/core/hle/service/ir/ir_rst.cpp +++ b/src/core/hle/service/ir/ir_rst.cpp @@ -149,9 +149,9 @@ IR_RST::IR_RST(Core::System& system) : ServiceFramework("ir:rst", 1) { using namespace Kernel; // Note: these two kernel objects are even available before Initialize service function is // called. - shared_memory = - SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read, - 0, MemoryRegion::BASE, "IRRST:SharedMemory"); + shared_memory = system.Kernel().CreateSharedMemory(nullptr, 0x1000, MemoryPermission::ReadWrite, + MemoryPermission::Read, 0, + MemoryRegion::BASE, "IRRST:SharedMemory"); update_event = system.Kernel().CreateEvent(ResetType::OneShot, "IRRST:UpdateEvent"); update_callback_id = From 751ebe55e9e48ea6f69af323aaa2f1af291ad575 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sat, 13 Oct 2018 17:24:51 -0400 Subject: [PATCH 024/102] Kernel: pass ref down to Object and wrap ID counter into kernel state --- src/core/hle/kernel/address_arbiter.cpp | 2 +- src/core/hle/kernel/client_port.cpp | 2 +- src/core/hle/kernel/client_session.cpp | 2 +- src/core/hle/kernel/event.cpp | 2 +- src/core/hle/kernel/kernel.cpp | 8 ++++---- src/core/hle/kernel/kernel.h | 4 ++++ src/core/hle/kernel/mutex.cpp | 2 +- src/core/hle/kernel/object.cpp | 3 +++ src/core/hle/kernel/object.h | 8 ++++---- src/core/hle/kernel/process.cpp | 4 ++-- src/core/hle/kernel/resource_limit.cpp | 2 +- src/core/hle/kernel/semaphore.cpp | 2 +- src/core/hle/kernel/server_port.cpp | 2 +- src/core/hle/kernel/server_session.cpp | 2 +- src/core/hle/kernel/shared_memory.cpp | 2 +- src/core/hle/kernel/thread.cpp | 2 +- src/core/hle/kernel/timer.cpp | 2 +- src/core/hle/kernel/wait_object.h | 2 ++ 18 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index ad2805cbf..d391da208 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -65,7 +65,7 @@ SharedPtr AddressArbiter::ResumeHighestPriorityThread(VAddr address) { return thread; } -AddressArbiter::AddressArbiter(KernelSystem& kernel) {} +AddressArbiter::AddressArbiter(KernelSystem& kernel) : Object(kernel) {} AddressArbiter::~AddressArbiter() {} SharedPtr KernelSystem::CreateAddressArbiter(std::string name) { diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index bfbfc3720..02c5d08fd 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -13,7 +13,7 @@ namespace Kernel { -ClientPort::ClientPort(KernelSystem& kernel) : kernel(kernel) {} +ClientPort::ClientPort(KernelSystem& kernel) : kernel(kernel), Object(kernel) {} ClientPort::~ClientPort() = default; ResultVal> ClientPort::Connect() { diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index c2c3634ba..ef1b90195 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -13,7 +13,7 @@ namespace Kernel { -ClientSession::ClientSession(KernelSystem& kernel) {} +ClientSession::ClientSession(KernelSystem& kernel) : Object(kernel) {} ClientSession::~ClientSession() { // This destructor will be called automatically when the last ClientSession handle is closed by // the emulated application. diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index d2acee21b..ce5f3d6ec 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -12,7 +12,7 @@ namespace Kernel { -Event::Event(KernelSystem& kernel) {} +Event::Event(KernelSystem& kernel) : WaitObject(kernel) {} Event::~Event() {} SharedPtr KernelSystem::CreateEvent(ResetType reset_type, std::string name) { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 8a8fa6709..ba7223db4 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -14,8 +14,6 @@ namespace Kernel { -std::atomic Object::next_object_id{0}; - /// Initialize the kernel KernelSystem::KernelSystem(u32 system_mode) { ConfigMem::Init(); @@ -25,8 +23,6 @@ KernelSystem::KernelSystem(u32 system_mode) { resource_limits = std::make_unique(*this); Kernel::ThreadingInit(); Kernel::TimersInit(); - - Object::next_object_id = 0; // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are // reserved for low-level services Process::next_process_id = 10; @@ -51,4 +47,8 @@ const ResourceLimitList& KernelSystem::ResourceLimit() const { return *resource_limits; } +u32 KernelSystem::GenerateObjectID() { + return next_object_id++; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4d0390408..98a5d14a2 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -177,8 +178,11 @@ public: MemoryPermission other_permissions, std::string name = "Unknown Applet"); + u32 GenerateObjectID(); + private: std::unique_ptr resource_limits; + std::atomic next_object_id{0}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index dc4a55d35..f31a2a5d7 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -24,7 +24,7 @@ void ReleaseThreadMutexes(Thread* thread) { thread->held_mutexes.clear(); } -Mutex::Mutex(KernelSystem& kernel) {} +Mutex::Mutex(KernelSystem& kernel) : WaitObject(kernel) {} Mutex::~Mutex() {} SharedPtr KernelSystem::CreateMutex(bool initial_locked, std::string name) { diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp index 48bc80fb2..f9ca68218 100644 --- a/src/core/hle/kernel/object.cpp +++ b/src/core/hle/kernel/object.cpp @@ -3,10 +3,13 @@ // Refer to the license.txt file included. #include "common/assert.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/object.h" namespace Kernel { +Object::Object(KernelSystem& kernel) : object_id{kernel.GenerateObjectID()} {} + Object::~Object() = default; bool Object::IsWaitable() const { diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index 6d05a30ea..f1fd03295 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -11,6 +11,8 @@ namespace Kernel { +class KernelSystem; + using Handle = u32; enum class HandleType : u32 { @@ -37,6 +39,7 @@ enum { class Object : NonCopyable { public: + explicit Object(KernelSystem& kernel); virtual ~Object(); /// Returns a unique identifier for the object. For debugging purposes only. @@ -58,15 +61,12 @@ public: */ bool IsWaitable() const; -public: - static std::atomic next_object_id; - private: friend void intrusive_ptr_add_ref(Object*); friend void intrusive_ptr_release(Object*); std::atomic ref_count{0}; - std::atomic object_id{next_object_id++}; + std::atomic object_id; }; // Special functions used by boost::instrusive_ptr to do automatic ref-counting diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 5d1b9389a..ae799d15f 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -29,7 +29,7 @@ SharedPtr KernelSystem::CreateCodeSet(std::string name, u64 program_id) return codeset; } -CodeSet::CodeSet(KernelSystem& system) {} +CodeSet::CodeSet(KernelSystem& kernel) : Object(kernel) {} CodeSet::~CodeSet() {} u32 Process::next_process_id; @@ -304,7 +304,7 @@ ResultCode Process::LinearFree(VAddr target, u32 size) { return RESULT_SUCCESS; } -Kernel::Process::Process(KernelSystem& kernel) : kernel(kernel) {} +Kernel::Process::Process(KernelSystem& kernel) : Object(kernel), kernel(kernel) {} Kernel::Process::~Process() {} void ClearProcessList() { diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp index 4aaf6be6b..3498acb23 100644 --- a/src/core/hle/kernel/resource_limit.cpp +++ b/src/core/hle/kernel/resource_limit.cpp @@ -9,7 +9,7 @@ namespace Kernel { -ResourceLimit::ResourceLimit(KernelSystem& kernel) {} +ResourceLimit::ResourceLimit(KernelSystem& kernel) : Object(kernel) {} ResourceLimit::~ResourceLimit() {} SharedPtr ResourceLimit::Create(KernelSystem& kernel, std::string name) { diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index afe770a64..8193f848d 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -10,7 +10,7 @@ namespace Kernel { -Semaphore::Semaphore(KernelSystem& kernel) {} +Semaphore::Semaphore(KernelSystem& kernel) : WaitObject(kernel) {} Semaphore::~Semaphore() {} ResultVal> KernelSystem::CreateSemaphore(s32 initial_count, s32 max_count, diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 44a5ca841..e17e699a4 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -13,7 +13,7 @@ namespace Kernel { -ServerPort::ServerPort(KernelSystem& kernel) {} +ServerPort::ServerPort(KernelSystem& kernel) : WaitObject(kernel) {} ServerPort::~ServerPort() {} ResultVal> ServerPort::Accept() { diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 3382abae3..83e2ec4fa 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -13,7 +13,7 @@ namespace Kernel { -ServerSession::ServerSession(KernelSystem& kernel) {} +ServerSession::ServerSession(KernelSystem& kernel) : WaitObject(kernel) {} ServerSession::~ServerSession() { // This destructor will be called automatically when the last ServerSession handle is closed by // the emulated application. diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 14a206c59..35bd53003 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -11,7 +11,7 @@ namespace Kernel { -SharedMemory::SharedMemory(KernelSystem& system) {} +SharedMemory::SharedMemory(KernelSystem& kernel) : Object(kernel) {} SharedMemory::~SharedMemory() {} SharedPtr KernelSystem::CreateSharedMemory(SharedPtr owner_process, u32 size, diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index bf7a18685..6844e76d5 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -60,7 +60,7 @@ inline static u32 const NewThreadId() { return next_thread_id++; } -Thread::Thread(KernelSystem&) : context(Core::CPU().NewContext()) {} +Thread::Thread(KernelSystem& kernel) : WaitObject(kernel), context(Core::CPU().NewContext()) {} Thread::~Thread() {} Thread* GetCurrentThread() { diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index b229a94af..8ef96e058 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -19,7 +19,7 @@ static CoreTiming::EventType* timer_callback_event_type = nullptr; // us to simply use a pool index or similar. static Kernel::HandleTable timer_callback_handle_table; -Timer::Timer(KernelSystem& kernel) {} +Timer::Timer(KernelSystem& kernel) : WaitObject(kernel) {} Timer::~Timer() {} SharedPtr KernelSystem::CreateTimer(ResetType reset_type, std::string name) { diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h index 2b9a9393b..01fc40a0d 100644 --- a/src/core/hle/kernel/wait_object.h +++ b/src/core/hle/kernel/wait_object.h @@ -16,6 +16,8 @@ class Thread; /// Class that represents a Kernel object that a thread can be waiting on class WaitObject : public Object { public: + using Object::Object; + /** * Check if the specified thread should wait until the object is available * @param thread The thread about which we're deciding. From 9238015dd44e997f411d36a845816bb8829fb5b9 Mon Sep 17 00:00:00 2001 From: lioncash Date: Wed, 19 Sep 2018 18:45:57 +0200 Subject: [PATCH 025/102] yuzu: Move GameListWorker to its own source files This has gotten sufficiently large enough to warrant moving it to its own source files. Especially given it dumps the file_sys headers around code that doesn't use it for the most part. This'll also make it easier to introduce a type alias for the compatibility list, so a large unordered_map type declaration doesn't need to be specified all the time (we don't want to propagate the game_list_p.h include via the main game_list.h header). --- src/citra_qt/CMakeLists.txt | 2 + src/citra_qt/game_list.cpp | 124 +----------------------- src/citra_qt/game_list.h | 1 + src/citra_qt/game_list_p.h | 66 ++----------- src/citra_qt/game_list_worker.cpp | 152 ++++++++++++++++++++++++++++++ src/citra_qt/game_list_worker.h | 64 +++++++++++++ 6 files changed, 230 insertions(+), 179 deletions(-) create mode 100644 src/citra_qt/game_list_worker.cpp create mode 100644 src/citra_qt/game_list_worker.h diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 3a61f9aa0..aa96a2e0d 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -76,6 +76,8 @@ add_executable(citra-qt game_list.cpp game_list.h game_list_p.h + game_list_worker.cpp + game_list_worker.h hotkeys.cpp hotkeys.h main.cpp diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp index f736c21df..c16b63b86 100644 --- a/src/citra_qt/game_list.cpp +++ b/src/citra_qt/game_list.cpp @@ -23,6 +23,7 @@ #include #include "citra_qt/game_list.h" #include "citra_qt/game_list_p.h" +#include "citra_qt/game_list_worker.h" #include "citra_qt/main.h" #include "citra_qt/ui_settings.h" #include "common/common_paths.h" @@ -30,7 +31,6 @@ #include "core/file_sys/archive_extsavedata.h" #include "core/file_sys/archive_source_sd_savedata.h" #include "core/hle/service/fs/archive.h" -#include "core/loader/loader.h" GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) : gamelist{gamelist} {} @@ -648,11 +648,6 @@ void GameList::LoadInterfaceLayout() { const QStringList GameList::supported_file_extensions = {"3ds", "3dsx", "elf", "axf", "cci", "cxi", "app"}; -static bool HasSupportedFileExtension(const std::string& file_name) { - QFileInfo file = QFileInfo(QString::fromStdString(file_name)); - return GameList::supported_file_extensions.contains(file.suffix(), Qt::CaseInsensitive); -} - void GameList::RefreshGameDirectory() { if (!UISettings::values.game_dirs.isEmpty() && current_worker != nullptr) { LOG_INFO(Frontend, "Change detected in the games directory. Reloading game list."); @@ -678,123 +673,6 @@ QString GameList::FindGameByProgramID(QStandardItem* current_item, u64 program_i return ""; } -void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion, - GameListDir* parent_dir) { - const auto callback = [this, recursion, parent_dir](u64* num_entries_out, - const std::string& directory, - const std::string& virtual_name) -> bool { - std::string physical_name = directory + DIR_SEP + virtual_name; - - if (stop_processing) - return false; // Breaks the callback loop. - - bool is_dir = FileUtil::IsDirectory(physical_name); - if (!is_dir && HasSupportedFileExtension(physical_name)) { - std::unique_ptr loader = Loader::GetLoader(physical_name); - if (!loader) - return true; - - u64 program_id = 0; - loader->ReadProgramId(program_id); - - u64 extdata_id = 0; - loader->ReadExtdataId(extdata_id); - - std::vector smdh = [program_id, &loader]() -> std::vector { - std::vector original_smdh; - loader->ReadIcon(original_smdh); - - if (program_id < 0x0004000000000000 || program_id > 0x00040000FFFFFFFF) - return original_smdh; - - std::string update_path = Service::AM::GetTitleContentPath( - Service::FS::MediaType::SDMC, program_id + 0x0000000E00000000); - - if (!FileUtil::Exists(update_path)) - return original_smdh; - - std::unique_ptr update_loader = Loader::GetLoader(update_path); - - if (!update_loader) - return original_smdh; - - std::vector update_smdh; - update_loader->ReadIcon(update_smdh); - return update_smdh; - }(); - - if (!Loader::IsValidSMDH(smdh) && UISettings::values.game_list_hide_no_icon) { - // Skip this invalid entry - return true; - } - - auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); - - // The game list uses this as compatibility number for untested games - QString compatibility("99"); - if (it != compatibility_list.end()) - compatibility = it->second.first; - - emit EntryReady( - { - new GameListItemPath(QString::fromStdString(physical_name), smdh, program_id, - extdata_id), - new GameListItemCompat(compatibility), - new GameListItemRegion(smdh), - new GameListItem( - QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), - new GameListItemSize(FileUtil::GetSize(physical_name)), - }, - parent_dir); - - } else if (is_dir && recursion > 0) { - watch_list.append(QString::fromStdString(physical_name)); - AddFstEntriesToGameList(physical_name, recursion - 1, parent_dir); - } - - return true; - }; - - FileUtil::ForeachDirectoryEntry(nullptr, dir_path, callback); -} - -void GameListWorker::run() { - stop_processing = false; - for (UISettings::GameDir& game_dir : game_dirs) { - if (game_dir.path == "INSTALLED") { - QString path = - QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)) + - "Nintendo " - "3DS/00000000000000000000000000000000/" - "00000000000000000000000000000000/title/00040000"; - watch_list.append(path); - GameListDir* game_list_dir = new GameListDir(game_dir, GameListItemType::InstalledDir); - emit DirEntryReady({game_list_dir}); - AddFstEntriesToGameList(path.toStdString(), 2, game_list_dir); - } else if (game_dir.path == "SYSTEM") { - QString path = - QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)) + - "00000000000000000000000000000000/title/00040010"; - watch_list.append(path); - GameListDir* game_list_dir = new GameListDir(game_dir, GameListItemType::SystemDir); - emit DirEntryReady({game_list_dir}); - AddFstEntriesToGameList(path.toStdString(), 2, game_list_dir); - } else { - watch_list.append(game_dir.path); - GameListDir* game_list_dir = new GameListDir(game_dir); - emit DirEntryReady({game_list_dir}); - AddFstEntriesToGameList(game_dir.path.toStdString(), game_dir.deep_scan ? 256 : 0, - game_list_dir); - } - }; - emit Finished(watch_list); -} - -void GameListWorker::Cancel() { - this->disconnect(); - stop_processing = true; -} - GameListPlaceholder::GameListPlaceholder(GMainWindow* parent) : QWidget{parent} { this->main_window = parent; diff --git a/src/citra_qt/game_list.h b/src/citra_qt/game_list.h index c355ecc1e..cfcf23615 100644 --- a/src/citra_qt/game_list.h +++ b/src/citra_qt/game_list.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include #include "common/common_types.h" diff --git a/src/citra_qt/game_list_p.h b/src/citra_qt/game_list_p.h index cc8b92851..46f4714bc 100644 --- a/src/citra_qt/game_list_p.h +++ b/src/citra_qt/game_list_p.h @@ -4,7 +4,6 @@ #pragma once -#include #include #include #include @@ -59,17 +58,6 @@ static QPixmap GetDefaultIcon(bool large) { return icon; } -static auto FindMatchingCompatibilityEntry( - const std::unordered_map>& compatibility_list, - u64 program_id) { - return std::find_if( - compatibility_list.begin(), compatibility_list.end(), - [program_id](const std::pair>& element) { - std::string pid = fmt::format("{:016X}", program_id); - return element.first == pid; - }); -} - /** * Gets the short game title from SMDH data. * @param smdh SMDH data @@ -373,50 +361,16 @@ public: } }; -/** - * Asynchronous worker object for populating the game list. - * Communicates with other threads through Qt's signal/slot system. - */ -class GameListWorker : public QObject, public QRunnable { - Q_OBJECT - -public: - explicit GameListWorker( - QList& game_dirs, - const std::unordered_map>& compatibility_list) - : game_dirs(game_dirs), compatibility_list(compatibility_list) {} - -public slots: - /// Starts the processing of directory tree information. - void run() override; - /// Tells the worker that it should no longer continue processing. Thread-safe. - void Cancel(); - -signals: - /** - * The `EntryReady` signal is emitted once an entry has been prepared and is ready - * to be added to the game list. - * @param entry_items a list with `QStandardItem`s that make up the columns of the new - * entry. - */ - void DirEntryReady(GameListDir* entry_items); - void EntryReady(QList entry_items, GameListDir* parent_dir); - - /** - * After the worker has traversed the game directory looking for entries, this signal is - * emitted with a list of folders that should be watched for changes as well. - */ - void Finished(QStringList watch_list); - -private: - QStringList watch_list; - const std::unordered_map>& compatibility_list; - QList& game_dirs; - std::atomic_bool stop_processing; - - void AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion, - GameListDir* parent_dir); -}; +inline auto FindMatchingCompatibilityEntry( + const std::unordered_map>& compatibility_list, + u64 program_id) { + return std::find_if( + compatibility_list.begin(), compatibility_list.end(), + [program_id](const std::pair>& element) { + std::string pid = fmt::format("{:016X}", program_id); + return element.first == pid; + }); +} class GameList; class QHBoxLayout; diff --git a/src/citra_qt/game_list_worker.cpp b/src/citra_qt/game_list_worker.cpp new file mode 100644 index 000000000..b29f4246b --- /dev/null +++ b/src/citra_qt/game_list_worker.cpp @@ -0,0 +1,152 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include + +#include +#include + +#include "citra_qt/game_list.h" +#include "citra_qt/game_list_p.h" +#include "citra_qt/game_list_worker.h" +#include "citra_qt/ui_settings.h" +#include "common/common_paths.h" +#include "common/file_util.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/fs/archive.h" +#include "core/loader/loader.h" + +namespace { +bool HasSupportedFileExtension(const std::string& file_name) { + const QFileInfo file = QFileInfo(QString::fromStdString(file_name)); + return GameList::supported_file_extensions.contains(file.suffix(), Qt::CaseInsensitive); +} +} // Anonymous namespace + +GameListWorker::GameListWorker( + QList& game_dirs, + const std::unordered_map>& compatibility_list) + : game_dirs(game_dirs), compatibility_list(compatibility_list) {} + +GameListWorker::~GameListWorker() = default; + +void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion, + GameListDir* parent_dir) { + const auto callback = [this, recursion, parent_dir](u64* num_entries_out, + const std::string& directory, + const std::string& virtual_name) -> bool { + std::string physical_name = directory + DIR_SEP + virtual_name; + + if (stop_processing) + return false; // Breaks the callback loop. + + bool is_dir = FileUtil::IsDirectory(physical_name); + if (!is_dir && HasSupportedFileExtension(physical_name)) { + std::unique_ptr loader = Loader::GetLoader(physical_name); + if (!loader) + return true; + + u64 program_id = 0; + loader->ReadProgramId(program_id); + + u64 extdata_id = 0; + loader->ReadExtdataId(extdata_id); + + std::vector smdh = [program_id, &loader]() -> std::vector { + std::vector original_smdh; + loader->ReadIcon(original_smdh); + + if (program_id < 0x0004000000000000 || program_id > 0x00040000FFFFFFFF) + return original_smdh; + + std::string update_path = Service::AM::GetTitleContentPath( + Service::FS::MediaType::SDMC, program_id + 0x0000000E00000000); + + if (!FileUtil::Exists(update_path)) + return original_smdh; + + std::unique_ptr update_loader = Loader::GetLoader(update_path); + + if (!update_loader) + return original_smdh; + + std::vector update_smdh; + update_loader->ReadIcon(update_smdh); + return update_smdh; + }(); + + if (!Loader::IsValidSMDH(smdh) && UISettings::values.game_list_hide_no_icon) { + // Skip this invalid entry + return true; + } + + auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); + + // The game list uses this as compatibility number for untested games + QString compatibility("99"); + if (it != compatibility_list.end()) + compatibility = it->second.first; + + emit EntryReady( + { + new GameListItemPath(QString::fromStdString(physical_name), smdh, program_id, + extdata_id), + new GameListItemCompat(compatibility), + new GameListItemRegion(smdh), + new GameListItem( + QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), + new GameListItemSize(FileUtil::GetSize(physical_name)), + }, + parent_dir); + + } else if (is_dir && recursion > 0) { + watch_list.append(QString::fromStdString(physical_name)); + AddFstEntriesToGameList(physical_name, recursion - 1, parent_dir); + } + + return true; + }; + + FileUtil::ForeachDirectoryEntry(nullptr, dir_path, callback); +} + +void GameListWorker::run() { + stop_processing = false; + for (UISettings::GameDir& game_dir : game_dirs) { + if (game_dir.path == "INSTALLED") { + QString path = + QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)) + + "Nintendo " + "3DS/00000000000000000000000000000000/" + "00000000000000000000000000000000/title/00040000"; + watch_list.append(path); + GameListDir* game_list_dir = new GameListDir(game_dir, GameListItemType::InstalledDir); + emit DirEntryReady({game_list_dir}); + AddFstEntriesToGameList(path.toStdString(), 2, game_list_dir); + } else if (game_dir.path == "SYSTEM") { + QString path = + QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)) + + "00000000000000000000000000000000/title/00040010"; + watch_list.append(path); + GameListDir* game_list_dir = new GameListDir(game_dir, GameListItemType::SystemDir); + emit DirEntryReady({game_list_dir}); + AddFstEntriesToGameList(path.toStdString(), 2, game_list_dir); + } else { + watch_list.append(game_dir.path); + GameListDir* game_list_dir = new GameListDir(game_dir); + emit DirEntryReady({game_list_dir}); + AddFstEntriesToGameList(game_dir.path.toStdString(), game_dir.deep_scan ? 256 : 0, + game_list_dir); + } + }; + emit Finished(watch_list); +} + +void GameListWorker::Cancel() { + this->disconnect(); + stop_processing = true; +} diff --git a/src/citra_qt/game_list_worker.h b/src/citra_qt/game_list_worker.h new file mode 100644 index 000000000..b35e890ca --- /dev/null +++ b/src/citra_qt/game_list_worker.h @@ -0,0 +1,64 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "common/common_types.h" + +class QStandardItem; + +/** + * Asynchronous worker object for populating the game list. + * Communicates with other threads through Qt's signal/slot system. + */ +class GameListWorker : public QObject, public QRunnable { + Q_OBJECT + +public: + GameListWorker( + QList& game_dirs, + const std::unordered_map>& compatibility_list); + ~GameListWorker() override; + + /// Starts the processing of directory tree information. + void run() override; + + /// Tells the worker that it should no longer continue processing. Thread-safe. + void Cancel(); + +signals: + /** + * The `EntryReady` signal is emitted once an entry has been prepared and is ready + * to be added to the game list. + * @param entry_items a list with `QStandardItem`s that make up the columns of the new entry. + */ + void DirEntryReady(GameListDir* entry_items); + void EntryReady(QList entry_items, GameListDir* parent_dir); + + /** + * After the worker has traversed the game directory looking for entries, this signal is emitted + * with a list of folders that should be watched for changes as well. + */ + void Finished(QStringList watch_list); + +private: + void AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion, + GameListDir* parent_dir); + + QStringList watch_list; + const std::unordered_map>& compatibility_list; + QList& game_dirs; + std::atomic_bool stop_processing; +}; From 230edc8c7c14dac2495ecde947cc837affdffce9 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 9 Sep 2018 19:09:37 -0400 Subject: [PATCH 026/102] yuzu: Move compatibility list specifics to their own source files Lets us keep the generic portions of the compatibility list code together, and allows us to introduce a type alias that makes it so we don't need to type out a very long type declaration anymore, making the immediate readability of some code better. --- src/citra_qt/CMakeLists.txt | 2 ++ src/citra_qt/compatibility_list.cpp | 18 ++++++++++++++++++ src/citra_qt/compatibility_list.h | 17 +++++++++++++++++ src/citra_qt/game_list.cpp | 1 + src/citra_qt/game_list.h | 9 ++++----- src/citra_qt/game_list_p.h | 11 ----------- src/citra_qt/game_list_worker.cpp | 6 +++--- src/citra_qt/game_list_worker.h | 8 ++++---- src/citra_qt/main.cpp | 8 +++----- src/citra_qt/main.h | 6 +++--- 10 files changed, 55 insertions(+), 31 deletions(-) create mode 100644 src/citra_qt/compatibility_list.cpp create mode 100644 src/citra_qt/compatibility_list.h diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index aa96a2e0d..3fb9c8433 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -14,6 +14,8 @@ add_executable(citra-qt applets/swkbd.h bootmanager.cpp bootmanager.h + compatibility_list.cpp + compatibility_list.h camera/camera_util.cpp camera/camera_util.h camera/still_image_camera.cpp diff --git a/src/citra_qt/compatibility_list.cpp b/src/citra_qt/compatibility_list.cpp new file mode 100644 index 000000000..5bf6e5648 --- /dev/null +++ b/src/citra_qt/compatibility_list.cpp @@ -0,0 +1,18 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#include + +#include "citra_qt/compatibility_list.h" + +CompatibilityList::const_iterator FindMatchingCompatibilityEntry( + const CompatibilityList& compatibility_list, u64 program_id) { + return std::find_if(compatibility_list.begin(), compatibility_list.end(), + [program_id](const auto& element) { + std::string pid = fmt::format("{:016X}", program_id); + return element.first == pid; + }); +} diff --git a/src/citra_qt/compatibility_list.h b/src/citra_qt/compatibility_list.h new file mode 100644 index 000000000..bc0175bd3 --- /dev/null +++ b/src/citra_qt/compatibility_list.h @@ -0,0 +1,17 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include + +#include "common/common_types.h" + +using CompatibilityList = std::unordered_map>; + +CompatibilityList::const_iterator FindMatchingCompatibilityEntry( + const CompatibilityList& compatibility_list, u64 program_id); diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp index c16b63b86..c28878b88 100644 --- a/src/citra_qt/game_list.cpp +++ b/src/citra_qt/game_list.cpp @@ -21,6 +21,7 @@ #include #include #include +#include "citra_qt/compatibility_list.h" #include "citra_qt/game_list.h" #include "citra_qt/game_list_p.h" #include "citra_qt/game_list_worker.h" diff --git a/src/citra_qt/game_list.h b/src/citra_qt/game_list.h index cfcf23615..a10d7fe15 100644 --- a/src/citra_qt/game_list.h +++ b/src/citra_qt/game_list.h @@ -4,10 +4,10 @@ #pragma once -#include #include #include #include +#include "citra_qt/compatibility_list.h" #include "common/common_types.h" #include "ui_settings.h" @@ -71,9 +71,8 @@ signals: void GameChosen(QString game_path); void ShouldCancelWorker(); void OpenFolderRequested(u64 program_id, GameListOpenTarget target); - void NavigateToGamedbEntryRequested( - u64 program_id, - std::unordered_map>& compatibility_list); + void NavigateToGamedbEntryRequested(u64 program_id, + const CompatibilityList& compatibility_list); void OpenDirectory(QString directory); void AddDirectory(); void ShowList(bool show); @@ -104,7 +103,7 @@ private: QStandardItemModel* item_model = nullptr; GameListWorker* current_worker = nullptr; QFileSystemWatcher* watcher = nullptr; - std::unordered_map> compatibility_list; + CompatibilityList compatibility_list; friend class GameListSearchField; }; diff --git a/src/citra_qt/game_list_p.h b/src/citra_qt/game_list_p.h index 46f4714bc..2a1cb615c 100644 --- a/src/citra_qt/game_list_p.h +++ b/src/citra_qt/game_list_p.h @@ -361,17 +361,6 @@ public: } }; -inline auto FindMatchingCompatibilityEntry( - const std::unordered_map>& compatibility_list, - u64 program_id) { - return std::find_if( - compatibility_list.begin(), compatibility_list.end(), - [program_id](const std::pair>& element) { - std::string pid = fmt::format("{:016X}", program_id); - return element.first == pid; - }); -} - class GameList; class QHBoxLayout; class QTreeView; diff --git a/src/citra_qt/game_list_worker.cpp b/src/citra_qt/game_list_worker.cpp index b29f4246b..5e1e98466 100644 --- a/src/citra_qt/game_list_worker.cpp +++ b/src/citra_qt/game_list_worker.cpp @@ -10,6 +10,7 @@ #include #include +#include "citra_qt/compatibility_list.h" #include "citra_qt/game_list.h" #include "citra_qt/game_list_p.h" #include "citra_qt/game_list_worker.h" @@ -27,9 +28,8 @@ bool HasSupportedFileExtension(const std::string& file_name) { } } // Anonymous namespace -GameListWorker::GameListWorker( - QList& game_dirs, - const std::unordered_map>& compatibility_list) +GameListWorker::GameListWorker(QList& game_dirs, + const CompatibilityList& compatibility_list) : game_dirs(game_dirs), compatibility_list(compatibility_list) {} GameListWorker::~GameListWorker() = default; diff --git a/src/citra_qt/game_list_worker.h b/src/citra_qt/game_list_worker.h index b35e890ca..f87492cb1 100644 --- a/src/citra_qt/game_list_worker.h +++ b/src/citra_qt/game_list_worker.h @@ -15,6 +15,7 @@ #include #include +#include "citra_qt/compatibility_list.h" #include "common/common_types.h" class QStandardItem; @@ -27,9 +28,8 @@ class GameListWorker : public QObject, public QRunnable { Q_OBJECT public: - GameListWorker( - QList& game_dirs, - const std::unordered_map>& compatibility_list); + GameListWorker(QList& game_dirs, + const CompatibilityList& compatibility_list); ~GameListWorker() override; /// Starts the processing of directory tree information. @@ -58,7 +58,7 @@ private: GameListDir* parent_dir); QStringList watch_list; - const std::unordered_map>& compatibility_list; + const CompatibilityList& compatibility_list; QList& game_dirs; std::atomic_bool stop_processing; }; diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 8d0856af1..f09c228a7 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -21,6 +21,7 @@ #include "citra_qt/camera/qt_multimedia_camera.h" #include "citra_qt/camera/still_image_camera.h" #include "citra_qt/compatdb.h" +#include "citra_qt/compatibility_list.h" #include "citra_qt/configuration/config.h" #include "citra_qt/configuration/configure_dialog.h" #include "citra_qt/debugger/console.h" @@ -960,14 +961,11 @@ void GMainWindow::OnGameListOpenFolder(u64 data_id, GameListOpenTarget target) { QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); } -void GMainWindow::OnGameListNavigateToGamedbEntry( - u64 program_id, - std::unordered_map>& compatibility_list) { - +void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, + const CompatibilityList& compatibility_list) { auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); QString directory; - if (it != compatibility_list.end()) directory = it->second.second; diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index bbc0714c5..fc1382ddd 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -9,6 +9,7 @@ #include #include #include +#include "citra_qt/compatibility_list.h" #include "citra_qt/hotkeys.h" #include "common/announce_multiplayer_room.h" #include "core/core.h" @@ -153,9 +154,8 @@ 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 OnGameListNavigateToGamedbEntry( - u64 program_id, - std::unordered_map>& compatibility_list); + void OnGameListNavigateToGamedbEntry(u64 program_id, + const CompatibilityList& compatibility_list); void OnGameListOpenDirectory(QString path); void OnGameListAddDirectory(); void OnGameListShowList(bool show); From 52ec85be12e79676bf31aba5b328da67e7e3a355 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 17 Sep 2018 05:31:27 -0400 Subject: [PATCH 027/102] game_list_p: Amend typo in GameListItemCompat's constructor parameter Adds a missing 'i' character that was missing in compatibility. --- src/citra_qt/game_list_p.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/citra_qt/game_list_p.h b/src/citra_qt/game_list_p.h index 2a1cb615c..40f19d229 100644 --- a/src/citra_qt/game_list_p.h +++ b/src/citra_qt/game_list_p.h @@ -204,7 +204,7 @@ class GameListItemCompat : public GameListItem { public: static const int CompatNumberRole = SortRole; GameListItemCompat() = default; - explicit GameListItemCompat(const QString& compatiblity) { + explicit GameListItemCompat(const QString& compatibility) { setData(type(), TypeRole); struct CompatStatus { @@ -223,13 +223,13 @@ public: {"99", {"#000000", QT_TR_NOOP("Not Tested"), QT_TR_NOOP("The game has not yet been tested.")}}}; // clang-format on - auto iterator = status_data.find(compatiblity); + auto iterator = status_data.find(compatibility); if (iterator == status_data.end()) { - LOG_WARNING(Frontend, "Invalid compatibility number {}", compatiblity.toStdString()); + LOG_WARNING(Frontend, "Invalid compatibility number {}", compatibility.toStdString()); return; } CompatStatus status = iterator->second; - setData(compatiblity, CompatNumberRole); + setData(compatibility, CompatNumberRole); setText(QObject::tr(status.text)); setToolTip(QObject::tr(status.tooltip)); setData(CreateCirclePixmapFromColor(status.color), Qt::DecorationRole); From f56a8403334d1a54c714c0c7beaf1ddcc05bec9f Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 17 Sep 2018 05:30:09 -0400 Subject: [PATCH 028/102] game_list_p: Take map iterator contents by const reference We don't need to copy the whole struct in this instance, we can just utilize a reference instead. --- src/citra_qt/game_list_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/citra_qt/game_list_p.h b/src/citra_qt/game_list_p.h index 40f19d229..b3f473397 100644 --- a/src/citra_qt/game_list_p.h +++ b/src/citra_qt/game_list_p.h @@ -228,7 +228,7 @@ public: LOG_WARNING(Frontend, "Invalid compatibility number {}", compatibility.toStdString()); return; } - CompatStatus status = iterator->second; + const CompatStatus& status = iterator->second; setData(compatibility, CompatNumberRole); setText(QObject::tr(status.text)); setToolTip(QObject::tr(status.tooltip)); From 111b7db759b06e37bb080a9832c0e18943b69c66 Mon Sep 17 00:00:00 2001 From: fearlessTobi Date: Fri, 21 Sep 2018 17:25:42 +0200 Subject: [PATCH 029/102] Stop splitting includes --- src/citra_qt/compatibility_list.cpp | 2 -- src/citra_qt/compatibility_list.h | 2 -- src/citra_qt/game_list_worker.cpp | 2 -- src/citra_qt/game_list_worker.h | 2 -- 4 files changed, 8 deletions(-) diff --git a/src/citra_qt/compatibility_list.cpp b/src/citra_qt/compatibility_list.cpp index 5bf6e5648..92e729dee 100644 --- a/src/citra_qt/compatibility_list.cpp +++ b/src/citra_qt/compatibility_list.cpp @@ -3,9 +3,7 @@ // Refer to the license.txt file included. #include - #include - #include "citra_qt/compatibility_list.h" CompatibilityList::const_iterator FindMatchingCompatibilityEntry( diff --git a/src/citra_qt/compatibility_list.h b/src/citra_qt/compatibility_list.h index bc0175bd3..df2dbd60a 100644 --- a/src/citra_qt/compatibility_list.h +++ b/src/citra_qt/compatibility_list.h @@ -6,9 +6,7 @@ #include #include - #include - #include "common/common_types.h" using CompatibilityList = std::unordered_map>; diff --git a/src/citra_qt/game_list_worker.cpp b/src/citra_qt/game_list_worker.cpp index 5e1e98466..7ec7c7677 100644 --- a/src/citra_qt/game_list_worker.cpp +++ b/src/citra_qt/game_list_worker.cpp @@ -6,10 +6,8 @@ #include #include #include - #include #include - #include "citra_qt/compatibility_list.h" #include "citra_qt/game_list.h" #include "citra_qt/game_list_p.h" diff --git a/src/citra_qt/game_list_worker.h b/src/citra_qt/game_list_worker.h index f87492cb1..a955e6376 100644 --- a/src/citra_qt/game_list_worker.h +++ b/src/citra_qt/game_list_worker.h @@ -9,12 +9,10 @@ #include #include #include - #include #include #include #include - #include "citra_qt/compatibility_list.h" #include "common/common_types.h" From 930abb4b5e57062c6dc4ce5b380f198e799c0f84 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 21 Oct 2018 22:00:06 -0400 Subject: [PATCH 030/102] svc: Correct vma_map boundary check within QueryProcessMemory This should be using the process instance retrieved within the function, and not g_current_process, otherwise this is potentially comparing iterators from unrelated vma_map instances (which is undefined behavior). --- src/core/hle/kernel/svc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 3e292bd3b..c2eeb786f 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -923,7 +923,7 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_inf auto vma = process->vm_manager.FindVMA(addr); - if (vma == g_current_process->vm_manager.vma_map.end()) + if (vma == process->vm_manager.vma_map.end()) return ERR_INVALID_ADDRESS; memory_info->base_address = vma->second.base; From 4238754d8c3fd97153b2ade89477c0a2c39682a5 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Wed, 17 Oct 2018 13:47:42 -0400 Subject: [PATCH 031/102] kernel/process: move next_process_id to kernel instance --- src/core/hle/kernel/kernel.cpp | 3 --- src/core/hle/kernel/kernel.h | 4 ++++ src/core/hle/kernel/process.cpp | 3 +-- src/core/hle/kernel/process.h | 4 +--- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index ba7223db4..306dc6cdd 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -23,9 +23,6 @@ KernelSystem::KernelSystem(u32 system_mode) { resource_limits = std::make_unique(*this); Kernel::ThreadingInit(); Kernel::TimersInit(); - // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are - // reserved for low-level services - Process::next_process_id = 10; } /// Shutdown the kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 98a5d14a2..015fbe87f 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -183,6 +183,10 @@ public: private: std::unique_ptr resource_limits; std::atomic next_object_id{0}; + + // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are + // reserved for low-level services + u32 next_process_id = 10; }; } // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index ae799d15f..7f089a4c4 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -32,8 +32,6 @@ SharedPtr KernelSystem::CreateCodeSet(std::string name, u64 program_id) CodeSet::CodeSet(KernelSystem& kernel) : Object(kernel) {} CodeSet::~CodeSet() {} -u32 Process::next_process_id; - SharedPtr KernelSystem::CreateProcess(SharedPtr code_set) { SharedPtr process(new Process(*this)); @@ -41,6 +39,7 @@ SharedPtr KernelSystem::CreateProcess(SharedPtr code_set) { process->flags.raw = 0; process->flags.memory_region.Assign(MemoryRegion::APPLICATION); process->status = ProcessStatus::Created; + process->process_id = ++next_process_id; process_list.push_back(process); return process; diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index a141dff4c..70be04ff5 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -123,8 +123,6 @@ public: return HANDLE_TYPE; } - static u32 next_process_id; - SharedPtr codeset; /// Resource limit descriptor for this process SharedPtr resource_limit; @@ -145,7 +143,7 @@ public: ProcessStatus status; /// The id of this process - u32 process_id = next_process_id++; + u32 process_id; /** * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them From d9342622b031f6ce9721e9560971769f2dd941ec Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Wed, 17 Oct 2018 14:06:47 -0400 Subject: [PATCH 032/102] kennel/process: move process list to kernel instance --- src/core/hle/kernel/kernel.h | 7 +++++++ src/core/hle/kernel/process.cpp | 9 +-------- src/core/hle/kernel/process.h | 5 ----- src/core/hle/kernel/thread.cpp | 1 - src/core/hle/service/fs/fs_user.cpp | 2 +- 5 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 015fbe87f..d3907a382 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "common/common_types.h" #include "core/hle/result.h" @@ -180,6 +181,9 @@ public: u32 GenerateObjectID(); + /// Retrieves a process from the current list of processes. + SharedPtr GetProcessById(u32 process_id) const; + private: std::unique_ptr resource_limits; std::atomic next_object_id{0}; @@ -187,6 +191,9 @@ private: // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are // reserved for low-level services u32 next_process_id = 10; + + // Lists all processes that exist in the current session. + std::vector> process_list; }; } // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 7f089a4c4..23a4684a6 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -17,9 +17,6 @@ namespace Kernel { -// Lists all processes that exist in the current session. -static std::vector> process_list; - SharedPtr KernelSystem::CreateCodeSet(std::string name, u64 program_id) { SharedPtr codeset(new CodeSet(*this)); @@ -306,11 +303,7 @@ ResultCode Process::LinearFree(VAddr target, u32 size) { Kernel::Process::Process(KernelSystem& kernel) : Object(kernel), kernel(kernel) {} Kernel::Process::~Process() {} -void ClearProcessList() { - process_list.clear(); -} - -SharedPtr GetProcessById(u32 process_id) { +SharedPtr KernelSystem::GetProcessById(u32 process_id) const { auto itr = std::find_if( process_list.begin(), process_list.end(), [&](const SharedPtr& process) { return process->process_id == process_id; }); diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 70be04ff5..89ce9bf8a 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -198,10 +198,5 @@ private: KernelSystem& kernel; }; -void ClearProcessList(); - -/// Retrieves a process from the current list of processes. -SharedPtr GetProcessById(u32 process_id); - extern SharedPtr g_current_process; } // namespace Kernel diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 6844e76d5..99d9df133 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -516,7 +516,6 @@ void ThreadingShutdown() { } thread_list.clear(); ready_queue.clear(); - ClearProcessList(); } const std::vector>& GetThreadList() { diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 7b1316e48..f9b883fe7 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -619,7 +619,7 @@ void FS_USER::GetProgramLaunchInfo(Kernel::HLERequestContext& ctx) { // TODO(Subv): The real FS service manages its own process list and only checks the processes // that were registered with the 'fs:REG' service. - auto process = Kernel::GetProcessById(process_id); + auto process = system.Kernel().GetProcessById(process_id); IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); From 8fb3d8ff38907ddb28526a66a04505c0cefe9b58 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Wed, 17 Oct 2018 15:23:56 -0400 Subject: [PATCH 033/102] kernel/process: move current process to kernel instance Two functional change: QueryProcessMemory uses the process passed from handle instead current_process Thread::Stop() uses TLS from owner_process instead of current_process --- src/core/core.cpp | 6 ++- src/core/core.h | 3 ++ src/core/file_sys/archive_savedata.cpp | 10 +++-- src/core/file_sys/archive_selfncch.cpp | 3 +- src/core/hle/kernel/handle_table.cpp | 5 ++- src/core/hle/kernel/kernel.cpp | 9 ++++- src/core/hle/kernel/kernel.h | 5 +++ src/core/hle/kernel/process.cpp | 2 - src/core/hle/kernel/process.h | 2 - src/core/hle/kernel/shared_memory.cpp | 4 +- src/core/hle/kernel/svc.cpp | 45 ++++++++++++--------- src/core/hle/kernel/thread.cpp | 8 ++-- src/core/hle/service/apt/applet_manager.cpp | 2 +- src/core/hle/service/cecd/cecd.cpp | 4 +- src/core/hle/service/cecd/cecd.h | 2 + src/core/hle/service/service.cpp | 9 +++-- src/core/memory.cpp | 20 +++++---- src/tests/core/arm/arm_test_common.cpp | 10 +++-- src/tests/core/arm/arm_test_common.h | 2 +- 19 files changed, 96 insertions(+), 55 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 4d4379299..910083644 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -126,7 +126,9 @@ System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& file return init_result; } - const Loader::ResultStatus load_result{app_loader->Load(Kernel::g_current_process)}; + Kernel::SharedPtr process; + const Loader::ResultStatus load_result{app_loader->Load(process)}; + kernel->SetCurrentProcess(process); if (Loader::ResultStatus::Success != load_result) { LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast(load_result)); System::Shutdown(); @@ -140,7 +142,7 @@ System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& file return ResultStatus::ErrorLoader; } } - Memory::SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table); + Memory::SetCurrentPageTable(&kernel->GetCurrentProcess()->vm_manager.page_table); status = ResultStatus::Success; m_emu_window = &emu_window; m_filepath = filepath; diff --git a/src/core/core.h b/src/core/core.h index 9341f79a4..ea986f433 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -251,8 +251,11 @@ private: std::unique_ptr archive_manager; +public: // HACK: this is temporary exposed for tests, + // due to WIP kernel refactor causing desync state in memory std::unique_ptr kernel; +private: static System s_instance; ResultStatus status = ResultStatus::Success; diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp index d551f590f..6e518af8b 100644 --- a/src/core/file_sys/archive_savedata.cpp +++ b/src/core/file_sys/archive_savedata.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include "core/core.h" #include "core/file_sys/archive_savedata.h" #include "core/hle/kernel/process.h" @@ -16,16 +17,19 @@ ArchiveFactory_SaveData::ArchiveFactory_SaveData( : sd_savedata_source(std::move(sd_savedata)) {} ResultVal> ArchiveFactory_SaveData::Open(const Path& path) { - return sd_savedata_source->Open(Kernel::g_current_process->codeset->program_id); + return sd_savedata_source->Open( + Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id); } ResultCode ArchiveFactory_SaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) { - return sd_savedata_source->Format(Kernel::g_current_process->codeset->program_id, format_info); + return sd_savedata_source->Format( + Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id, format_info); } ResultVal ArchiveFactory_SaveData::GetFormatInfo(const Path& path) const { - return sd_savedata_source->GetFormatInfo(Kernel::g_current_process->codeset->program_id); + return sd_savedata_source->GetFormatInfo( + Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id); } } // namespace FileSys diff --git a/src/core/file_sys/archive_selfncch.cpp b/src/core/file_sys/archive_selfncch.cpp index 14be1f966..dc2c61666 100644 --- a/src/core/file_sys/archive_selfncch.cpp +++ b/src/core/file_sys/archive_selfncch.cpp @@ -7,6 +7,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/swap.h" +#include "core/core.h" #include "core/file_sys/archive_selfncch.h" #include "core/file_sys/errors.h" #include "core/file_sys/ivfc_archive.h" @@ -279,7 +280,7 @@ void ArchiveFactory_SelfNCCH::Register(Loader::AppLoader& app_loader) { ResultVal> ArchiveFactory_SelfNCCH::Open(const Path& path) { auto archive = std::make_unique( - ncch_data[Kernel::g_current_process->codeset->program_id]); + ncch_data[Core::System::GetInstance().Kernel().GetCurrentProcess()->codeset->program_id]); return MakeResult>(std::move(archive)); } diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index a0805a752..99b65fa93 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -5,6 +5,7 @@ #include #include "common/assert.h" #include "common/logging/log.h" +#include "core/core.h" // TODO: for current_process. Remove this later #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/process.h" @@ -76,7 +77,9 @@ SharedPtr HandleTable::GetGeneric(Handle handle) const { if (handle == CurrentThread) { return GetCurrentThread(); } else if (handle == CurrentProcess) { - return g_current_process; + // TODO: should this return HandleTable's parent process, or kernel's current process? + // Should change this either way + return Core::System::GetInstance().Kernel().GetCurrentProcess(); } if (!IsValid(handle)) { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 306dc6cdd..bed63ff91 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -30,7 +30,6 @@ KernelSystem::~KernelSystem() { g_handle_table.Clear(); // Free all kernel objects Kernel::ThreadingShutdown(); - g_current_process = nullptr; Kernel::TimersShutdown(); Kernel::MemoryShutdown(); @@ -48,4 +47,12 @@ u32 KernelSystem::GenerateObjectID() { return next_object_id++; } +SharedPtr KernelSystem::GetCurrentProcess() const { + return current_process; +} + +void KernelSystem::SetCurrentProcess(SharedPtr process) { + current_process = std::move(process); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index d3907a382..d461dc6e8 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -184,6 +184,9 @@ public: /// Retrieves a process from the current list of processes. SharedPtr GetProcessById(u32 process_id) const; + SharedPtr GetCurrentProcess() const; + void SetCurrentProcess(SharedPtr process); + private: std::unique_ptr resource_limits; std::atomic next_object_id{0}; @@ -194,6 +197,8 @@ private: // Lists all processes that exist in the current session. std::vector> process_list; + + SharedPtr current_process; }; } // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 23a4684a6..c6be6effc 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -313,6 +313,4 @@ SharedPtr KernelSystem::GetProcessById(u32 process_id) const { return *itr; } - -SharedPtr g_current_process; } // namespace Kernel diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 89ce9bf8a..762e0c0a1 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -197,6 +197,4 @@ private: friend class KernelSystem; KernelSystem& kernel; }; - -extern SharedPtr g_current_process; } // namespace Kernel diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 35bd53003..70a937222 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -52,8 +52,8 @@ SharedPtr KernelSystem::CreateSharedMemory(SharedPtr owne } // Refresh the address mappings for the current process. - if (Kernel::g_current_process != nullptr) { - Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); + if (current_process != nullptr) { + current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); } } else { auto& vm_manager = shared_memory->owner_process->vm_manager; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index c2eeb786f..b27ee5293 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -83,7 +83,7 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add } VMAPermission vma_permissions = (VMAPermission)permissions; - auto& process = *g_current_process; + auto& process = *Core::System::GetInstance().Kernel().GetCurrentProcess(); switch (operation & MEMOP_OPERATION_MASK) { case MEMOP_FREE: { @@ -145,16 +145,17 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add } static void ExitProcess() { - LOG_INFO(Kernel_SVC, "Process {} exiting", g_current_process->process_id); + SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); + LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->process_id); - ASSERT_MSG(g_current_process->status == ProcessStatus::Running, "Process has already exited"); + ASSERT_MSG(current_process->status == ProcessStatus::Running, "Process has already exited"); - g_current_process->status = ProcessStatus::Exited; + current_process->status = ProcessStatus::Exited; // Stop all the process threads that are currently waiting for objects. auto& thread_list = GetThreadList(); for (auto& thread : thread_list) { - if (thread->owner_process != g_current_process) + if (thread->owner_process != current_process) continue; if (thread == GetCurrentThread()) @@ -195,7 +196,8 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o case MemoryPermission::WriteExecute: case MemoryPermission::ReadWriteExecute: case MemoryPermission::DontCare: - return shared_memory->Map(g_current_process.get(), addr, permissions_type, + return shared_memory->Map(Core::System::GetInstance().Kernel().GetCurrentProcess().get(), + addr, permissions_type, static_cast(other_permissions)); default: LOG_ERROR(Kernel_SVC, "unknown permissions=0x{:08X}", permissions); @@ -213,7 +215,8 @@ static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) { if (shared_memory == nullptr) return ERR_INVALID_HANDLE; - return shared_memory->Unmap(g_current_process.get(), addr); + return shared_memory->Unmap(Core::System::GetInstance().Kernel().GetCurrentProcess().get(), + addr); } /// Connect to an OS service given the port name, returns the handle to the port to out @@ -733,14 +736,16 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point return ERR_OUT_OF_RANGE; } - SharedPtr& resource_limit = g_current_process->resource_limit; + SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); + + SharedPtr& resource_limit = current_process->resource_limit; if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) { return ERR_NOT_AUTHORIZED; } if (processor_id == ThreadProcessorIdDefault) { // Set the target CPU to the one specified in the process' exheader. - processor_id = g_current_process->ideal_processor; + processor_id = current_process->ideal_processor; ASSERT(processor_id != ThreadProcessorIdDefault); } @@ -761,9 +766,9 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point break; } - CASCADE_RESULT(SharedPtr thread, Core::System::GetInstance().Kernel().CreateThread( - name, entry_point, priority, arg, processor_id, - stack_top, g_current_process)); + CASCADE_RESULT(SharedPtr thread, + Core::System::GetInstance().Kernel().CreateThread( + name, entry_point, priority, arg, processor_id, stack_top, current_process)); thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO); // 0x03C00000 @@ -810,7 +815,8 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { // Note: The kernel uses the current process's resource limit instead of // the one from the thread owner's resource limit. - SharedPtr& resource_limit = g_current_process->resource_limit; + SharedPtr& resource_limit = + Core::System::GetInstance().Kernel().GetCurrentProcess()->resource_limit; if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) { return ERR_NOT_AUTHORIZED; } @@ -1097,16 +1103,18 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 return ERR_INVALID_ADDRESS; } + SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); + // When trying to create a memory block with address = 0, // if the process has the Shared Device Memory flag in the exheader, // then we have to allocate from the same region as the caller process instead of the BASE // region. MemoryRegion region = MemoryRegion::BASE; - if (addr == 0 && g_current_process->flags.shared_device_mem) - region = g_current_process->flags.memory_region; + if (addr == 0 && current_process->flags.shared_device_mem) + region = current_process->flags.memory_region; shared_memory = Core::System::GetInstance().Kernel().CreateSharedMemory( - g_current_process, size, static_cast(my_permission), + current_process, size, static_cast(my_permission), static_cast(other_permission), addr, region); CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(shared_memory))); @@ -1407,8 +1415,9 @@ void CallSVC(u32 immediate) { // Lock the global kernel mutex when we enter the kernel HLE. std::lock_guard lock(HLE::g_hle_lock); - ASSERT_MSG(g_current_process->status == ProcessStatus::Running, - "Running threads from exiting processes is unimplemented"); + DEBUG_ASSERT_MSG(Core::System::GetInstance().Kernel().GetCurrentProcess()->status == + ProcessStatus::Running, + "Running threads from exiting processes is unimplemented"); const FunctionDef* info = GetSVCInfo(immediate); if (info) { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 99d9df133..bc4aba38b 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -96,7 +96,7 @@ void Thread::Stop() { u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; u32 tls_slot = ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; - Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot); + owner_process->tls_slots[tls_page].reset(tls_slot); } /** @@ -127,7 +127,7 @@ static void SwitchContext(Thread* new_thread) { // Cancel any outstanding wakeup events for this thread CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle); - auto previous_process = Kernel::g_current_process; + auto previous_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); current_thread = new_thread; @@ -135,8 +135,8 @@ static void SwitchContext(Thread* new_thread) { new_thread->status = ThreadStatus::Running; if (previous_process != current_thread->owner_process) { - Kernel::g_current_process = current_thread->owner_process; - SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table); + Core::System::GetInstance().Kernel().SetCurrentProcess(current_thread->owner_process); + SetCurrentPageTable(¤t_thread->owner_process->vm_manager.page_table); } Core::CPU().LoadContext(new_thread->context); diff --git a/src/core/hle/service/apt/applet_manager.cpp b/src/core/hle/service/apt/applet_manager.cpp index bc02c5eb6..076f5f6cf 100644 --- a/src/core/hle/service/apt/applet_manager.cpp +++ b/src/core/hle/service/apt/applet_manager.cpp @@ -258,7 +258,7 @@ ResultVal AppletManager::Initialize(AppletId ap slot_data->applet_id = static_cast(app_id); // Note: In the real console the title id of a given applet slot is set by the APT module when // calling StartApplication. - slot_data->title_id = Kernel::g_current_process->codeset->program_id; + slot_data->title_id = system.Kernel().GetCurrentProcess()->codeset->program_id; slot_data->attributes.raw = attributes.raw; if (slot_data->applet_id == AppletId::Application || diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp index f2759e7fc..df217d76e 100644 --- a/src/core/hle/service/cecd/cecd.cpp +++ b/src/core/hle/service/cecd/cecd.cpp @@ -97,7 +97,7 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) { if (path_type == CecDataPathType::MboxProgramId) { std::vector program_id(8); - u64_le le_program_id = Kernel::g_current_process->codeset->program_id; + u64_le le_program_id = cecd->system.Kernel().GetCurrentProcess()->codeset->program_id; std::memcpy(program_id.data(), &le_program_id, sizeof(u64)); session_data->file->Write(0, sizeof(u64), true, program_id.data()); session_data->file->Close(); @@ -1351,7 +1351,7 @@ Module::SessionData::~SessionData() { Module::Interface::Interface(std::shared_ptr cecd, const char* name, u32 max_session) : ServiceFramework(name, max_session), cecd(std::move(cecd)) {} -Module::Module(Core::System& system) { +Module::Module(Core::System& system) : system(system) { using namespace Kernel; cecinfo_event = system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "CECD::cecinfo_event"); change_state_event = diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h index 3102bc318..d8023f5cf 100644 --- a/src/core/hle/service/cecd/cecd.h +++ b/src/core/hle/service/cecd/cecd.h @@ -610,6 +610,8 @@ private: Kernel::SharedPtr cecinfo_event; Kernel::SharedPtr change_state_event; + + Core::System& system; }; /// Initialize CECD service(s) diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 6bdafd0e8..117bf2b2c 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -188,11 +188,13 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr server_ses return ReportUnimplementedFunction(cmd_buf, info); } + Kernel::SharedPtr current_process = + Core::System::GetInstance().Kernel().GetCurrentProcess(); + // TODO(yuriks): The kernel should be the one handling this as part of translation after // everything else is migrated Kernel::HLERequestContext context(std::move(server_session)); - context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process, - Kernel::g_handle_table); + context.PopulateFromIncomingCommandBuffer(cmd_buf, *current_process, Kernel::g_handle_table); LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName().c_str(), cmd_buf)); handler_invoker(this, info->handler_callback, context); @@ -204,8 +206,7 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr server_ses // the thread to sleep then the writing of the command buffer will be deferred to the wakeup // callback. if (thread->status == Kernel::ThreadStatus::Running) { - context.WriteToOutgoingCommandBuffer(cmd_buf, *Kernel::g_current_process, - Kernel::g_handle_table); + context.WriteToOutgoingCommandBuffer(cmd_buf, *current_process, Kernel::g_handle_table); } } diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 52252c932..f109c752f 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -111,7 +111,7 @@ static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) { * using a VMA from the current process. */ static u8* GetPointerFromVMA(VAddr vaddr) { - return GetPointerFromVMA(*Kernel::g_current_process, vaddr); + return GetPointerFromVMA(*Core::System::GetInstance().Kernel().GetCurrentProcess(), vaddr); } /** @@ -128,7 +128,8 @@ static MMIORegionPointer GetMMIOHandler(const PageTable& page_table, VAddr vaddr } static MMIORegionPointer GetMMIOHandler(VAddr vaddr) { - const PageTable& page_table = Kernel::g_current_process->vm_manager.page_table; + const PageTable& page_table = + Core::System::GetInstance().Kernel().GetCurrentProcess()->vm_manager.page_table; return GetMMIOHandler(page_table, vaddr); } @@ -229,7 +230,7 @@ bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { } bool IsValidVirtualAddress(const VAddr vaddr) { - return IsValidVirtualAddress(*Kernel::g_current_process, vaddr); + return IsValidVirtualAddress(*Core::System::GetInstance().Kernel().GetCurrentProcess(), vaddr); } bool IsValidPhysicalAddress(const PAddr paddr) { @@ -524,7 +525,8 @@ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_ } void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { - ReadBlock(*Kernel::g_current_process, src_addr, dest_buffer, size); + ReadBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), src_addr, dest_buffer, + size); } void Write8(const VAddr addr, const u8 data) { @@ -592,7 +594,8 @@ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const voi } void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { - WriteBlock(*Kernel::g_current_process, dest_addr, src_buffer, size); + WriteBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), dest_addr, src_buffer, + size); } void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { @@ -644,7 +647,7 @@ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std: } void ZeroBlock(const VAddr dest_addr, const std::size_t size) { - ZeroBlock(*Kernel::g_current_process, dest_addr, size); + ZeroBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), dest_addr, size); } void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, @@ -699,7 +702,7 @@ void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, } void CopyBlock(VAddr dest_addr, VAddr src_addr, const std::size_t size) { - CopyBlock(*Kernel::g_current_process, dest_addr, src_addr, size); + CopyBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), dest_addr, src_addr, size); } template <> @@ -778,7 +781,8 @@ std::optional PhysicalToVirtualAddress(const PAddr addr) { } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) { return addr - VRAM_PADDR + VRAM_VADDR; } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) { - return addr - FCRAM_PADDR + Kernel::g_current_process->GetLinearHeapAreaAddress(); + return addr - FCRAM_PADDR + + Core::System::GetInstance().Kernel().GetCurrentProcess()->GetLinearHeapAreaAddress(); } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) { return addr - DSP_RAM_PADDR + DSP_RAM_VADDR; } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) { diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp index 4706c2512..1127a504f 100644 --- a/src/tests/core/arm/arm_test_common.cpp +++ b/src/tests/core/arm/arm_test_common.cpp @@ -17,10 +17,14 @@ TestEnvironment::TestEnvironment(bool mutable_memory_) : mutable_memory(mutable_memory_), test_memory(std::make_shared(this)) { CoreTiming::Init(); - kernel = std::make_unique(0); + // HACK: some memory functions are currently referring kernel from the global instance, + // so we need to create the kernel object there. + // Change this when all global states are eliminated. + Core::System::GetInstance().kernel = std::make_unique(0); + kernel = Core::System::GetInstance().kernel.get(); - Kernel::g_current_process = kernel->CreateProcess(kernel->CreateCodeSet("", 0)); - page_table = &Kernel::g_current_process->vm_manager.page_table; + kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0))); + page_table = &kernel->GetCurrentProcess()->vm_manager.page_table; page_table->pointers.fill(nullptr); page_table->attributes.fill(Memory::PageType::Unmapped); diff --git a/src/tests/core/arm/arm_test_common.h b/src/tests/core/arm/arm_test_common.h index 4f396416f..b52d26e3c 100644 --- a/src/tests/core/arm/arm_test_common.h +++ b/src/tests/core/arm/arm_test_common.h @@ -80,7 +80,7 @@ private: std::shared_ptr test_memory; std::vector write_records; - std::unique_ptr kernel; + Kernel::KernelSystem* kernel; }; } // namespace ArmTests From 5b45a3e1b57d9636c5ef7e2a954820f9c88a78b7 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 18 Oct 2018 21:40:22 -0400 Subject: [PATCH 034/102] Kernel/Timer: use unordered_map for callback recording --- src/core/hle/kernel/timer.cpp | 31 ++++++++++++++++++------------- src/core/hle/kernel/timer.h | 4 ++-- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 8ef96e058..d9d89abd0 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include "common/assert.h" #include "common/logging/log.h" #include "core/core_timing.h" @@ -15,12 +16,15 @@ namespace Kernel { /// The event type of the generic timer callback event static CoreTiming::EventType* timer_callback_event_type = nullptr; -// TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing -// us to simply use a pool index or similar. -static Kernel::HandleTable timer_callback_handle_table; + +static u64 next_timer_callback_id; +static std::unordered_map timer_callback_table; Timer::Timer(KernelSystem& kernel) : WaitObject(kernel) {} -Timer::~Timer() {} +Timer::~Timer() { + Cancel(); + timer_callback_table.erase(callback_id); +} SharedPtr KernelSystem::CreateTimer(ResetType reset_type, std::string name) { SharedPtr timer(new Timer(*this)); @@ -30,7 +34,8 @@ SharedPtr KernelSystem::CreateTimer(ResetType reset_type, std::string nam timer->name = std::move(name); timer->initial_delay = 0; timer->interval_delay = 0; - timer->callback_handle = timer_callback_handle_table.Create(timer).Unwrap(); + timer->callback_id = ++next_timer_callback_id; + timer_callback_table[timer->callback_id] = timer.get(); return timer; } @@ -57,12 +62,12 @@ void Timer::Set(s64 initial, s64 interval) { // Immediately invoke the callback Signal(0); } else { - CoreTiming::ScheduleEvent(nsToCycles(initial), timer_callback_event_type, callback_handle); + CoreTiming::ScheduleEvent(nsToCycles(initial), timer_callback_event_type, callback_id); } } void Timer::Cancel() { - CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle); + CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_id); } void Timer::Clear() { @@ -87,17 +92,16 @@ void Timer::Signal(s64 cycles_late) { if (interval_delay != 0) { // Reschedule the timer with the interval delay CoreTiming::ScheduleEvent(nsToCycles(interval_delay) - cycles_late, - timer_callback_event_type, callback_handle); + timer_callback_event_type, callback_id); } } /// The timer callback event, called when a timer is fired -static void TimerCallback(u64 timer_handle, s64 cycles_late) { - SharedPtr timer = - timer_callback_handle_table.Get(static_cast(timer_handle)); +static void TimerCallback(u64 callback_id, s64 cycles_late) { + SharedPtr timer = timer_callback_table.at(callback_id); if (timer == nullptr) { - LOG_CRITICAL(Kernel, "Callback fired for invalid timer {:08x}", timer_handle); + LOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016x}", callback_id); return; } @@ -105,7 +109,8 @@ static void TimerCallback(u64 timer_handle, s64 cycles_late) { } void TimersInit() { - timer_callback_handle_table.Clear(); + next_timer_callback_id = 0; + timer_callback_table.clear(); timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); } diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h index c039bb4f1..653dacb5b 100644 --- a/src/core/hle/kernel/timer.h +++ b/src/core/hle/kernel/timer.h @@ -71,8 +71,8 @@ private: bool signaled; ///< Whether the timer has been signaled or not std::string name; ///< Name of timer (optional) - /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. - Handle callback_handle; + /// ID used as userdata to reference this object when inserting into the CoreTiming queue. + u64 callback_id; friend class KernelSystem; }; From fda2a5cf5492ca7db730636cf47e918b84c2b4bb Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 18 Oct 2018 22:19:29 -0400 Subject: [PATCH 035/102] kernel/thread: use std::unordered_map for callback record --- src/core/hle/kernel/thread.cpp | 25 ++++++++++++------------- src/core/hle/kernel/thread.h | 3 --- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index bc4aba38b..220e6aa17 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include "common/assert.h" #include "common/common_types.h" @@ -37,9 +38,8 @@ void Thread::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); } -// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing -// us to simply use a pool index or similar. -static Kernel::HandleTable wakeup_callback_handle_table; +static u64 next_callback_id; +static std::unordered_map wakeup_callback_table; // Lists all thread ids that aren't deleted/etc. static std::vector> thread_list; @@ -69,9 +69,8 @@ Thread* GetCurrentThread() { void Thread::Stop() { // Cancel any outstanding wakeup events for this thread - CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); - wakeup_callback_handle_table.Close(callback_handle); - callback_handle = 0; + CoreTiming::UnscheduleEvent(ThreadWakeupEventType, thread_id); + wakeup_callback_table.erase(thread_id); // Clean up thread from ready queue // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) @@ -125,7 +124,7 @@ static void SwitchContext(Thread* new_thread) { "Thread must be ready to become running."); // Cancel any outstanding wakeup events for this thread - CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle); + CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->thread_id); auto previous_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); @@ -185,13 +184,13 @@ void ExitCurrentThread() { /** * Callback that will wake up the thread it was scheduled for - * @param thread_handle The handle of the thread that's been awoken + * @param thread_id The ID of the thread that's been awoken * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time */ -static void ThreadWakeupCallback(u64 thread_handle, s64 cycles_late) { - SharedPtr thread = wakeup_callback_handle_table.Get((Handle)thread_handle); +static void ThreadWakeupCallback(u64 thread_id, s64 cycles_late) { + SharedPtr thread = wakeup_callback_table.at(thread_id); if (thread == nullptr) { - LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", (Handle)thread_handle); + LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", thread_id); return; } @@ -217,7 +216,7 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { if (nanoseconds == -1) return; - CoreTiming::ScheduleEvent(nsToCycles(nanoseconds), ThreadWakeupEventType, callback_handle); + CoreTiming::ScheduleEvent(nsToCycles(nanoseconds), ThreadWakeupEventType, thread_id); } void Thread::ResumeFromWait() { @@ -359,7 +358,7 @@ ResultVal> KernelSystem::CreateThread(std::string name, VAddr thread->wait_objects.clear(); thread->wait_address = 0; thread->name = std::move(name); - thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap(); + wakeup_callback_table[thread->thread_id] = thread.get(); thread->owner_process = owner_process; // Find the next available TLS index, and mark it as used diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 9e6a22759..bb0ab5b15 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -199,9 +199,6 @@ public: std::string name; - /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. - Handle callback_handle; - using WakeupCallback = void(ThreadWakeupReason reason, SharedPtr thread, SharedPtr object); // Callback that will be invoked when the thread is resumed from a waiting state. If the thread From eb285c33fd2751b8f03afb5b8e207cfa6e4b17cc Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Fri, 19 Oct 2018 21:04:18 -0400 Subject: [PATCH 036/102] kernel: make handle table per-process --- src/core/hle/kernel/handle_table.cpp | 9 +- src/core/hle/kernel/handle_table.h | 6 +- src/core/hle/kernel/hle_ipc.cpp | 15 ++- src/core/hle/kernel/hle_ipc.h | 6 +- src/core/hle/kernel/ipc.cpp | 6 +- src/core/hle/kernel/kernel.cpp | 2 - src/core/hle/kernel/process.cpp | 3 +- src/core/hle/kernel/process.h | 3 + src/core/hle/kernel/svc.cpp | 167 +++++++++++++++++--------- src/core/hle/service/service.cpp | 4 +- src/tests/core/hle/kernel/hle_ipc.cpp | 67 ++++++----- 11 files changed, 169 insertions(+), 119 deletions(-) diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 99b65fa93..87ba03f36 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -5,7 +5,6 @@ #include #include "common/assert.h" #include "common/logging/log.h" -#include "core/core.h" // TODO: for current_process. Remove this later #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/process.h" @@ -13,9 +12,7 @@ namespace Kernel { -HandleTable g_handle_table; - -HandleTable::HandleTable() { +HandleTable::HandleTable(KernelSystem& kernel) : kernel(kernel) { next_generation = 1; Clear(); } @@ -77,9 +74,7 @@ SharedPtr HandleTable::GetGeneric(Handle handle) const { if (handle == CurrentThread) { return GetCurrentThread(); } else if (handle == CurrentProcess) { - // TODO: should this return HandleTable's parent process, or kernel's current process? - // Should change this either way - return Core::System::GetInstance().Kernel().GetCurrentProcess(); + return kernel.GetCurrentProcess(); } if (!IsValid(handle)) { diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 5497dd74a..00cb47a33 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -42,7 +42,7 @@ enum KernelHandle : Handle { */ class HandleTable final : NonCopyable { public: - HandleTable(); + explicit HandleTable(KernelSystem& kernel); /** * Allocates a handle for the given object. @@ -119,8 +119,8 @@ private: /// Head of the free slots linked list. u16 next_free_slot; + + KernelSystem& kernel; }; -extern HandleTable g_handle_table; - } // namespace Kernel diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 1da7c8a81..a72d33dd9 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -50,7 +50,7 @@ SharedPtr HLERequestContext::SleepClientThread(SharedPtr thread, std::array cmd_buff; Memory::ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(), cmd_buff.size() * sizeof(u32)); - context.WriteToOutgoingCommandBuffer(cmd_buff.data(), *process, Kernel::g_handle_table); + context.WriteToOutgoingCommandBuffer(cmd_buff.data(), *process); // Copy the translated command buffer back into the thread's command buffer area. Memory::WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(), cmd_buff.size() * sizeof(u32)); @@ -98,8 +98,7 @@ void HLERequestContext::AddStaticBuffer(u8 buffer_id, std::vector data) { } ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, - Process& src_process, - HandleTable& src_table) { + Process& src_process) { IPC::Header header{src_cmdbuf[0]}; std::size_t untranslated_size = 1u + header.normal_params_size; @@ -122,10 +121,10 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr Handle handle = src_cmdbuf[i]; SharedPtr object = nullptr; if (handle != 0) { - object = src_table.GetGeneric(handle); + object = src_process.handle_table.GetGeneric(handle); ASSERT(object != nullptr); // TODO(yuriks): Return error if (descriptor == IPC::DescriptorType::MoveHandle) { - src_table.Close(handle); + src_process.handle_table.Close(handle); } } @@ -163,8 +162,8 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr return RESULT_SUCCESS; } -ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, - HandleTable& dst_table) const { +ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, + Process& dst_process) const { IPC::Header header{cmd_buf[0]}; std::size_t untranslated_size = 1u + header.normal_params_size; @@ -189,7 +188,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P Handle handle = 0; if (object != nullptr) { // TODO(yuriks): Figure out the proper error handling for if this fails - handle = dst_table.Create(object).Unwrap(); + handle = dst_process.handle_table.Create(object).Unwrap(); } dst_cmdbuf[i++] = handle; } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 3a2b81b16..a41264834 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -226,11 +226,9 @@ public: MappedBuffer& GetMappedBuffer(u32 id_from_cmdbuf); /// Populates this context with data from the requesting process/thread. - ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process, - HandleTable& src_table); + ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process); /// Writes data from this context back to the requesting process/thread. - ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, - HandleTable& dst_table) const; + ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process) const; private: std::array cmd_buf; diff --git a/src/core/hle/kernel/ipc.cpp b/src/core/hle/kernel/ipc.cpp index 8db9d241f..b50a2429f 100644 --- a/src/core/hle/kernel/ipc.cpp +++ b/src/core/hle/kernel/ipc.cpp @@ -60,9 +60,9 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtrhandle_table.GetGeneric(handle); if (descriptor == IPC::DescriptorType::MoveHandle) { - g_handle_table.Close(handle); + src_process->handle_table.Close(handle); } } @@ -73,7 +73,7 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtrhandle_table.Create(std::move(object)); cmd_buf[i++] = result.ValueOr(0); } break; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index bed63ff91..afe6af195 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -27,8 +27,6 @@ KernelSystem::KernelSystem(u32 system_mode) { /// Shutdown the kernel KernelSystem::~KernelSystem() { - g_handle_table.Clear(); // Free all kernel objects - Kernel::ThreadingShutdown(); Kernel::TimersShutdown(); diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index c6be6effc..21204eeb8 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -300,7 +300,8 @@ ResultCode Process::LinearFree(VAddr target, u32 size) { return RESULT_SUCCESS; } -Kernel::Process::Process(KernelSystem& kernel) : Object(kernel), kernel(kernel) {} +Kernel::Process::Process(KernelSystem& kernel) + : Object(kernel), handle_table(kernel), kernel(kernel) {} Kernel::Process::~Process() {} SharedPtr KernelSystem::GetProcessById(u32 process_id) const { diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 762e0c0a1..fa04d8c42 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -13,6 +13,7 @@ #include #include "common/bit_field.h" #include "common/common_types.h" +#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/vm_manager.h" @@ -123,6 +124,8 @@ public: return HANDLE_TYPE; } + HandleTable handle_table; + SharedPtr codeset; /// Resource limit descriptor for this process SharedPtr resource_limit; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b27ee5293..94a820f34 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -182,7 +182,9 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o "otherpermission={}", handle, addr, permissions, other_permissions); - SharedPtr shared_memory = g_handle_table.Get(handle); + SharedPtr shared_memory = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( + handle); if (shared_memory == nullptr) return ERR_INVALID_HANDLE; @@ -211,12 +213,12 @@ static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) { // TODO(Subv): Return E0A01BF5 if the address is not in the application's heap - SharedPtr shared_memory = g_handle_table.Get(handle); + SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); + SharedPtr shared_memory = current_process->handle_table.Get(handle); if (shared_memory == nullptr) return ERR_INVALID_HANDLE; - return shared_memory->Unmap(Core::System::GetInstance().Kernel().GetCurrentProcess().get(), - addr); + return shared_memory->Unmap(current_process.get(), addr); } /// Connect to an OS service given the port name, returns the handle to the port to out @@ -244,13 +246,17 @@ static ResultCode ConnectToPort(Handle* out_handle, VAddr port_name_address) { CASCADE_RESULT(client_session, client_port->Connect()); // Return the client session - CASCADE_RESULT(*out_handle, g_handle_table.Create(client_session)); + CASCADE_RESULT(*out_handle, + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Create( + client_session)); return RESULT_SUCCESS; } /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Handle handle) { - SharedPtr session = g_handle_table.Get(handle); + SharedPtr session = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( + handle); if (session == nullptr) { return ERR_INVALID_HANDLE; } @@ -265,12 +271,14 @@ static ResultCode SendSyncRequest(Handle handle) { /// Close a handle static ResultCode CloseHandle(Handle handle) { LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); - return g_handle_table.Close(handle); + return Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Close(handle); } /// Wait for a handle to synchronize, timeout after the specified nanoseconds static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { - auto object = g_handle_table.Get(handle); + auto object = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( + handle); Thread* thread = GetCurrentThread(); if (object == nullptr) @@ -341,7 +349,9 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand for (int i = 0; i < handle_count; ++i) { Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); - auto object = g_handle_table.Get(handle); + auto object = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( + handle); if (object == nullptr) return ERR_INVALID_HANDLE; objects[i] = object; @@ -505,9 +515,11 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ using ObjectPtr = SharedPtr; std::vector objects(handle_count); + SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); + for (int i = 0; i < handle_count; ++i) { Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); - auto object = g_handle_table.Get(handle); + auto object = current_process->handle_table.Get(handle); if (object == nullptr) return ERR_INVALID_HANDLE; objects[i] = object; @@ -518,7 +530,7 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ u32* cmd_buff = GetCommandBuffer(); IPC::Header header{cmd_buff[0]}; if (reply_target != 0 && header.command_id != 0xFFFF) { - auto session = g_handle_table.Get(reply_target); + auto session = current_process->handle_table.Get(reply_target); if (session == nullptr) return ERR_INVALID_HANDLE; @@ -618,8 +630,10 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ /// Create an address arbiter (to allocate access to shared resources) static ResultCode CreateAddressArbiter(Handle* out_handle) { - SharedPtr arbiter = Core::System::GetInstance().Kernel().CreateAddressArbiter(); - CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(arbiter))); + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + SharedPtr arbiter = kernel.CreateAddressArbiter(); + CASCADE_RESULT(*out_handle, + kernel.GetCurrentProcess()->handle_table.Create(std::move(arbiter))); LOG_TRACE(Kernel_SVC, "returned handle=0x{:08X}", *out_handle); return RESULT_SUCCESS; } @@ -630,7 +644,9 @@ static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 val LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}, address=0x{:08X}, type=0x{:08X}, value=0x{:08X}", handle, address, type, value); - SharedPtr arbiter = g_handle_table.Get(handle); + SharedPtr arbiter = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( + handle); if (arbiter == nullptr) return ERR_INVALID_HANDLE; @@ -678,11 +694,12 @@ static void OutputDebugString(VAddr address, int len) { static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle) { LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle); - SharedPtr process = g_handle_table.Get(process_handle); + SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); + SharedPtr process = current_process->handle_table.Get(process_handle); if (process == nullptr) return ERR_INVALID_HANDLE; - CASCADE_RESULT(*resource_limit, g_handle_table.Create(process->resource_limit)); + CASCADE_RESULT(*resource_limit, current_process->handle_table.Create(process->resource_limit)); return RESULT_SUCCESS; } @@ -694,7 +711,8 @@ static ResultCode GetResourceLimitCurrentValues(VAddr values, Handle resource_li resource_limit_handle, names, name_count); SharedPtr resource_limit = - g_handle_table.Get(resource_limit_handle); + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( + resource_limit_handle); if (resource_limit == nullptr) return ERR_INVALID_HANDLE; @@ -714,7 +732,8 @@ static ResultCode GetResourceLimitLimitValues(VAddr values, Handle resource_limi resource_limit_handle, names, name_count); SharedPtr resource_limit = - g_handle_table.Get(resource_limit_handle); + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( + resource_limit_handle); if (resource_limit == nullptr) return ERR_INVALID_HANDLE; @@ -773,7 +792,7 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO); // 0x03C00000 - CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(thread))); + CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(thread))); Core::System::GetInstance().PrepareReschedule(); @@ -795,7 +814,8 @@ static void ExitThread() { /// Gets the priority for the specified thread static ResultCode GetThreadPriority(u32* priority, Handle handle) { - const SharedPtr thread = g_handle_table.Get(handle); + const SharedPtr thread = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); if (thread == nullptr) return ERR_INVALID_HANDLE; @@ -809,7 +829,8 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { return ERR_OUT_OF_RANGE; } - SharedPtr thread = g_handle_table.Get(handle); + SharedPtr thread = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); if (thread == nullptr) return ERR_INVALID_HANDLE; @@ -834,9 +855,10 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { /// Create a mutex static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { - SharedPtr mutex = Core::System::GetInstance().Kernel().CreateMutex(initial_locked != 0); + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + SharedPtr mutex = kernel.CreateMutex(initial_locked != 0); mutex->name = fmt::format("mutex-{:08x}", Core::CPU().GetReg(14)); - CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(mutex))); + CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(std::move(mutex))); LOG_TRACE(Kernel_SVC, "called initial_locked={} : created handle=0x{:08X}", initial_locked ? "true" : "false", *out_handle); @@ -848,7 +870,8 @@ static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { static ResultCode ReleaseMutex(Handle handle) { LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}", handle); - SharedPtr mutex = g_handle_table.Get(handle); + SharedPtr mutex = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); if (mutex == nullptr) return ERR_INVALID_HANDLE; @@ -859,7 +882,9 @@ static ResultCode ReleaseMutex(Handle handle) { static ResultCode GetProcessId(u32* process_id, Handle process_handle) { LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle); - const SharedPtr process = g_handle_table.Get(process_handle); + const SharedPtr process = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( + process_handle); if (process == nullptr) return ERR_INVALID_HANDLE; @@ -871,7 +896,9 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) { static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) { LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); - const SharedPtr thread = g_handle_table.Get(thread_handle); + const SharedPtr thread = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( + thread_handle); if (thread == nullptr) return ERR_INVALID_HANDLE; @@ -887,7 +914,8 @@ static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) { static ResultCode GetThreadId(u32* thread_id, Handle handle) { LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", handle); - const SharedPtr thread = g_handle_table.Get(handle); + const SharedPtr thread = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); if (thread == nullptr) return ERR_INVALID_HANDLE; @@ -897,10 +925,12 @@ static ResultCode GetThreadId(u32* thread_id, Handle handle) { /// Creates a semaphore static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) { + KernelSystem& kernel = Core::System::GetInstance().Kernel(); CASCADE_RESULT(SharedPtr semaphore, - Core::System::GetInstance().Kernel().CreateSemaphore(initial_count, max_count)); + kernel.CreateSemaphore(initial_count, max_count)); semaphore->name = fmt::format("semaphore-{:08x}", Core::CPU().GetReg(14)); - CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(semaphore))); + CASCADE_RESULT(*out_handle, + kernel.GetCurrentProcess()->handle_table.Create(std::move(semaphore))); LOG_TRACE(Kernel_SVC, "called initial_count={}, max_count={}, created handle=0x{:08X}", initial_count, max_count, *out_handle); @@ -911,7 +941,9 @@ static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { LOG_TRACE(Kernel_SVC, "called release_count={}, handle=0x{:08X}", release_count, handle); - SharedPtr semaphore = g_handle_table.Get(handle); + SharedPtr semaphore = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( + handle); if (semaphore == nullptr) return ERR_INVALID_HANDLE; @@ -923,7 +955,9 @@ static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) /// Query process memory static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info, Handle process_handle, u32 addr) { - SharedPtr process = g_handle_table.Get(process_handle); + SharedPtr process = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( + process_handle); if (process == nullptr) return ERR_INVALID_HANDLE; @@ -949,9 +983,10 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32 /// Create an event static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { - SharedPtr evt = Core::System::GetInstance().Kernel().CreateEvent( - static_cast(reset_type), fmt::format("event-{:08x}", Core::CPU().GetReg(14))); - CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(evt))); + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + SharedPtr evt = kernel.CreateEvent(static_cast(reset_type), + fmt::format("event-{:08x}", Core::CPU().GetReg(14))); + CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(std::move(evt))); LOG_TRACE(Kernel_SVC, "called reset_type=0x{:08X} : created handle=0x{:08X}", reset_type, *out_handle); @@ -960,7 +995,9 @@ static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { /// Duplicates a kernel handle static ResultCode DuplicateHandle(Handle* out, Handle handle) { - CASCADE_RESULT(*out, g_handle_table.Duplicate(handle)); + CASCADE_RESULT( + *out, + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Duplicate(handle)); LOG_TRACE(Kernel_SVC, "duplicated 0x{:08X} to 0x{:08X}", handle, *out); return RESULT_SUCCESS; } @@ -969,7 +1006,8 @@ static ResultCode DuplicateHandle(Handle* out, Handle handle) { static ResultCode SignalEvent(Handle handle) { LOG_TRACE(Kernel_SVC, "called event=0x{:08X}", handle); - SharedPtr evt = g_handle_table.Get(handle); + SharedPtr evt = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); if (evt == nullptr) return ERR_INVALID_HANDLE; @@ -982,7 +1020,8 @@ static ResultCode SignalEvent(Handle handle) { static ResultCode ClearEvent(Handle handle) { LOG_TRACE(Kernel_SVC, "called event=0x{:08X}", handle); - SharedPtr evt = g_handle_table.Get(handle); + SharedPtr evt = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); if (evt == nullptr) return ERR_INVALID_HANDLE; @@ -992,9 +1031,10 @@ static ResultCode ClearEvent(Handle handle) { /// Creates a timer static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { - SharedPtr timer = Core::System::GetInstance().Kernel().CreateTimer( + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + SharedPtr timer = kernel.CreateTimer( static_cast(reset_type), fmt ::format("timer-{:08x}", Core::CPU().GetReg(14))); - CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(timer))); + CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(std::move(timer))); LOG_TRACE(Kernel_SVC, "called reset_type=0x{:08X} : created handle=0x{:08X}", reset_type, *out_handle); @@ -1005,7 +1045,8 @@ static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { static ResultCode ClearTimer(Handle handle) { LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle); - SharedPtr timer = g_handle_table.Get(handle); + SharedPtr timer = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); if (timer == nullptr) return ERR_INVALID_HANDLE; @@ -1021,7 +1062,8 @@ static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { return ERR_OUT_OF_RANGE_KERNEL; } - SharedPtr timer = g_handle_table.Get(handle); + SharedPtr timer = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); if (timer == nullptr) return ERR_INVALID_HANDLE; @@ -1034,7 +1076,8 @@ static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { static ResultCode CancelTimer(Handle handle) { LOG_TRACE(Kernel_SVC, "called timer=0x{:08X}", handle); - SharedPtr timer = g_handle_table.Get(handle); + SharedPtr timer = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); if (timer == nullptr) return ERR_INVALID_HANDLE; @@ -1116,7 +1159,7 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 shared_memory = Core::System::GetInstance().Kernel().CreateSharedMemory( current_process, size, static_cast(my_permission), static_cast(other_permission), addr, region); - CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(shared_memory))); + CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(shared_memory))); LOG_WARNING(Kernel_SVC, "called addr=0x{:08X}", addr); return RESULT_SUCCESS; @@ -1127,48 +1170,58 @@ static ResultCode CreatePort(Handle* server_port, Handle* client_port, VAddr nam // TODO(Subv): Implement named ports. ASSERT_MSG(name_address == 0, "Named ports are currently unimplemented"); - auto ports = Core::System::GetInstance().Kernel().CreatePortPair(max_sessions); - CASCADE_RESULT(*client_port, - g_handle_table.Create(std::move(std::get>(ports)))); + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + SharedPtr current_process = kernel.GetCurrentProcess(); + + auto ports = kernel.CreatePortPair(max_sessions); + CASCADE_RESULT(*client_port, current_process->handle_table.Create( + std::move(std::get>(ports)))); // Note: The 3DS kernel also leaks the client port handle if the server port handle fails to be // created. - CASCADE_RESULT(*server_port, - g_handle_table.Create(std::move(std::get>(ports)))); + CASCADE_RESULT(*server_port, current_process->handle_table.Create( + std::move(std::get>(ports)))); LOG_TRACE(Kernel_SVC, "called max_sessions={}", max_sessions); return RESULT_SUCCESS; } static ResultCode CreateSessionToPort(Handle* out_client_session, Handle client_port_handle) { - SharedPtr client_port = g_handle_table.Get(client_port_handle); + SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); + SharedPtr client_port = + current_process->handle_table.Get(client_port_handle); if (client_port == nullptr) return ERR_INVALID_HANDLE; CASCADE_RESULT(auto session, client_port->Connect()); - CASCADE_RESULT(*out_client_session, g_handle_table.Create(std::move(session))); + CASCADE_RESULT(*out_client_session, current_process->handle_table.Create(std::move(session))); return RESULT_SUCCESS; } static ResultCode CreateSession(Handle* server_session, Handle* client_session) { - auto sessions = Core::System::GetInstance().Kernel().CreateSessionPair(); + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + auto sessions = kernel.CreateSessionPair(); + + SharedPtr current_process = kernel.GetCurrentProcess(); auto& server = std::get>(sessions); - CASCADE_RESULT(*server_session, g_handle_table.Create(std::move(server))); + CASCADE_RESULT(*server_session, current_process->handle_table.Create(std::move(server))); auto& client = std::get>(sessions); - CASCADE_RESULT(*client_session, g_handle_table.Create(std::move(client))); + CASCADE_RESULT(*client_session, current_process->handle_table.Create(std::move(client))); LOG_TRACE(Kernel_SVC, "called"); return RESULT_SUCCESS; } static ResultCode AcceptSession(Handle* out_server_session, Handle server_port_handle) { - SharedPtr server_port = g_handle_table.Get(server_port_handle); + SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); + SharedPtr server_port = + current_process->handle_table.Get(server_port_handle); if (server_port == nullptr) return ERR_INVALID_HANDLE; CASCADE_RESULT(auto session, server_port->Accept()); - CASCADE_RESULT(*out_server_session, g_handle_table.Create(std::move(session))); + CASCADE_RESULT(*out_server_session, current_process->handle_table.Create(std::move(session))); return RESULT_SUCCESS; } @@ -1218,7 +1271,9 @@ static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) { static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) { LOG_TRACE(Kernel_SVC, "called process=0x{:08X} type={}", process_handle, type); - SharedPtr process = g_handle_table.Get(process_handle); + SharedPtr process = + Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( + process_handle); if (process == nullptr) return ERR_INVALID_HANDLE; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 117bf2b2c..1217376b1 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -194,7 +194,7 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr server_ses // TODO(yuriks): The kernel should be the one handling this as part of translation after // everything else is migrated Kernel::HLERequestContext context(std::move(server_session)); - context.PopulateFromIncomingCommandBuffer(cmd_buf, *current_process, Kernel::g_handle_table); + context.PopulateFromIncomingCommandBuffer(cmd_buf, *current_process); LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName().c_str(), cmd_buf)); handler_invoker(this, info->handler_callback, context); @@ -206,7 +206,7 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr server_ses // the thread to sleep then the writing of the command buffer will be deferred to the wakeup // callback. if (thread->status == Kernel::ThreadStatus::Running) { - context.WriteToOutgoingCommandBuffer(cmd_buf, *current_process, Kernel::g_handle_table); + context.WriteToOutgoingCommandBuffer(cmd_buf, *current_process); } } diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp index 9e093f4e4..068d767b6 100644 --- a/src/tests/core/hle/kernel/hle_ipc.cpp +++ b/src/tests/core/hle/kernel/hle_ipc.cpp @@ -26,14 +26,13 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel HLERequestContext context(std::move(session)); auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); - HandleTable handle_table; SECTION("works with empty cmdbuf") { const u32_le input[]{ IPC::MakeHeader(0x1234, 0, 0), }; - context.PopulateFromIncomingCommandBuffer(input, *process, handle_table); + context.PopulateFromIncomingCommandBuffer(input, *process); REQUIRE(context.CommandBuffer()[0] == 0x12340000); } @@ -46,7 +45,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel 0xAABBCCDD, }; - context.PopulateFromIncomingCommandBuffer(input, *process, handle_table); + context.PopulateFromIncomingCommandBuffer(input, *process); auto* output = context.CommandBuffer(); REQUIRE(output[1] == 0x12345678); @@ -56,34 +55,34 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel SECTION("translates move handles") { auto a = MakeObject(kernel); - Handle a_handle = handle_table.Create(a).Unwrap(); + Handle a_handle = process->handle_table.Create(a).Unwrap(); const u32_le input[]{ IPC::MakeHeader(0, 0, 2), IPC::MoveHandleDesc(1), a_handle, }; - context.PopulateFromIncomingCommandBuffer(input, *process, handle_table); + context.PopulateFromIncomingCommandBuffer(input, *process); auto* output = context.CommandBuffer(); REQUIRE(context.GetIncomingHandle(output[2]) == a); - REQUIRE(handle_table.GetGeneric(a_handle) == nullptr); + REQUIRE(process->handle_table.GetGeneric(a_handle) == nullptr); } SECTION("translates copy handles") { auto a = MakeObject(kernel); - Handle a_handle = handle_table.Create(a).Unwrap(); + Handle a_handle = process->handle_table.Create(a).Unwrap(); const u32_le input[]{ IPC::MakeHeader(0, 0, 2), IPC::CopyHandleDesc(1), a_handle, }; - context.PopulateFromIncomingCommandBuffer(input, *process, handle_table); + context.PopulateFromIncomingCommandBuffer(input, *process); auto* output = context.CommandBuffer(); REQUIRE(context.GetIncomingHandle(output[2]) == a); - REQUIRE(handle_table.GetGeneric(a_handle) == a); + REQUIRE(process->handle_table.GetGeneric(a_handle) == a); } SECTION("translates multi-handle descriptors") { @@ -91,12 +90,15 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel auto b = MakeObject(kernel); auto c = MakeObject(kernel); const u32_le input[]{ - IPC::MakeHeader(0, 0, 5), IPC::MoveHandleDesc(2), - handle_table.Create(a).Unwrap(), handle_table.Create(b).Unwrap(), - IPC::MoveHandleDesc(1), handle_table.Create(c).Unwrap(), + IPC::MakeHeader(0, 0, 5), + IPC::MoveHandleDesc(2), + process->handle_table.Create(a).Unwrap(), + process->handle_table.Create(b).Unwrap(), + IPC::MoveHandleDesc(1), + process->handle_table.Create(c).Unwrap(), }; - context.PopulateFromIncomingCommandBuffer(input, *process, handle_table); + context.PopulateFromIncomingCommandBuffer(input, *process); auto* output = context.CommandBuffer(); REQUIRE(context.GetIncomingHandle(output[2]) == a); @@ -111,7 +113,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel 0, }; - auto result = context.PopulateFromIncomingCommandBuffer(input, *process, handle_table); + auto result = context.PopulateFromIncomingCommandBuffer(input, *process); REQUIRE(result == RESULT_SUCCESS); auto* output = context.CommandBuffer(); @@ -125,7 +127,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel 0x98989898, }; - context.PopulateFromIncomingCommandBuffer(input, *process, handle_table); + context.PopulateFromIncomingCommandBuffer(input, *process); REQUIRE(context.CommandBuffer()[2] == process->process_id); } @@ -145,7 +147,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel target_address, }; - context.PopulateFromIncomingCommandBuffer(input, *process, handle_table); + context.PopulateFromIncomingCommandBuffer(input, *process); CHECK(context.GetStaticBuffer(0) == *buffer); @@ -166,7 +168,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel target_address, }; - context.PopulateFromIncomingCommandBuffer(input, *process, handle_table); + context.PopulateFromIncomingCommandBuffer(input, *process); std::vector other_buffer(buffer->size()); context.GetMappedBuffer(0).Read(other_buffer.data(), 0, buffer->size()); @@ -199,7 +201,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel 0x12345678, 0xABCDEF00, IPC::MoveHandleDesc(1), - handle_table.Create(a).Unwrap(), + process->handle_table.Create(a).Unwrap(), IPC::CallingPidDesc(), 0, IPC::StaticBufferDesc(buffer_static->size(), 0), @@ -208,7 +210,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel target_address_mapped, }; - context.PopulateFromIncomingCommandBuffer(input, *process, handle_table); + context.PopulateFromIncomingCommandBuffer(input, *process); auto* output = context.CommandBuffer(); CHECK(output[1] == 0x12345678); @@ -236,14 +238,13 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { HLERequestContext context(std::move(session)); auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); - HandleTable handle_table; auto* input = context.CommandBuffer(); u32_le output[IPC::COMMAND_BUFFER_LENGTH]; SECTION("works with empty cmdbuf") { input[0] = IPC::MakeHeader(0x1234, 0, 0); - context.WriteToOutgoingCommandBuffer(output, *process, handle_table); + context.WriteToOutgoingCommandBuffer(output, *process); REQUIRE(output[0] == 0x12340000); } @@ -254,7 +255,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { input[2] = 0x21122112; input[3] = 0xAABBCCDD; - context.WriteToOutgoingCommandBuffer(output, *process, handle_table); + context.WriteToOutgoingCommandBuffer(output, *process); REQUIRE(output[1] == 0x12345678); REQUIRE(output[2] == 0x21122112); @@ -270,10 +271,10 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { input[3] = IPC::CopyHandleDesc(1); input[4] = context.AddOutgoingHandle(b); - context.WriteToOutgoingCommandBuffer(output, *process, handle_table); + context.WriteToOutgoingCommandBuffer(output, *process); - REQUIRE(handle_table.GetGeneric(output[2]) == a); - REQUIRE(handle_table.GetGeneric(output[4]) == b); + REQUIRE(process->handle_table.GetGeneric(output[2]) == a); + REQUIRE(process->handle_table.GetGeneric(output[4]) == b); } SECTION("translates null handles") { @@ -281,7 +282,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { input[1] = IPC::MoveHandleDesc(1); input[2] = context.AddOutgoingHandle(nullptr); - auto result = context.WriteToOutgoingCommandBuffer(output, *process, handle_table); + auto result = context.WriteToOutgoingCommandBuffer(output, *process); REQUIRE(result == RESULT_SUCCESS); REQUIRE(output[2] == 0); @@ -298,11 +299,11 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { input[4] = IPC::CopyHandleDesc(1); input[5] = context.AddOutgoingHandle(c); - context.WriteToOutgoingCommandBuffer(output, *process, handle_table); + context.WriteToOutgoingCommandBuffer(output, *process); - REQUIRE(handle_table.GetGeneric(output[2]) == a); - REQUIRE(handle_table.GetGeneric(output[3]) == b); - REQUIRE(handle_table.GetGeneric(output[5]) == c); + REQUIRE(process->handle_table.GetGeneric(output[2]) == a); + REQUIRE(process->handle_table.GetGeneric(output[3]) == b); + REQUIRE(process->handle_table.GetGeneric(output[5]) == c); } SECTION("translates StaticBuffer descriptors") { @@ -329,7 +330,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { IPC::StaticBufferDesc(output_buffer->size(), 0); output_cmdbuff[IPC::COMMAND_BUFFER_LENGTH + 1] = target_address; - context.WriteToOutgoingCommandBuffer(output_cmdbuff.data(), *process, handle_table); + context.WriteToOutgoingCommandBuffer(output_cmdbuff.data(), *process); CHECK(*output_buffer == input_buffer); REQUIRE(process->vm_manager.UnmapRange(target_address, output_buffer->size()) == @@ -352,7 +353,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { target_address, }; - context.PopulateFromIncomingCommandBuffer(input_cmdbuff, *process, handle_table); + context.PopulateFromIncomingCommandBuffer(input_cmdbuff, *process); context.GetMappedBuffer(0).Write(input_buffer.data(), 0, input_buffer.size()); @@ -360,7 +361,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { input[1] = IPC::MappedBufferDesc(output_buffer->size(), IPC::W); input[2] = 0; - context.WriteToOutgoingCommandBuffer(output, *process, handle_table); + context.WriteToOutgoingCommandBuffer(output, *process); CHECK(output[1] == IPC::MappedBufferDesc(output_buffer->size(), IPC::W)); CHECK(output[2] == target_address); From d5bb2a21aa634246df84ed1b56a49227ec19dc27 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 9 Oct 2018 14:45:22 -0400 Subject: [PATCH 037/102] telemetry_session: Remove unimplemented FinalizeAsyncJob prototype This isn't implemented anywhere, so it can just be removed. --- src/core/telemetry_session.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h index bcf206b1b..905704fb2 100644 --- a/src/core/telemetry_session.h +++ b/src/core/telemetry_session.h @@ -30,8 +30,6 @@ public: field_collection.AddField(type, name, std::move(value)); } - static void FinalizeAsyncJob(); - private: Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session std::unique_ptr backend; ///< Backend interface that logs fields From 61627c20425f7522d70ae02decf4665ac058fdee Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 9 Oct 2018 14:47:24 -0400 Subject: [PATCH 038/102] telemetry_session: Add missing includes Prevents potential compilation issues in the future by including missing headers for certain functions and types. --- src/core/telemetry_session.cpp | 1 + src/core/telemetry_session.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 94270dbfe..9535ffee4 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -7,6 +7,7 @@ #include "common/assert.h" #include "common/file_util.h" +#include "common/logging/log.h" #include "common/scm_rev.h" #ifdef ARCHITECTURE_x86_64 #include "common/x64/cpu_detect.h" diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h index 905704fb2..976e2d7ed 100644 --- a/src/core/telemetry_session.h +++ b/src/core/telemetry_session.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "common/telemetry.h" namespace Core { From 7142d3cf7818ed8fdfdda0af2a3d8e02f8b5742c Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 9 Oct 2018 14:49:15 -0400 Subject: [PATCH 039/102] telemetry_session: Remove doxygen comment for a non-existent parameter There's no "func" parameter, so this can just be removed. --- src/core/telemetry_session.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h index 976e2d7ed..e37b6599e 100644 --- a/src/core/telemetry_session.h +++ b/src/core/telemetry_session.h @@ -52,7 +52,6 @@ u64 RegenerateTelemetryId(); * Verifies the username and token. * @param username Citra username to use for authentication. * @param token Citra token to use for authentication. - * @param func A function that gets exectued when the verification is finished * @returns Future with bool indicating whether the verification succeeded */ bool VerifyLogin(const std::string& username, const std::string& token); From c9013c481aaf2583150c9997876493c9c198e03b Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 10 Oct 2018 20:57:29 -0400 Subject: [PATCH 040/102] telemetry_json: Remove unnecessary includes Removes unused includes. Also rectifies a missing include. --- src/web_service/telemetry_json.cpp | 2 -- src/web_service/telemetry_json.h | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp index 033ea1ea4..e77950aa3 100644 --- a/src/web_service/telemetry_json.cpp +++ b/src/web_service/telemetry_json.cpp @@ -2,8 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include -#include "common/assert.h" #include "common/detached_tasks.h" #include "web_service/telemetry_json.h" #include "web_service/web_backend.h" diff --git a/src/web_service/telemetry_json.h b/src/web_service/telemetry_json.h index 42a15b6a4..a10f91091 100644 --- a/src/web_service/telemetry_json.h +++ b/src/web_service/telemetry_json.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include #include "common/announce_multiplayer_room.h" From 8747d93f6a42cf255256a88c41b80421adbfe08a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 10 Oct 2018 20:59:25 -0400 Subject: [PATCH 041/102] telemetry_json: Take std::string parameters by value Taking them by const reference isn't advisable here, because it means the std::move calls were doing nothing and we were always copying the std::string instances. --- src/web_service/telemetry_json.cpp | 3 +-- src/web_service/telemetry_json.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp index e77950aa3..b24e806a8 100644 --- a/src/web_service/telemetry_json.cpp +++ b/src/web_service/telemetry_json.cpp @@ -8,8 +8,7 @@ namespace WebService { -TelemetryJson::TelemetryJson(const std::string& host, const std::string& username, - const std::string& token) +TelemetryJson::TelemetryJson(std::string host, std::string username, std::string token) : host(std::move(host)), username(std::move(username)), token(std::move(token)) {} TelemetryJson::~TelemetryJson() = default; diff --git a/src/web_service/telemetry_json.h b/src/web_service/telemetry_json.h index a10f91091..69e87ad7a 100644 --- a/src/web_service/telemetry_json.h +++ b/src/web_service/telemetry_json.h @@ -19,7 +19,7 @@ namespace WebService { */ class TelemetryJson : public Telemetry::VisitorInterface { public: - TelemetryJson(const std::string& host, const std::string& username, const std::string& token); + TelemetryJson(std::string host, std::string username, std::string token); ~TelemetryJson(); void Visit(const Telemetry::Field& field) override; From 131ce598000b002fa8cec74a0ce53e78bb602671 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 10 Oct 2018 21:00:39 -0400 Subject: [PATCH 042/102] telemetry_json: Add missing override specifier to the destructor of TelemetryJson --- src/web_service/telemetry_json.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web_service/telemetry_json.h b/src/web_service/telemetry_json.h index 69e87ad7a..361243649 100644 --- a/src/web_service/telemetry_json.h +++ b/src/web_service/telemetry_json.h @@ -20,7 +20,7 @@ namespace WebService { class TelemetryJson : public Telemetry::VisitorInterface { public: TelemetryJson(std::string host, std::string username, std::string token); - ~TelemetryJson(); + ~TelemetryJson() override; void Visit(const Telemetry::Field& field) override; void Visit(const Telemetry::Field& field) override; From 25038aeb0de73d7630ed11a024311680ccd3074a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 10 Oct 2018 21:04:19 -0400 Subject: [PATCH 043/102] telemetry_json: Use the PImpl idiom to avoid unnecessary dependency exposure Users of the web_service library shouldn't need to care about an external library like json.h. However, given it's exposed in our interface, this requires that other libraries publicly link in the JSON library. We can do better. By using the PImpl idiom, we can hide this dependency in the cpp file and remove the need to link that library in altogether. --- src/web_service/telemetry_json.cpp | 84 ++++++++++++++++++------------ src/web_service/telemetry_json.h | 18 +------ 2 files changed, 54 insertions(+), 48 deletions(-) diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp index b24e806a8..3c5590054 100644 --- a/src/web_service/telemetry_json.cpp +++ b/src/web_service/telemetry_json.cpp @@ -2,93 +2,113 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "common/detached_tasks.h" #include "web_service/telemetry_json.h" #include "web_service/web_backend.h" namespace WebService { +struct TelemetryJson::Impl { + Impl(std::string host, std::string username, std::string token) + : host{std::move(host)}, username{std::move(username)}, token{std::move(token)} {} + + nlohmann::json& TopSection() { + return sections[static_cast(Telemetry::FieldType::None)]; + } + + const nlohmann::json& TopSection() const { + return sections[static_cast(Telemetry::FieldType::None)]; + } + + template + void Serialize(Telemetry::FieldType type, const std::string& name, T value) { + sections[static_cast(type)][name] = value; + } + + void SerializeSection(Telemetry::FieldType type, const std::string& name) { + TopSection()[name] = sections[static_cast(type)]; + } + + nlohmann::json output; + std::array sections; + std::string host; + std::string username; + std::string token; +}; + TelemetryJson::TelemetryJson(std::string host, std::string username, std::string token) - : host(std::move(host)), username(std::move(username)), token(std::move(token)) {} + : impl{std::make_unique(std::move(host), std::move(username), std::move(token))} {} TelemetryJson::~TelemetryJson() = default; -template -void TelemetryJson::Serialize(Telemetry::FieldType type, const std::string& name, T value) { - sections[static_cast(type)][name] = value; -} - -void TelemetryJson::SerializeSection(Telemetry::FieldType type, const std::string& name) { - TopSection()[name] = sections[static_cast(type)]; -} - void TelemetryJson::Visit(const Telemetry::Field& field) { - Serialize(field.GetType(), field.GetName(), field.GetValue()); + impl->Serialize(field.GetType(), field.GetName(), field.GetValue()); } void TelemetryJson::Visit(const Telemetry::Field& field) { - Serialize(field.GetType(), field.GetName(), field.GetValue()); + impl->Serialize(field.GetType(), field.GetName(), field.GetValue()); } void TelemetryJson::Visit(const Telemetry::Field& field) { - Serialize(field.GetType(), field.GetName(), field.GetValue()); + impl->Serialize(field.GetType(), field.GetName(), field.GetValue()); } void TelemetryJson::Visit(const Telemetry::Field& field) { - Serialize(field.GetType(), field.GetName(), field.GetValue()); + impl->Serialize(field.GetType(), field.GetName(), field.GetValue()); } void TelemetryJson::Visit(const Telemetry::Field& field) { - Serialize(field.GetType(), field.GetName(), field.GetValue()); + impl->Serialize(field.GetType(), field.GetName(), field.GetValue()); } void TelemetryJson::Visit(const Telemetry::Field& field) { - Serialize(field.GetType(), field.GetName(), field.GetValue()); + impl->Serialize(field.GetType(), field.GetName(), field.GetValue()); } void TelemetryJson::Visit(const Telemetry::Field& field) { - Serialize(field.GetType(), field.GetName(), field.GetValue()); + impl->Serialize(field.GetType(), field.GetName(), field.GetValue()); } void TelemetryJson::Visit(const Telemetry::Field& field) { - Serialize(field.GetType(), field.GetName(), field.GetValue()); + impl->Serialize(field.GetType(), field.GetName(), field.GetValue()); } void TelemetryJson::Visit(const Telemetry::Field& field) { - Serialize(field.GetType(), field.GetName(), field.GetValue()); + impl->Serialize(field.GetType(), field.GetName(), field.GetValue()); } void TelemetryJson::Visit(const Telemetry::Field& field) { - Serialize(field.GetType(), field.GetName(), field.GetValue()); + impl->Serialize(field.GetType(), field.GetName(), field.GetValue()); } void TelemetryJson::Visit(const Telemetry::Field& field) { - Serialize(field.GetType(), field.GetName(), field.GetValue()); + impl->Serialize(field.GetType(), field.GetName(), field.GetValue()); } void TelemetryJson::Visit(const Telemetry::Field& field) { - Serialize(field.GetType(), field.GetName(), field.GetValue()); + impl->Serialize(field.GetType(), field.GetName(), field.GetValue()); } void TelemetryJson::Visit(const Telemetry::Field& field) { - Serialize(field.GetType(), field.GetName(), std::string(field.GetValue())); + impl->Serialize(field.GetType(), field.GetName(), std::string(field.GetValue())); } void TelemetryJson::Visit(const Telemetry::Field& field) { - Serialize(field.GetType(), field.GetName(), field.GetValue().count()); + impl->Serialize(field.GetType(), field.GetName(), field.GetValue().count()); } void TelemetryJson::Complete() { - SerializeSection(Telemetry::FieldType::App, "App"); - SerializeSection(Telemetry::FieldType::Session, "Session"); - SerializeSection(Telemetry::FieldType::Performance, "Performance"); - SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback"); - SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig"); - SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem"); + impl->SerializeSection(Telemetry::FieldType::App, "App"); + impl->SerializeSection(Telemetry::FieldType::Session, "Session"); + impl->SerializeSection(Telemetry::FieldType::Performance, "Performance"); + impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback"); + impl->SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig"); + impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem"); - auto content = TopSection().dump(); + auto content = impl->TopSection().dump(); // Send the telemetry async but don't handle the errors since they were written to the log Common::DetachedTasks::AddTask( - [host{this->host}, username{this->username}, token{this->token}, content]() { + [host{impl->host}, username{impl->username}, token{impl->token}, content]() { Client{host, username, token}.PostJson("/telemetry", content, true); }); } diff --git a/src/web_service/telemetry_json.h b/src/web_service/telemetry_json.h index 361243649..4b4bef3bc 100644 --- a/src/web_service/telemetry_json.h +++ b/src/web_service/telemetry_json.h @@ -4,10 +4,8 @@ #pragma once -#include #include #include -#include #include "common/announce_multiplayer_room.h" #include "common/telemetry.h" @@ -40,20 +38,8 @@ public: void Complete() override; private: - nlohmann::json& TopSection() { - return sections[static_cast(Telemetry::FieldType::None)]; - } - - template - void Serialize(Telemetry::FieldType type, const std::string& name, T value); - - void SerializeSection(Telemetry::FieldType type, const std::string& name); - - nlohmann::json output; - std::array sections; - std::string host; - std::string username; - std::string token; + struct Impl; + std::unique_ptr impl; }; } // namespace WebService From 8b98560ebbd0d218b50e95f8e26bc3dd3acadbfb Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 10 Oct 2018 21:23:41 -0400 Subject: [PATCH 044/102] web_backend: Make Client use the PImpl idiom Like with TelemetryJson, we can make the implementation details private and avoid the need to expose httplib to external libraries that need to use the Client class. --- src/web_service/telemetry_json.cpp | 1 + src/web_service/verify_login.cpp | 1 + src/web_service/web_backend.cpp | 256 +++++++++++++++++------------ src/web_service/web_backend.h | 56 +------ 4 files changed, 161 insertions(+), 153 deletions(-) diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp index 3c5590054..0a8f2bd9e 100644 --- a/src/web_service/telemetry_json.cpp +++ b/src/web_service/telemetry_json.cpp @@ -4,6 +4,7 @@ #include #include "common/detached_tasks.h" +#include "common/web_result.h" #include "web_service/telemetry_json.h" #include "web_service/web_backend.h" diff --git a/src/web_service/verify_login.cpp b/src/web_service/verify_login.cpp index 124aa3863..ca4b43b93 100644 --- a/src/web_service/verify_login.cpp +++ b/src/web_service/verify_login.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include "common/web_result.h" #include "web_service/verify_login.h" #include "web_service/web_backend.h" diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp index 9b824e47d..6329c6a0c 100644 --- a/src/web_service/web_backend.cpp +++ b/src/web_service/web_backend.cpp @@ -3,11 +3,12 @@ // Refer to the license.txt file included. #include +#include #include -#include #include #include #include "common/announce_multiplayer_room.h" +#include "common/common_types.h" #include "common/logging/log.h" #include "web_service/web_backend.h" @@ -20,101 +21,132 @@ constexpr int HTTPS_PORT = 443; constexpr std::size_t TIMEOUT_SECONDS = 30; -Client::JWTCache Client::jwt_cache{}; - -Client::Client(const std::string& host, const std::string& username, const std::string& token) - : host(host), username(username), token(token) { - std::lock_guard lock(jwt_cache.mutex); - if (username == jwt_cache.username && token == jwt_cache.token) { - jwt = jwt_cache.jwt; - } -} - -Client::~Client() = default; - -Common::WebResult Client::GenericJson(const std::string& method, const std::string& path, - const std::string& data, const std::string& jwt, - const std::string& username, const std::string& token) { - if (cli == nullptr) { - auto parsedUrl = LUrlParser::clParseURL::ParseURL(host); - int port; - if (parsedUrl.m_Scheme == "http") { - if (!parsedUrl.GetPort(&port)) { - port = HTTP_PORT; - } - cli = - std::make_unique(parsedUrl.m_Host.c_str(), port, TIMEOUT_SECONDS); - } else if (parsedUrl.m_Scheme == "https") { - if (!parsedUrl.GetPort(&port)) { - port = HTTPS_PORT; - } - cli = std::make_unique(parsedUrl.m_Host.c_str(), port, - TIMEOUT_SECONDS); - } else { - LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme); - return Common::WebResult{Common::WebResult::Code::InvalidURL, "Bad URL scheme"}; +struct Client::Impl { + Impl(std::string host, std::string username, std::string token) + : host{std::move(host)}, username{std::move(username)}, token{std::move(token)} { + std::lock_guard lock(jwt_cache.mutex); + if (this->username == jwt_cache.username && this->token == jwt_cache.token) { + jwt = jwt_cache.jwt; } } - if (cli == nullptr) { - LOG_ERROR(WebService, "Invalid URL {}", host + path); - return Common::WebResult{Common::WebResult::Code::InvalidURL, "Invalid URL"}; + + /// A generic function handles POST, GET and DELETE request together + Common::WebResult GenericJson(const std::string& method, const std::string& path, + const std::string& data, bool allow_anonymous) { + if (jwt.empty()) { + UpdateJWT(); + } + + if (jwt.empty() && !allow_anonymous) { + LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); + return Common::WebResult{Common::WebResult::Code::CredentialsMissing, + "Credentials needed"}; + } + + auto result = GenericJson(method, path, data, jwt); + if (result.result_string == "401") { + // Try again with new JWT + UpdateJWT(); + result = GenericJson(method, path, data, jwt); + } + + return result; } - httplib::Headers params; - if (!jwt.empty()) { - params = { - {std::string("Authorization"), fmt::format("Bearer {}", jwt)}, - }; - } else if (!username.empty()) { - params = { - {std::string("x-username"), username}, - {std::string("x-token"), token}, + /** + * A generic function with explicit authentication method specified + * JWT is used if the jwt parameter is not empty + * username + token is used if jwt is empty but username and token are + * not empty anonymous if all of jwt, username and token are empty + */ + Common::WebResult GenericJson(const std::string& method, const std::string& path, + const std::string& data, const std::string& jwt = "", + const std::string& username = "", const std::string& token = "") { + if (cli == nullptr) { + auto parsedUrl = LUrlParser::clParseURL::ParseURL(host); + int port; + if (parsedUrl.m_Scheme == "http") { + if (!parsedUrl.GetPort(&port)) { + port = HTTP_PORT; + } + cli = std::make_unique(parsedUrl.m_Host.c_str(), port, + TIMEOUT_SECONDS); + } else if (parsedUrl.m_Scheme == "https") { + if (!parsedUrl.GetPort(&port)) { + port = HTTPS_PORT; + } + cli = std::make_unique(parsedUrl.m_Host.c_str(), port, + TIMEOUT_SECONDS); + } else { + LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme); + return Common::WebResult{Common::WebResult::Code::InvalidURL, "Bad URL scheme"}; + } + } + if (cli == nullptr) { + LOG_ERROR(WebService, "Invalid URL {}", host + path); + return Common::WebResult{Common::WebResult::Code::InvalidURL, "Invalid URL"}; + } + + httplib::Headers params; + if (!jwt.empty()) { + params = { + {std::string("Authorization"), fmt::format("Bearer {}", jwt)}, + }; + } else if (!username.empty()) { + params = { + {std::string("x-username"), username}, + {std::string("x-token"), token}, + }; + } + + params.emplace(std::string("api-version"), + std::string(API_VERSION.begin(), API_VERSION.end())); + if (method != "GET") { + params.emplace(std::string("Content-Type"), std::string("application/json")); }; + + httplib::Request request; + request.method = method; + request.path = path; + request.headers = params; + request.body = data; + + httplib::Response response; + + if (!cli->send(request, response)) { + LOG_ERROR(WebService, "{} to {} returned null", method, host + path); + return Common::WebResult{Common::WebResult::Code::LibError, "Null response"}; + } + + if (response.status >= 400) { + LOG_ERROR(WebService, "{} to {} returned error status code: {}", method, host + path, + response.status); + return Common::WebResult{Common::WebResult::Code::HttpError, + std::to_string(response.status)}; + } + + auto content_type = response.headers.find("content-type"); + + if (content_type == response.headers.end()) { + LOG_ERROR(WebService, "{} to {} returned no content", method, host + path); + return Common::WebResult{Common::WebResult::Code::WrongContent, ""}; + } + + if (content_type->second.find("application/json") == std::string::npos && + content_type->second.find("text/html; charset=utf-8") == std::string::npos) { + LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path, + content_type->second); + return Common::WebResult{Common::WebResult::Code::WrongContent, "Wrong content"}; + } + return Common::WebResult{Common::WebResult::Code::Success, "", response.body}; } - params.emplace(std::string("api-version"), std::string(API_VERSION.begin(), API_VERSION.end())); - if (method != "GET") { - params.emplace(std::string("Content-Type"), std::string("application/json")); - }; + // Retrieve a new JWT from given username and token + void UpdateJWT() { + if (username.empty() || token.empty()) { + return; + } - httplib::Request request; - request.method = method; - request.path = path; - request.headers = params; - request.body = data; - - httplib::Response response; - - if (!cli->send(request, response)) { - LOG_ERROR(WebService, "{} to {} returned null", method, host + path); - return Common::WebResult{Common::WebResult::Code::LibError, "Null response"}; - } - - if (response.status >= 400) { - LOG_ERROR(WebService, "{} to {} returned error status code: {}", method, host + path, - response.status); - return Common::WebResult{Common::WebResult::Code::HttpError, - std::to_string(response.status)}; - } - - auto content_type = response.headers.find("content-type"); - - if (content_type == response.headers.end()) { - LOG_ERROR(WebService, "{} to {} returned no content", method, host + path); - return Common::WebResult{Common::WebResult::Code::WrongContent, ""}; - } - - if (content_type->second.find("application/json") == std::string::npos && - content_type->second.find("text/html; charset=utf-8") == std::string::npos) { - LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path, - content_type->second); - return Common::WebResult{Common::WebResult::Code::WrongContent, "Wrong content"}; - } - return Common::WebResult{Common::WebResult::Code::Success, "", response.body}; -} - -void Client::UpdateJWT() { - if (!username.empty() && !token.empty()) { auto result = GenericJson("POST", "/jwt/internal", "", "", username, token); if (result.result_code != Common::WebResult::Code::Success) { LOG_ERROR(WebService, "UpdateJWT failed"); @@ -125,27 +157,39 @@ void Client::UpdateJWT() { jwt_cache.jwt = jwt = result.returned_data; } } + + std::string host; + std::string username; + std::string token; + std::string jwt; + std::unique_ptr cli; + + struct JWTCache { + std::mutex mutex; + std::string username; + std::string token; + std::string jwt; + }; + static inline JWTCache jwt_cache; +}; + +Client::Client(std::string host, std::string username, std::string token) + : impl{std::make_unique(std::move(host), std::move(username), std::move(token))} {} + +Client::~Client() = default; + +Common::WebResult Client::PostJson(const std::string& path, const std::string& data, + bool allow_anonymous) { + return impl->GenericJson("POST", path, data, allow_anonymous); } -Common::WebResult Client::GenericJson(const std::string& method, const std::string& path, - const std::string& data, bool allow_anonymous) { - if (jwt.empty()) { - UpdateJWT(); - } +Common::WebResult Client::GetJson(const std::string& path, bool allow_anonymous) { + return impl->GenericJson("GET", path, "", allow_anonymous); +} - if (jwt.empty() && !allow_anonymous) { - LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); - return Common::WebResult{Common::WebResult::Code::CredentialsMissing, "Credentials needed"}; - } - - auto result = GenericJson(method, path, data, jwt); - if (result.result_string == "401") { - // Try again with new JWT - UpdateJWT(); - result = GenericJson(method, path, data, jwt); - } - - return result; +Common::WebResult Client::DeleteJson(const std::string& path, const std::string& data, + bool allow_anonymous) { + return impl->GenericJson("DELETE", path, data, allow_anonymous); } } // namespace WebService diff --git a/src/web_service/web_backend.h b/src/web_service/web_backend.h index 6cdf35b48..c637e09df 100644 --- a/src/web_service/web_backend.h +++ b/src/web_service/web_backend.h @@ -4,22 +4,18 @@ #pragma once -#include -#include +#include #include -#include -#include "common/announce_multiplayer_room.h" -#include "common/common_types.h" -namespace httplib { -class Client; +namespace Common { +struct WebResult; } namespace WebService { class Client { public: - Client(const std::string& host, const std::string& username, const std::string& token); + Client(std::string host, std::string username, std::string token); ~Client(); /** @@ -30,9 +26,7 @@ public: * @return the result of the request. */ Common::WebResult PostJson(const std::string& path, const std::string& data, - bool allow_anonymous) { - return GenericJson("POST", path, data, allow_anonymous); - } + bool allow_anonymous); /** * Gets JSON from the specified path. @@ -40,9 +34,7 @@ public: * @param allow_anonymous If true, allow anonymous unauthenticated requests. * @return the result of the request. */ - Common::WebResult GetJson(const std::string& path, bool allow_anonymous) { - return GenericJson("GET", path, "", allow_anonymous); - } + Common::WebResult GetJson(const std::string& path, bool allow_anonymous); /** * Deletes JSON to the specified path. @@ -52,41 +44,11 @@ public: * @return the result of the request. */ Common::WebResult DeleteJson(const std::string& path, const std::string& data, - bool allow_anonymous) { - return GenericJson("DELETE", path, data, allow_anonymous); - } + bool allow_anonymous); private: - /// A generic function handles POST, GET and DELETE request together - Common::WebResult GenericJson(const std::string& method, const std::string& path, - const std::string& data, bool allow_anonymous); - - /** - * A generic function with explicit authentication method specified - * JWT is used if the jwt parameter is not empty - * username + token is used if jwt is empty but username and token are not empty - * anonymous if all of jwt, username and token are empty - */ - Common::WebResult GenericJson(const std::string& method, const std::string& path, - const std::string& data, const std::string& jwt = "", - const std::string& username = "", const std::string& token = ""); - - // Retrieve a new JWT from given username and token - void UpdateJWT(); - - std::string host; - std::string username; - std::string token; - std::string jwt; - std::unique_ptr cli; - - struct JWTCache { - std::mutex mutex; - std::string username; - std::string token; - std::string jwt; - }; - static JWTCache jwt_cache; + struct Impl; + std::unique_ptr impl; }; } // namespace WebService From 6fb673764214cc585af470f14bccebf2fa7de321 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 10 Oct 2018 21:37:19 -0400 Subject: [PATCH 045/102] core/CMakeLists: Make all web_service-related libraries private Now that all external dependencies are hidden, we can remove json-headers from the publically linked libraries, as the use of this library is now completely hidden from external users of the web_service library. We can also make the web_services library private as well, considering it's not a requirement. If a library needs to link in web_service, it should be done explicitly -- not via indirect linking. --- src/core/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2b9838a84..c30ddcbdd 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -446,7 +446,7 @@ target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core) target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp fmt open_source_archives) if (ENABLE_WEB_SERVICE) target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) - target_link_libraries(core PRIVATE json-headers web_service) + target_link_libraries(core PRIVATE web_service) endif() if (ARCHITECTURE_x86_64) From 8d32843d68907de5cdbe438eb917faf25259f123 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Tue, 23 Oct 2018 10:06:32 -0400 Subject: [PATCH 046/102] thread/kernel: remove unused callback_id we use the thread id for the same purpose now --- src/core/hle/kernel/thread.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 220e6aa17..69680acf8 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -38,7 +38,6 @@ void Thread::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); } -static u64 next_callback_id; static std::unordered_map wakeup_callback_table; // Lists all thread ids that aren't deleted/etc. From 6147bb622db7c08937794aabdc4da25d2c7dbc10 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 20 Oct 2018 17:28:27 -0400 Subject: [PATCH 047/102] CMakeLists: Use target_compile_definitions instead of add_definitions to define YUZU_ENABLE_COMPATIBILITY_REPORTING Keeps the definition constrained to the citra_qt target and prevents polluting anything else in the same directory (should that ever happen). It also keeps it consistent with how the USE_DISCORD_PRESENCE definition is introduced below it. --- src/citra_qt/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index ea275f3d2..0be279ddb 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -209,7 +209,7 @@ target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::Op target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) if (CITRA_ENABLE_COMPATIBILITY_REPORTING) - add_definitions(-DCITRA_ENABLE_COMPATIBILITY_REPORTING) + target_compile_definitions(citra-qt PRIVATE -DCITRA_ENABLE_COMPATIBILITY_REPORTING) endif() if (USE_DISCORD_PRESENCE) From dec3fb2dcf6d06991da552093a7c34e725625e54 Mon Sep 17 00:00:00 2001 From: Tobias Date: Thu, 25 Oct 2018 03:01:38 +0200 Subject: [PATCH 048/102] nfc: Add Amiibo support (REOPENED) (#4337) * Initial implementation * Various fixes and new features * Address some review comments * Fixes * Address more comments * Use g_hle_lock * Add more state checking, remove unneeded include * Minor changes --- src/citra_qt/main.cpp | 41 ++++++ src/citra_qt/main.h | 2 + src/citra_qt/main.ui | 25 ++++ src/core/hle/service/nfc/nfc.cpp | 214 ++++++++++++++++++++++++++--- src/core/hle/service/nfc/nfc.h | 64 ++++++++- src/core/hle/service/nfc/nfc_m.cpp | 6 +- src/core/hle/service/nfc/nfc_u.cpp | 6 +- 7 files changed, 332 insertions(+), 26 deletions(-) diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index af33515c1..83fd6a86a 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -45,6 +45,7 @@ #include "citra_qt/util/clickable_label.h" #include "common/common_paths.h" #include "common/detached_tasks.h" +#include "common/file_util.h" #include "common/logging/backend.h" #include "common/logging/filter.h" #include "common/logging/log.h" @@ -58,6 +59,7 @@ #include "core/frontend/applets/default_applets.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/service/fs/archive.h" +#include "core/hle/service/nfc/nfc.h" #include "core/loader/loader.h" #include "core/movie.h" #include "core/settings.h" @@ -496,6 +498,8 @@ void GMainWindow::ConnectMenuEvents() { connect(ui.action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile); connect(ui.action_Install_CIA, &QAction::triggered, this, &GMainWindow::OnMenuInstallCIA); connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close); + connect(ui.action_Load_Amiibo, &QAction::triggered, this, &GMainWindow::OnLoadAmiibo); + connect(ui.action_Remove_Amiibo, &QAction::triggered, this, &GMainWindow::OnRemoveAmiibo); // Emulation connect(ui.action_Start, &QAction::triggered, this, &GMainWindow::OnStartGame); @@ -848,6 +852,8 @@ void GMainWindow::ShutdownGame() { ui.action_Pause->setEnabled(false); ui.action_Stop->setEnabled(false); ui.action_Restart->setEnabled(false); + ui.action_Load_Amiibo->setEnabled(false); + ui.action_Remove_Amiibo->setEnabled(false); ui.action_Report_Compatibility->setEnabled(false); ui.action_Enable_Frame_Advancing->setEnabled(false); ui.action_Enable_Frame_Advancing->setChecked(false); @@ -1135,6 +1141,7 @@ void GMainWindow::OnStartGame() { ui.action_Pause->setEnabled(true); ui.action_Stop->setEnabled(true); ui.action_Restart->setEnabled(true); + ui.action_Load_Amiibo->setEnabled(true); ui.action_Report_Compatibility->setEnabled(true); ui.action_Enable_Frame_Advancing->setEnabled(true); @@ -1289,6 +1296,40 @@ void GMainWindow::OnConfigure() { } } +void GMainWindow::OnLoadAmiibo() { + const QString extensions{"*.bin"}; + const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions); + const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), "", file_filter); + + if (!filename.isEmpty()) { + Core::System& system{Core::System::GetInstance()}; + Service::SM::ServiceManager& sm = system.ServiceManager(); + auto nfc = sm.GetService("nfc:u"); + if (nfc != nullptr) { + Service::NFC::AmiiboData amiibo_data{}; + auto nfc_file = FileUtil::IOFile(filename.toStdString(), "rb"); + std::size_t read_length = + nfc_file.ReadBytes(&amiibo_data, sizeof(Service::NFC::AmiiboData)); + if (read_length != sizeof(Service::NFC::AmiiboData)) { + LOG_ERROR(Frontend, "Amiibo file size is incorrect"); + return; + } + nfc->LoadAmiibo(amiibo_data); + ui.action_Remove_Amiibo->setEnabled(true); + } + } +} + +void GMainWindow::OnRemoveAmiibo() { + Core::System& system{Core::System::GetInstance()}; + Service::SM::ServiceManager& sm = system.ServiceManager(); + auto nfc = sm.GetService("nfc:u"); + if (nfc != nullptr) { + nfc->RemoveAmiibo(); + ui.action_Remove_Amiibo->setEnabled(false); + } +} + void GMainWindow::OnToggleFilterBar() { game_list->setFilterVisible(ui.action_Show_Filter_Bar->isChecked()); if (ui.action_Show_Filter_Bar->isChecked()) { diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index fc1382ddd..684a9e332 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -166,6 +166,8 @@ private slots: void OnCIAInstallFinished(); void OnMenuRecentFile(); void OnConfigure(); + void OnLoadAmiibo(); + void OnRemoveAmiibo(); void OnToggleFilterBar(); void OnDisplayTitleBars(bool); void ToggleFullscreen(); diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index c2c58300d..b5810715f 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui @@ -57,11 +57,20 @@ Recent Files + + + Amiibo + + + + + + @@ -415,6 +424,22 @@ Restart + + + false + + + Load... + + + + + false + + + Remove + + diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index e76c7b3ee..cadb0fa77 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp @@ -5,19 +5,61 @@ #include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" +#include "core/hle/lock.h" #include "core/hle/service/nfc/nfc.h" #include "core/hle/service/nfc/nfc_m.h" #include "core/hle/service/nfc/nfc_u.h" namespace Service::NFC { +struct TagInfo { + u16_le id_offset_size; + u8 unk1; + u8 unk2; + std::array uuid; + INSERT_PADDING_BYTES(0x20); +}; +static_assert(sizeof(TagInfo) == 0x2C, "TagInfo is an invalid size"); + +struct AmiiboConfig { + u16_le lastwritedate_year; + u8 lastwritedate_month; + u8 lastwritedate_day; + u16_le write_counter; + std::array characterID; + u16_le amiiboID; + u8 type; + u8 pagex4_byte3; + u16_le appdata_size; + INSERT_PADDING_BYTES(0x30); +}; +static_assert(sizeof(AmiiboConfig) == 0x40, "AmiiboConfig is an invalid size"); + +struct IdentificationBlockReply { + u16_le char_id; + u8 char_variant; + u8 series; + u16_le model_number; + u8 figure_type; + INSERT_PADDING_BYTES(0x2F); +}; +static_assert(sizeof(IdentificationBlockReply) == 0x36, + "IdentificationBlockReply is an invalid size"); + void Module::Interface::Initialize(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x01, 1, 0); u8 param = rp.Pop(); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + if (nfc->nfc_tag_state != TagState::NotInitialized) { + LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast(nfc->nfc_tag_state.load())); + rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + nfc->nfc_tag_state = TagState::NotScanning; - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); LOG_WARNING(Service_NFC, "(STUBBED) called, param={}", param); } @@ -53,35 +95,83 @@ void Module::Interface::StartTagScanning(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x05, 1, 0); // 0x00050040 u16 in_val = rp.Pop(); - ResultCode result = RESULT_SUCCESS; - - // TODO(shinyquagsire23): Implement NFC tag detection, for now stub result - result = ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, - ErrorSummary::InvalidState, ErrorLevel::Status); - - if (result == RESULT_SUCCESS) { - nfc->nfc_tag_state = TagState::TagInRange; - nfc->tag_in_range_event->Signal(); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + if (nfc->nfc_tag_state != TagState::NotScanning && + nfc->nfc_tag_state != TagState::TagOutOfRange) { + LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast(nfc->nfc_tag_state.load())); + rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; } - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(result); + nfc->nfc_tag_state = TagState::Scanning; + + rb.Push(RESULT_SUCCESS); LOG_WARNING(Service_NFC, "(STUBBED) called, in_val={:04x}", in_val); } +void Module::Interface::GetTagInfo(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x11, 0, 0); + + if (nfc->nfc_tag_state != TagState::TagInRange && + nfc->nfc_tag_state != TagState::TagDataLoaded && nfc->nfc_tag_state != TagState::Unknown6) { + LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast(nfc->nfc_tag_state.load())); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + + TagInfo tag_info{}; + tag_info.uuid = nfc->amiibo_data.uuid; + tag_info.id_offset_size = tag_info.uuid.size(); + tag_info.unk1 = 0x0; + tag_info.unk2 = 0x2; + + IPC::RequestBuilder rb = rp.MakeBuilder(12, 0); + rb.Push(RESULT_SUCCESS); + rb.PushRaw(tag_info); + LOG_WARNING(Service_NFC, "(STUBBED) called"); +} + +void Module::Interface::GetAmiiboConfig(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x18, 0, 0); + + AmiiboConfig amiibo_config{}; + amiibo_config.lastwritedate_year = 2017; + amiibo_config.lastwritedate_month = 10; + amiibo_config.lastwritedate_day = 10; + // TODO(FearlessTobi): Find the right values for the struct + + IPC::RequestBuilder rb = rp.MakeBuilder(17, 0); + rb.Push(RESULT_SUCCESS); + rb.PushRaw(amiibo_config); + LOG_WARNING(Service_NFC, "(STUBBED) called"); +} + void Module::Interface::StopTagScanning(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x06, 0, 0); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + if (nfc->nfc_tag_state == TagState::NotInitialized || + nfc->nfc_tag_state == TagState::NotScanning) { + LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast(nfc->nfc_tag_state.load())); + rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + nfc->nfc_tag_state = TagState::NotScanning; - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_NFC, "(STUBBED) called"); + LOG_DEBUG(Service_NFC, "called"); } void Module::Interface::LoadAmiiboData(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x07, 0, 0); + // TODO(FearlessTobi): Add state checking when this function gets properly implemented + nfc->nfc_tag_state = TagState::TagDataLoaded; IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); @@ -92,29 +182,52 @@ void Module::Interface::LoadAmiiboData(Kernel::HLERequestContext& ctx) { void Module::Interface::ResetTagScanState(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x08, 0, 0); - nfc->nfc_tag_state = TagState::NotScanning; - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + if (nfc->nfc_tag_state != TagState::TagDataLoaded && nfc->nfc_tag_state != TagState::Unknown6) { + LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast(nfc->nfc_tag_state.load())); + rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + + nfc->nfc_tag_state = TagState::TagInRange; + rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_NFC, "(STUBBED) called"); + LOG_DEBUG(Service_NFC, "called"); } void Module::Interface::GetTagInRangeEvent(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0B, 0, 0); + if (nfc->nfc_tag_state != TagState::NotScanning) { + LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast(nfc->nfc_tag_state.load())); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(nfc->tag_in_range_event); - LOG_WARNING(Service_NFC, "(STUBBED) called"); + LOG_DEBUG(Service_NFC, "called"); } void Module::Interface::GetTagOutOfRangeEvent(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0C, 0, 0); + if (nfc->nfc_tag_state != TagState::NotScanning) { + LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast(nfc->nfc_tag_state.load())); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(nfc->tag_out_of_range_event); - LOG_WARNING(Service_NFC, "(STUBBED) called"); + LOG_DEBUG(Service_NFC, "called"); } void Module::Interface::GetTagState(Kernel::HLERequestContext& ctx) { @@ -122,8 +235,8 @@ void Module::Interface::GetTagState(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); - rb.PushEnum(nfc->nfc_tag_state); - LOG_DEBUG(Service_NFC, "(STUBBED) called"); + rb.PushEnum(nfc->nfc_tag_state.load()); + LOG_DEBUG(Service_NFC, "called"); } void Module::Interface::CommunicationGetStatus(Kernel::HLERequestContext& ctx) { @@ -135,6 +248,65 @@ void Module::Interface::CommunicationGetStatus(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NFC, "(STUBBED) called"); } +void Module::Interface::Unknown0x1A(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1A, 0, 0); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + if (nfc->nfc_tag_state != TagState::TagInRange) { + LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast(nfc->nfc_tag_state.load())); + rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + + nfc->nfc_tag_state = TagState::Unknown6; + + rb.Push(RESULT_SUCCESS); + LOG_DEBUG(Service_NFC, "called"); +} + +void Module::Interface::GetIdentificationBlock(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1B, 0, 0); + + if (nfc->nfc_tag_state != TagState::TagDataLoaded && nfc->nfc_tag_state != TagState::Unknown6) { + LOG_ERROR(Service_NFC, "Invalid TagState {}", static_cast(nfc->nfc_tag_state.load())); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + + IdentificationBlockReply identification_block_reply{}; + identification_block_reply.char_id = nfc->amiibo_data.char_id; + identification_block_reply.char_variant = nfc->amiibo_data.char_variant; + identification_block_reply.series = nfc->amiibo_data.series; + identification_block_reply.model_number = nfc->amiibo_data.model_number; + identification_block_reply.figure_type = nfc->amiibo_data.figure_type; + + IPC::RequestBuilder rb = rp.MakeBuilder(0x1F, 0); + rb.Push(RESULT_SUCCESS); + rb.PushRaw(identification_block_reply); + LOG_DEBUG(Service_NFC, "called"); +} + +std::shared_ptr Module::Interface::GetModule() const { + return nfc; +} + +void Module::Interface::LoadAmiibo(const AmiiboData& amiibo_data) { + std::lock_guard lock(HLE::g_hle_lock); + nfc->amiibo_data = amiibo_data; + nfc->nfc_tag_state = Service::NFC::TagState::TagInRange; + nfc->tag_in_range_event->Signal(); +} + +void Module::Interface::RemoveAmiibo() { + std::lock_guard lock(HLE::g_hle_lock); + nfc->nfc_tag_state = Service::NFC::TagState::TagOutOfRange; + nfc->tag_out_of_range_event->Signal(); + nfc->amiibo_data = {}; +} + Module::Interface::Interface(std::shared_ptr nfc, const char* name, u32 max_session) : ServiceFramework(name, max_session), nfc(std::move(nfc)) {} diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h index bafdcf0fa..afa05d60e 100644 --- a/src/core/hle/service/nfc/nfc.h +++ b/src/core/hle/service/nfc/nfc.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include "common/common_types.h" #include "core/hle/kernel/kernel.h" @@ -25,6 +26,19 @@ enum { }; } // namespace ErrCodes +// TODO(FearlessTobi): Add more members to this struct +struct AmiiboData { + std::array uuid; + INSERT_PADDING_BYTES(0x4D); + u16_le char_id; + u8 char_variant; + u8 figure_type; + u16_be model_number; + u8 series; + INSERT_PADDING_BYTES(0x1C1); +}; +static_assert(sizeof(AmiiboData) == 0x21C, "AmiiboData is an invalid size"); + enum class TagState : u8 { NotInitialized = 0, NotScanning = 1, @@ -32,6 +46,7 @@ enum class TagState : u8 { TagInRange = 3, TagOutOfRange = 4, TagDataLoaded = 5, + Unknown6 = 6, }; enum class CommunicationStatus : u8 { @@ -49,6 +64,12 @@ public: Interface(std::shared_ptr nfc, const char* name, u32 max_session); ~Interface(); + std::shared_ptr GetModule() const; + + void LoadAmiibo(const AmiiboData& amiibo_data); + + void RemoveAmiibo(); + protected: /** * NFC::Initialize service function @@ -167,6 +188,45 @@ public: */ void CommunicationGetStatus(Kernel::HLERequestContext& ctx); + /** + * NFC::GetTagInfo service function + * Inputs: + * 0 : Header code [0x00110000] + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2-12 : 0x2C-byte struct + */ + void GetTagInfo(Kernel::HLERequestContext& ctx); + + /** + * NFC::GetAmiiboConfig service function + * Inputs: + * 0 : Header code [0x00180000] + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2-17 : 0x40-byte config struct + */ + void GetAmiiboConfig(Kernel::HLERequestContext& ctx); + + /** + * NFC::Unknown0x1A service function + * Inputs: + * 0 : Header code [0x001A0000] + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void Unknown0x1A(Kernel::HLERequestContext& ctx); + + /** + * NFC::GetIdentificationBlock service function + * Inputs: + * 0 : Header code [0x001B0000] + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2-31 : 0x36-byte struct + */ + void GetIdentificationBlock(Kernel::HLERequestContext& ctx); + private: std::shared_ptr nfc; }; @@ -174,8 +234,10 @@ public: private: Kernel::SharedPtr tag_in_range_event; Kernel::SharedPtr tag_out_of_range_event; - TagState nfc_tag_state = TagState::NotInitialized; + std::atomic nfc_tag_state = TagState::NotInitialized; CommunicationStatus nfc_status = CommunicationStatus::NfcInitialized; + + AmiiboData amiibo_data{}; }; void InstallInterfaces(Core::System& system); diff --git a/src/core/hle/service/nfc/nfc_m.cpp b/src/core/hle/service/nfc/nfc_m.cpp index d91b6a31a..310490b8f 100644 --- a/src/core/hle/service/nfc/nfc_m.cpp +++ b/src/core/hle/service/nfc/nfc_m.cpp @@ -24,15 +24,17 @@ NFC_M::NFC_M(std::shared_ptr nfc) : Module::Interface(std::move(nfc), "n {0x000D0000, &NFC_M::GetTagState, "GetTagState"}, {0x000F0000, &NFC_M::CommunicationGetStatus, "CommunicationGetStatus"}, {0x00100000, nullptr, "GetTagInfo2"}, - {0x00110000, nullptr, "GetTagInfo"}, + {0x00110000, &NFC_M::GetTagInfo, "GetTagInfo"}, {0x00120000, nullptr, "CommunicationGetResult"}, {0x00130040, nullptr, "OpenAppData"}, {0x00140384, nullptr, "InitializeWriteAppData"}, {0x00150040, nullptr, "ReadAppData"}, {0x00160242, nullptr, "WriteAppData"}, {0x00170000, nullptr, "GetAmiiboSettings"}, - {0x00180000, nullptr, "GetAmiiboConfig"}, + {0x00180000, &NFC_M::GetAmiiboConfig, "GetAmiiboConfig"}, {0x00190000, nullptr, "GetAppDataInitStruct"}, + {0x001A0000, &NFC_M::Unknown0x1A, "Unknown0x1A"}, + {0x001B0000, &NFC_M::GetIdentificationBlock, "GetIdentificationBlock"}, // nfc:m {0x04040A40, nullptr, "SetAmiiboSettings"} // clang-format on diff --git a/src/core/hle/service/nfc/nfc_u.cpp b/src/core/hle/service/nfc/nfc_u.cpp index 8cdcca287..a6e99ace2 100644 --- a/src/core/hle/service/nfc/nfc_u.cpp +++ b/src/core/hle/service/nfc/nfc_u.cpp @@ -23,15 +23,17 @@ NFC_U::NFC_U(std::shared_ptr nfc) : Module::Interface(std::move(nfc), "n {0x000D0000, &NFC_U::GetTagState, "GetTagState"}, {0x000F0000, &NFC_U::CommunicationGetStatus, "CommunicationGetStatus"}, {0x00100000, nullptr, "GetTagInfo2"}, - {0x00110000, nullptr, "GetTagInfo"}, + {0x00110000, &NFC_U::GetTagInfo, "GetTagInfo"}, {0x00120000, nullptr, "CommunicationGetResult"}, {0x00130040, nullptr, "OpenAppData"}, {0x00140384, nullptr, "InitializeWriteAppData"}, {0x00150040, nullptr, "ReadAppData"}, {0x00160242, nullptr, "WriteAppData"}, {0x00170000, nullptr, "GetAmiiboSettings"}, - {0x00180000, nullptr, "GetAmiiboConfig"}, + {0x00180000, &NFC_U::GetAmiiboConfig, "GetAmiiboConfig"}, {0x00190000, nullptr, "GetAppDataInitStruct"}, + {0x001A0000, &NFC_U::Unknown0x1A, "Unknown0x1A"}, + {0x001B0000, &NFC_U::GetIdentificationBlock, "GetIdentificationBlock"}, // clang-format on }; RegisterHandlers(functions); From c5b7018625d93099647d600d886508619767c3b7 Mon Sep 17 00:00:00 2001 From: Pengfei Zhu Date: Thu, 25 Oct 2018 21:29:43 +0800 Subject: [PATCH 049/102] citra_qt: add seconds section to clock settings (#4347) * citra_qt: add seconds section to clock settings Simple fix to make the UI more usable. * Use an ISO styled format string Not actually tested locally --- src/citra_qt/configuration/configure_system.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/citra_qt/configuration/configure_system.ui b/src/citra_qt/configuration/configure_system.ui index 74efa3b27..51ad7c8ca 100644 --- a/src/citra_qt/configuration/configure_system.ui +++ b/src/citra_qt/configuration/configure_system.ui @@ -261,6 +261,9 @@ + + yyyy-MM-ddTHH:mm:ss + From 92b1a5c546b765a0f116d4d24388139b54a786fb Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 25 Oct 2018 14:30:46 -0400 Subject: [PATCH 050/102] citra_qt: fix translation for opengl version error variable in tr() won't trigger linguist to generate translation entry. Instead it needs a string literal --- src/citra_qt/main.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 669ced7f6..1c127a592 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -667,12 +667,12 @@ bool GMainWindow::LoadROM(const QString& filename) { render_window->InitRenderTarget(); render_window->MakeCurrent(); - const char* below_gl33_title = "OpenGL 3.3 Unsupported"; - const char* below_gl33_message = "Your GPU may not support OpenGL 3.3, or you do not " - "have the latest graphics driver."; + const QString below_gl33_title = tr("OpenGL 3.3 Unsupported"); + const QString below_gl33_message = tr("Your GPU may not support OpenGL 3.3, or you do not " + "have the latest graphics driver."); if (!gladLoadGL()) { - QMessageBox::critical(this, tr(below_gl33_title), tr(below_gl33_message)); + QMessageBox::critical(this, below_gl33_title, below_gl33_message); return false; } @@ -743,7 +743,7 @@ bool GMainWindow::LoadROM(const QString& filename) { break; case Core::System::ResultStatus::ErrorVideoCore_ErrorBelowGL33: - QMessageBox::critical(this, tr(below_gl33_title), tr(below_gl33_message)); + QMessageBox::critical(this, below_gl33_title, below_gl33_message); break; default: From e5c5d1eccee6dbeb4d2e20dd3d1a80e8f0b4ce26 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 25 Oct 2018 19:54:06 -0400 Subject: [PATCH 051/102] Kernel: change owner_process in Thread/SharedMemory to raw pointer Otherwise circular ownership would form in Process->handle_table->thread->owner_process --- src/core/hle/kernel/kernel.h | 4 ++-- src/core/hle/kernel/shared_memory.cpp | 2 +- src/core/hle/kernel/shared_memory.h | 2 +- src/core/hle/kernel/svc.cpp | 8 ++++---- src/core/hle/kernel/thread.cpp | 5 ++--- src/core/hle/kernel/thread.h | 2 +- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index d461dc6e8..223b3ce37 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -102,7 +102,7 @@ public: */ ResultVal> CreateThread(std::string name, VAddr entry_point, u32 priority, u32 arg, s32 processor_id, VAddr stack_top, - SharedPtr owner_process); + Process* owner_process); /** * Creates a semaphore. @@ -156,7 +156,7 @@ public: * linear heap. * @param name Optional object name, used for debugging purposes. */ - SharedPtr CreateSharedMemory(SharedPtr owner_process, u32 size, + SharedPtr CreateSharedMemory(Process* owner_process, u32 size, MemoryPermission permissions, MemoryPermission other_permissions, VAddr address = 0, diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 70a937222..4f0b2e8ee 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -14,7 +14,7 @@ namespace Kernel { SharedMemory::SharedMemory(KernelSystem& kernel) : Object(kernel) {} SharedMemory::~SharedMemory() {} -SharedPtr KernelSystem::CreateSharedMemory(SharedPtr owner_process, u32 size, +SharedPtr KernelSystem::CreateSharedMemory(Process* owner_process, u32 size, MemoryPermission permissions, MemoryPermission other_permissions, VAddr address, MemoryRegion region, diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index d5d862927..18a87b9fe 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -58,7 +58,7 @@ public: u8* GetPointer(u32 offset = 0); /// Process that created this shared memory block. - SharedPtr owner_process; + Process* owner_process; /// Address of shared memory block in the owner process if specified. VAddr base_address; /// Physical address of the shared memory block in the linear heap if no address was specified diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 94a820f34..0e7a21c0a 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -785,9 +785,9 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point break; } - CASCADE_RESULT(SharedPtr thread, - Core::System::GetInstance().Kernel().CreateThread( - name, entry_point, priority, arg, processor_id, stack_top, current_process)); + CASCADE_RESULT(SharedPtr thread, Core::System::GetInstance().Kernel().CreateThread( + name, entry_point, priority, arg, processor_id, + stack_top, current_process.get())); thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO); // 0x03C00000 @@ -1157,7 +1157,7 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 region = current_process->flags.memory_region; shared_memory = Core::System::GetInstance().Kernel().CreateSharedMemory( - current_process, size, static_cast(my_permission), + current_process.get(), size, static_cast(my_permission), static_cast(other_permission), addr, region); CASCADE_RESULT(*out_handle, current_process->handle_table.Create(std::move(shared_memory))); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 69680acf8..11ea54fbd 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -320,8 +320,7 @@ static void ResetThreadContext(const std::unique_ptr> KernelSystem::CreateThread(std::string name, VAddr entry_point, u32 priority, u32 arg, s32 processor_id, - VAddr stack_top, - SharedPtr owner_process) { + VAddr stack_top, Process* owner_process) { // Check if priority is in ranged. Lowest priority -> highest priority id. if (priority > ThreadPrioLowest) { LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); @@ -447,7 +446,7 @@ SharedPtr SetupMainThread(KernelSystem& kernel, u32 entry_point, u32 pri // Initialize new "main" thread auto thread_res = kernel.CreateThread("main", entry_point, priority, 0, owner_process->ideal_processor, - Memory::HEAP_VADDR_END, owner_process); + Memory::HEAP_VADDR_END, owner_process.get()); SharedPtr thread = std::move(thread_res).Unwrap(); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index bb0ab5b15..9c7dd45cc 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -189,7 +189,7 @@ public: /// Mutexes that this thread is currently waiting for. boost::container::flat_set> pending_mutexes; - SharedPtr owner_process; ///< Process that owns this thread + Process* owner_process; ///< Process that owns this thread /// Objects that the thread is waiting on, in the same order as they were // passed to WaitSynchronization1/N. From fa0e82b8129b9071b9c2dbbd87929837f70690cd Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 25 Oct 2018 21:39:26 -0400 Subject: [PATCH 052/102] SeedDB: replace seek(tell, set) with seek(cur) (#4344) --- src/core/file_sys/seed_db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/file_sys/seed_db.cpp b/src/core/file_sys/seed_db.cpp index 56009d293..f5b38fb0e 100644 --- a/src/core/file_sys/seed_db.cpp +++ b/src/core/file_sys/seed_db.cpp @@ -34,7 +34,7 @@ bool SeedDB::Load() { LOG_ERROR(Service_FS, "Failed to read seed database count fully"); return false; } - if (!file.Seek(file.Tell() + SEEDDB_PADDING_BYTES, SEEK_SET)) { + if (!file.Seek(SEEDDB_PADDING_BYTES, SEEK_CUR)) { LOG_ERROR(Service_FS, "Failed to skip seed database padding"); return false; } From b4062abc11e5920ea753282304e83065e0572c04 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Fri, 26 Oct 2018 00:32:41 -0400 Subject: [PATCH 053/102] cubeb_sink: ignore null-name device when selecting We already ignore them on listing devices. We should do the same when selecting devices. This fix a crash when opening a specific device while there is a null device in the list --- src/audio_core/cubeb_sink.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp index 790629336..29e353fe4 100644 --- a/src/audio_core/cubeb_sink.cpp +++ b/src/audio_core/cubeb_sink.cpp @@ -56,7 +56,8 @@ CubebSink::CubebSink(std::string target_device_name) : impl(std::make_uniquedevid; From 8ad6cbfde2bcd59ad1571eb06085b37ca67e5bde Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Fri, 26 Oct 2018 09:37:46 -0400 Subject: [PATCH 054/102] kernel/thread: change owner_process parameter to reference To enforce a valid process object --- src/core/hle/kernel/kernel.h | 2 +- src/core/hle/kernel/svc.cpp | 2 +- src/core/hle/kernel/thread.cpp | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 223b3ce37..344635c6a 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -102,7 +102,7 @@ public: */ ResultVal> CreateThread(std::string name, VAddr entry_point, u32 priority, u32 arg, s32 processor_id, VAddr stack_top, - Process* owner_process); + Process& owner_process); /** * Creates a semaphore. diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 0e7a21c0a..6a33736ba 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -787,7 +787,7 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point CASCADE_RESULT(SharedPtr thread, Core::System::GetInstance().Kernel().CreateThread( name, entry_point, priority, arg, processor_id, - stack_top, current_process.get())); + stack_top, *current_process)); thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO); // 0x03C00000 diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 11ea54fbd..a7b6eba1e 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -320,7 +320,7 @@ static void ResetThreadContext(const std::unique_ptr> KernelSystem::CreateThread(std::string name, VAddr entry_point, u32 priority, u32 arg, s32 processor_id, - VAddr stack_top, Process* owner_process) { + VAddr stack_top, Process& owner_process) { // Check if priority is in ranged. Lowest priority -> highest priority id. if (priority > ThreadPrioLowest) { LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); @@ -334,7 +334,7 @@ ResultVal> KernelSystem::CreateThread(std::string name, VAddr // TODO(yuriks): Other checks, returning 0xD9001BEA - if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) { + if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) { LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:08x}", name, entry_point); // TODO: Verify error return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, @@ -357,10 +357,10 @@ ResultVal> KernelSystem::CreateThread(std::string name, VAddr thread->wait_address = 0; thread->name = std::move(name); wakeup_callback_table[thread->thread_id] = thread.get(); - thread->owner_process = owner_process; + thread->owner_process = &owner_process; // Find the next available TLS index, and mark it as used - auto& tls_slots = owner_process->tls_slots; + auto& tls_slots = owner_process.tls_slots; auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots); @@ -381,13 +381,13 @@ ResultVal> KernelSystem::CreateThread(std::string name, VAddr // Allocate some memory from the end of the linear heap for this region. linheap_memory->insert(linheap_memory->end(), Memory::PAGE_SIZE, 0); memory_region->used += Memory::PAGE_SIZE; - owner_process->linear_heap_used += Memory::PAGE_SIZE; + owner_process.linear_heap_used += Memory::PAGE_SIZE; tls_slots.emplace_back(0); // The page is completely available at the start available_page = tls_slots.size() - 1; available_slot = 0; // Use the first slot in the new page - auto& vm_manager = owner_process->vm_manager; + auto& vm_manager = owner_process.vm_manager; vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); // Map the page to the current process' address space. @@ -446,7 +446,7 @@ SharedPtr SetupMainThread(KernelSystem& kernel, u32 entry_point, u32 pri // Initialize new "main" thread auto thread_res = kernel.CreateThread("main", entry_point, priority, 0, owner_process->ideal_processor, - Memory::HEAP_VADDR_END, owner_process.get()); + Memory::HEAP_VADDR_END, *owner_process); SharedPtr thread = std::move(thread_res).Unwrap(); From ccd5ceeaf7f61f5465356966ac2047127e16909f Mon Sep 17 00:00:00 2001 From: Frederic Laing <27208977+FreddyFunk@users.noreply.github.com> Date: Fri, 26 Oct 2018 15:55:46 +0200 Subject: [PATCH 055/102] Removed unused import binascii --- dist/scripting/citra.py | 1 - 1 file changed, 1 deletion(-) diff --git a/dist/scripting/citra.py b/dist/scripting/citra.py index 869f64041..be6068685 100644 --- a/dist/scripting/citra.py +++ b/dist/scripting/citra.py @@ -1,7 +1,6 @@ import zmq import struct import random -import binascii import enum CURRENT_REQUEST_VERSION = 1 From 34f1fe088cca4621422757dbc9828f86bd83b234 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Tue, 23 Oct 2018 09:57:59 -0400 Subject: [PATCH 056/102] kernel/thread: add ThreadManager --- src/core/hle/kernel/kernel.cpp | 9 +++++++++ src/core/hle/kernel/kernel.h | 6 ++++++ src/core/hle/kernel/thread.cpp | 4 +++- src/core/hle/kernel/thread.h | 6 ++++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index afe6af195..0811fa699 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -21,6 +21,7 @@ KernelSystem::KernelSystem(u32 system_mode) { Kernel::MemoryInit(system_mode); resource_limits = std::make_unique(*this); + thread_manager = std::make_unique(); Kernel::ThreadingInit(); Kernel::TimersInit(); } @@ -53,4 +54,12 @@ void KernelSystem::SetCurrentProcess(SharedPtr process) { current_process = std::move(process); } +ThreadManager& KernelSystem::GetThreadManager() { + return *thread_manager; +} + +const ThreadManager& KernelSystem::GetThreadManager() const { + return *thread_manager; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 344635c6a..83f622670 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -28,6 +28,7 @@ class ClientSession; class ServerSession; class ResourceLimitList; class SharedMemory; +class ThreadManager; enum class ResetType { OneShot, @@ -187,6 +188,9 @@ public: SharedPtr GetCurrentProcess() const; void SetCurrentProcess(SharedPtr process); + ThreadManager& GetThreadManager(); + const ThreadManager& GetThreadManager() const; + private: std::unique_ptr resource_limits; std::atomic next_object_id{0}; @@ -199,6 +203,8 @@ private: std::vector> process_list; SharedPtr current_process; + + std::unique_ptr thread_manager; }; } // namespace Kernel diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index a7b6eba1e..1c835f601 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -59,7 +59,9 @@ inline static u32 const NewThreadId() { return next_thread_id++; } -Thread::Thread(KernelSystem& kernel) : WaitObject(kernel), context(Core::CPU().NewContext()) {} +Thread::Thread(KernelSystem& kernel) + : WaitObject(kernel), context(Core::CPU().NewContext()), + thread_manager(kernel.GetThreadManager()) {} Thread::~Thread() {} Thread* GetCurrentThread() { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 9c7dd45cc..6c9df27ff 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -53,6 +53,10 @@ enum class ThreadWakeupReason { Timeout // The thread was woken up due to a wait timeout. }; +class ThreadManager { +public: +}; + class Thread final : public WaitObject { public: std::string GetName() const override { @@ -210,6 +214,8 @@ private: explicit Thread(KernelSystem&); ~Thread() override; + ThreadManager& thread_manager; + friend class KernelSystem; }; From 876729ab525a6298468bf7c4760c910309a0d5eb Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Tue, 23 Oct 2018 10:32:23 -0400 Subject: [PATCH 057/102] kernel/thread: move next_thread_id into manager --- src/core/hle/kernel/thread.cpp | 12 ++---------- src/core/hle/kernel/thread.h | 8 ++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 1c835f601..80cbe789a 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -48,14 +48,7 @@ static Common::ThreadQueueList ready_queue; static SharedPtr current_thread; -// The first available thread id at startup -static u32 next_thread_id; - -/** - * Creates a new thread ID - * @return The new thread ID - */ -inline static u32 const NewThreadId() { +u32 ThreadManager::NewThreadId() { return next_thread_id++; } @@ -348,7 +341,7 @@ ResultVal> KernelSystem::CreateThread(std::string name, VAddr thread_list.push_back(thread); ready_queue.prepare(priority); - thread->thread_id = NewThreadId(); + thread->thread_id = thread_manager->NewThreadId(); thread->status = ThreadStatus::Dormant; thread->entry_point = entry_point; thread->stack_top = stack_top; @@ -504,7 +497,6 @@ void ThreadingInit() { ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); current_thread = nullptr; - next_thread_id = 1; } void ThreadingShutdown() { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 6c9df27ff..759332254 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -55,6 +55,14 @@ enum class ThreadWakeupReason { class ThreadManager { public: + /** + * Creates a new thread ID + * @return The new thread ID + */ + u32 NewThreadId(); + +private: + u32 next_thread_id = 1; }; class Thread final : public WaitObject { From 0478bc3dee06087b84106803cb13a45cda1daa7a Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Tue, 23 Oct 2018 11:40:57 -0400 Subject: [PATCH 058/102] Kernel/Thread: move thread queue, current thread, and scheduling related function into the manager As we touched it, remove IPC::GetCommandBuffer --- src/core/arm/dynarmic/arm_dynarmic.cpp | 3 +- src/core/arm/skyeye_common/armstate.cpp | 3 +- src/core/core.cpp | 4 +- src/core/hle/ipc.h | 21 ------ src/core/hle/kernel/handle_table.cpp | 2 +- src/core/hle/kernel/hle_ipc.h | 3 +- src/core/hle/kernel/mutex.cpp | 2 +- src/core/hle/kernel/svc.cpp | 73 +++++++++++---------- src/core/hle/kernel/thread.cpp | 54 +++++----------- src/core/hle/kernel/thread.h | 85 ++++++++++++++----------- src/core/hle/service/fs/file.cpp | 3 +- src/core/hle/service/nwm/nwm_uds.cpp | 3 +- src/core/hle/service/service.cpp | 9 +-- src/core/hle/service/sm/srv.cpp | 4 +- 14 files changed, 123 insertions(+), 146 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 3cfd2a6d6..b079afa9a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -134,7 +134,8 @@ public: if (GDBStub::IsConnected()) { parent.jit->HaltExecution(); parent.SetPC(pc); - Kernel::Thread* thread = Kernel::GetCurrentThread(); + Kernel::Thread* thread = + Core::System::GetInstance().Kernel().GetThreadManager().GetCurrentThread(); parent.SaveContext(thread->context); GDBStub::Break(); GDBStub::SendTrap(thread, 5); diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp index 88ad7f533..a28f5a87f 100644 --- a/src/core/arm/skyeye_common/armstate.cpp +++ b/src/core/arm/skyeye_common/armstate.cpp @@ -604,7 +604,8 @@ void ARMul_State::ServeBreak() { if (last_bkpt_hit) { Reg[15] = last_bkpt.address; } - Kernel::Thread* thread = Kernel::GetCurrentThread(); + Kernel::Thread* thread = + Core::System::GetInstance().Kernel().GetThreadManager().GetCurrentThread(); Core::CPU().SaveContext(thread->context); if (last_bkpt_hit || GDBStub::GetCpuStepFlag()) { last_bkpt_hit = false; diff --git a/src/core/core.cpp b/src/core/core.cpp index 910083644..695afef4f 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -59,7 +59,7 @@ System::ResultStatus System::RunLoop(bool tight_loop) { // If we don't have a currently active thread then don't execute instructions, // instead advance to the next event and try to yield to the next thread - if (Kernel::GetCurrentThread() == nullptr) { + if (Kernel().GetThreadManager().GetCurrentThread() == nullptr) { LOG_TRACE(Core_ARM11, "Idling"); CoreTiming::Idle(); CoreTiming::Advance(); @@ -164,7 +164,7 @@ void System::Reschedule() { } reschedule_pending = false; - Kernel::Reschedule(); + kernel->GetThreadManager().Reschedule(); } System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index e9c7d1b0f..7736f5fca 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h @@ -9,27 +9,6 @@ #include "core/hle/kernel/thread.h" #include "core/memory.h" -namespace Kernel { - -/// Offset into command buffer of header -static const int kCommandHeaderOffset = 0x80; - -/** - * Returns a pointer to the command buffer in the current thread's TLS - * TODO(Subv): This is not entirely correct, the command buffer should be copied from - * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to - * the service handler process' memory. - * @param offset Optional offset into command buffer - * @param offset Optional offset into command buffer (in bytes) - * @return Pointer to command buffer - */ -inline u32* GetCommandBuffer(const int offset = 0) { - return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + - offset); -} - -} // namespace Kernel - namespace IPC { /// Size of the command buffer area, in 32-bit words. diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 87ba03f36..15dcc4583 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -72,7 +72,7 @@ bool HandleTable::IsValid(Handle handle) const { SharedPtr HandleTable::GetGeneric(Handle handle) const { if (handle == CurrentThread) { - return GetCurrentThread(); + return kernel.GetThreadManager().GetCurrentThread(); } else if (handle == CurrentProcess) { return kernel.GetCurrentProcess(); } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index a41264834..4e0c31d98 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -124,8 +124,7 @@ private: /** * Class containing information about an in-flight IPC request being handled by an HLE service - * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and - * when possible use the APIs in this class to service the request. + * implementation. * * HLE handle protocol * =================== diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index f31a2a5d7..88d03d8f2 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -36,7 +36,7 @@ SharedPtr KernelSystem::CreateMutex(bool initial_locked, std::string name // Acquire mutex with current thread if initialized as locked if (initial_locked) - mutex->Acquire(GetCurrentThread()); + mutex->Acquire(thread_manager->GetCurrentThread()); return mutex; } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 6a33736ba..840a36ca7 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -145,7 +145,8 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add } static void ExitProcess() { - SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + SharedPtr current_process = kernel.GetCurrentProcess(); LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->process_id); ASSERT_MSG(current_process->status == ProcessStatus::Running, "Process has already exited"); @@ -158,7 +159,7 @@ static void ExitProcess() { if (thread->owner_process != current_process) continue; - if (thread == GetCurrentThread()) + if (thread == kernel.GetThreadManager().GetCurrentThread()) continue; // TODO(Subv): When are the other running/ready threads terminated? @@ -170,7 +171,7 @@ static void ExitProcess() { } // Kill the current thread - GetCurrentThread()->Stop(); + kernel.GetThreadManager().GetCurrentThread()->Stop(); Core::System::GetInstance().PrepareReschedule(); } @@ -254,9 +255,9 @@ static ResultCode ConnectToPort(Handle* out_handle, VAddr port_name_address) { /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Handle handle) { + KernelSystem& kernel = Core::System::GetInstance().Kernel(); SharedPtr session = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( - handle); + kernel.GetCurrentProcess()->handle_table.Get(handle); if (session == nullptr) { return ERR_INVALID_HANDLE; } @@ -265,7 +266,7 @@ static ResultCode SendSyncRequest(Handle handle) { Core::System::GetInstance().PrepareReschedule(); - return session->SendSyncRequest(GetCurrentThread()); + return session->SendSyncRequest(kernel.GetThreadManager().GetCurrentThread()); } /// Close a handle @@ -276,10 +277,9 @@ static ResultCode CloseHandle(Handle handle) { /// Wait for a handle to synchronize, timeout after the specified nanoseconds static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { - auto object = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( - handle); - Thread* thread = GetCurrentThread(); + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + auto object = kernel.GetCurrentProcess()->handle_table.Get(handle); + Thread* thread = kernel.GetThreadManager().GetCurrentThread(); if (object == nullptr) return ERR_INVALID_HANDLE; @@ -331,7 +331,8 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { /// Wait for the given handles to synchronize, timeout after the specified nanoseconds static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle_count, bool wait_all, s64 nano_seconds) { - Thread* thread = GetCurrentThread(); + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + Thread* thread = kernel.GetThreadManager().GetCurrentThread(); if (!Memory::IsValidVirtualAddress(handles_address)) return ERR_INVALID_POINTER; @@ -349,9 +350,7 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand for (int i = 0; i < handle_count; ++i) { Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); - auto object = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( - handle); + auto object = kernel.GetCurrentProcess()->handle_table.Get(handle); if (object == nullptr) return ERR_INVALID_HANDLE; objects[i] = object; @@ -515,7 +514,8 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ using ObjectPtr = SharedPtr; std::vector objects(handle_count); - SharedPtr current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + SharedPtr current_process = kernel.GetCurrentProcess(); for (int i = 0; i < handle_count; ++i) { Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); @@ -527,8 +527,9 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ // We are also sending a command reply. // Do not send a reply if the command id in the command buffer is 0xFFFF. - u32* cmd_buff = GetCommandBuffer(); - IPC::Header header{cmd_buff[0]}; + Thread* thread = kernel.GetThreadManager().GetCurrentThread(); + u32 cmd_buff_header = Memory::Read32(thread->GetCommandBufferAddress()); + IPC::Header header{cmd_buff_header}; if (reply_target != 0 && header.command_id != 0xFFFF) { auto session = current_process->handle_table.Get(reply_target); if (session == nullptr) @@ -546,11 +547,11 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ return ERR_SESSION_CLOSED_BY_REMOTE; } - VAddr source_address = GetCurrentThread()->GetCommandBufferAddress(); + VAddr source_address = thread->GetCommandBufferAddress(); VAddr target_address = request_thread->GetCommandBufferAddress(); - ResultCode translation_result = TranslateCommandBuffer( - Kernel::GetCurrentThread(), request_thread, source_address, target_address, true); + ResultCode translation_result = + TranslateCommandBuffer(thread, request_thread, source_address, target_address, true); // Note: The real kernel seems to always panic if the Server->Client buffer translation // fails for whatever reason. @@ -570,8 +571,6 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ return RESULT_SUCCESS; } - auto thread = GetCurrentThread(); - // Find the first object that is acquirable in the provided list of objects auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) { return !object->ShouldWait(thread); @@ -587,7 +586,7 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ return RESULT_SUCCESS; auto server_session = static_cast(object); - return ReceiveIPCRequest(server_session, GetCurrentThread()); + return ReceiveIPCRequest(server_session, thread); } // No objects were ready to be acquired, prepare to suspend the thread. @@ -644,14 +643,16 @@ static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 val LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}, address=0x{:08X}, type=0x{:08X}, value=0x{:08X}", handle, address, type, value); + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + SharedPtr arbiter = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get( - handle); + kernel.GetCurrentProcess()->handle_table.Get(handle); if (arbiter == nullptr) return ERR_INVALID_HANDLE; - auto res = arbiter->ArbitrateAddress(GetCurrentThread(), static_cast(type), - address, value, nanoseconds); + auto res = + arbiter->ArbitrateAddress(kernel.GetThreadManager().GetCurrentThread(), + static_cast(type), address, value, nanoseconds); // TODO(Subv): Identify in which specific cases this call should cause a reschedule. Core::System::GetInstance().PrepareReschedule(); @@ -808,7 +809,7 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point static void ExitThread() { LOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CPU().GetPC()); - ExitCurrentThread(); + Core::System::GetInstance().Kernel().GetThreadManager().ExitCurrentThread(); Core::System::GetInstance().PrepareReschedule(); } @@ -870,12 +871,13 @@ static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { static ResultCode ReleaseMutex(Handle handle) { LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}", handle); - SharedPtr mutex = - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get(handle); + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + + SharedPtr mutex = kernel.GetCurrentProcess()->handle_table.Get(handle); if (mutex == nullptr) return ERR_INVALID_HANDLE; - return mutex->Release(GetCurrentThread()); + return mutex->Release(kernel.GetThreadManager().GetCurrentThread()); } /// Get the ID of the specified process @@ -1090,16 +1092,19 @@ static ResultCode CancelTimer(Handle handle) { static void SleepThread(s64 nanoseconds) { LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + ThreadManager& thread_manager = kernel.GetThreadManager(); + // Don't attempt to yield execution if there are no available threads to run, // this way we avoid a useless reschedule to the idle thread. - if (nanoseconds == 0 && !HaveReadyThreads()) + if (nanoseconds == 0 && !thread_manager.HaveReadyThreads()) return; // Sleep current thread and check for next thread to schedule - WaitCurrentThread_Sleep(); + thread_manager.WaitCurrentThread_Sleep(); // Create an event to wake the thread up after the specified nanosecond delay has passed - GetCurrentThread()->WakeAfterDelay(nanoseconds); + thread_manager.GetCurrentThread()->WakeAfterDelay(nanoseconds); Core::System::GetInstance().PrepareReschedule(); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 80cbe789a..71817675d 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -10,7 +10,6 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/math_util.h" -#include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" #include "core/arm/skyeye_common/armstate.h" #include "core/core.h" @@ -43,11 +42,6 @@ static std::unordered_map wakeup_callback_table; // Lists all thread ids that aren't deleted/etc. static std::vector> thread_list; -// Lists only ready thread ids. -static Common::ThreadQueueList ready_queue; - -static SharedPtr current_thread; - u32 ThreadManager::NewThreadId() { return next_thread_id++; } @@ -57,7 +51,7 @@ Thread::Thread(KernelSystem& kernel) thread_manager(kernel.GetThreadManager()) {} Thread::~Thread() {} -Thread* GetCurrentThread() { +Thread* ThreadManager::GetCurrentThread() const { return current_thread.get(); } @@ -69,7 +63,7 @@ void Thread::Stop() { // Clean up thread from ready queue // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) if (status == ThreadStatus::Ready) { - ready_queue.remove(current_priority, this); + thread_manager.ready_queue.remove(current_priority, this); } status = ThreadStatus::Dead; @@ -92,11 +86,7 @@ void Thread::Stop() { owner_process->tls_slots[tls_page].reset(tls_slot); } -/** - * Switches the CPU's active thread context to that of the specified thread - * @param new_thread The thread to switch to - */ -static void SwitchContext(Thread* new_thread) { +void ThreadManager::SwitchContext(Thread* new_thread) { Thread* previous_thread = GetCurrentThread(); // Save context for previous thread @@ -141,11 +131,7 @@ static void SwitchContext(Thread* new_thread) { } } -/** - * Pops and returns the next thread from the thread queue - * @return A pointer to the next ready thread - */ -static Thread* PopNextReadyThread() { +Thread* ThreadManager::PopNextReadyThread() { Thread* next; Thread* thread = GetCurrentThread(); @@ -164,12 +150,12 @@ static Thread* PopNextReadyThread() { return next; } -void WaitCurrentThread_Sleep() { +void ThreadManager::WaitCurrentThread_Sleep() { Thread* thread = GetCurrentThread(); thread->status = ThreadStatus::WaitSleep; } -void ExitCurrentThread() { +void ThreadManager::ExitCurrentThread() { Thread* thread = GetCurrentThread(); thread->Stop(); thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), @@ -246,15 +232,12 @@ void Thread::ResumeFromWait() { wakeup_callback = nullptr; - ready_queue.push_back(current_priority, this); + thread_manager.ready_queue.push_back(current_priority, this); status = ThreadStatus::Ready; Core::System::GetInstance().PrepareReschedule(); } -/** - * Prints the thread queue for debugging purposes - */ -static void DebugThreadQueue() { +void ThreadManager::DebugThreadQueue() { Thread* thread = GetCurrentThread(); if (!thread) { LOG_DEBUG(Kernel, "Current: NO CURRENT THREAD"); @@ -339,7 +322,7 @@ ResultVal> KernelSystem::CreateThread(std::string name, VAddr SharedPtr thread(new Thread(*this)); thread_list.push_back(thread); - ready_queue.prepare(priority); + thread_manager->ready_queue.prepare(priority); thread->thread_id = thread_manager->NewThreadId(); thread->status = ThreadStatus::Dormant; @@ -400,7 +383,7 @@ ResultVal> KernelSystem::CreateThread(std::string name, VAddr // to initialize the context ResetThreadContext(thread->context, stack_top, entry_point, arg); - ready_queue.push_back(thread->current_priority, thread.get()); + thread_manager->ready_queue.push_back(thread->current_priority, thread.get()); thread->status = ThreadStatus::Ready; return MakeResult>(std::move(thread)); @@ -411,9 +394,9 @@ void Thread::SetPriority(u32 priority) { "Invalid priority value."); // If thread was ready, adjust queues if (status == ThreadStatus::Ready) - ready_queue.move(this, current_priority, priority); + thread_manager.ready_queue.move(this, current_priority, priority); else - ready_queue.prepare(priority); + thread_manager.ready_queue.prepare(priority); nominal_priority = current_priority = priority; } @@ -430,9 +413,9 @@ void Thread::UpdatePriority() { void Thread::BoostPriority(u32 priority) { // If thread was ready, adjust queues if (status == ThreadStatus::Ready) - ready_queue.move(this, current_priority, priority); + thread_manager.ready_queue.move(this, current_priority, priority); else - ready_queue.prepare(priority); + thread_manager.ready_queue.prepare(priority); current_priority = priority; } @@ -452,11 +435,11 @@ SharedPtr SetupMainThread(KernelSystem& kernel, u32 entry_point, u32 pri return thread; } -bool HaveReadyThreads() { +bool ThreadManager::HaveReadyThreads() { return ready_queue.get_first() != nullptr; } -void Reschedule() { +void ThreadManager::Reschedule() { Thread* cur = GetCurrentThread(); Thread* next = PopNextReadyThread(); @@ -495,18 +478,13 @@ VAddr Thread::GetCommandBufferAddress() const { void ThreadingInit() { ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); - - current_thread = nullptr; } void ThreadingShutdown() { - current_thread = nullptr; - for (auto& t : thread_list) { t->Stop(); } thread_list.clear(); - ready_queue.clear(); } const std::vector>& GetThreadList() { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 759332254..4a9384bd8 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -10,6 +10,7 @@ #include #include #include "common/common_types.h" +#include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/wait_object.h" @@ -61,8 +62,55 @@ public: */ u32 NewThreadId(); + /** + * Gets the current thread + */ + Thread* GetCurrentThread() const; + + /** + * Reschedules to the next available thread (call after current thread is suspended) + */ + void Reschedule(); + + /** + * Prints the thread queue for debugging purposes + */ + void DebugThreadQueue(); + + /** + * Returns whether there are any threads that are ready to run. + */ + bool HaveReadyThreads(); + + /** + * Waits the current thread on a sleep + */ + void WaitCurrentThread_Sleep(); + + /** + * Stops the current thread and removes it from the thread_list + */ + void ExitCurrentThread(); + private: + /** + * Switches the CPU's active thread context to that of the specified thread + * @param new_thread The thread to switch to + */ + void SwitchContext(Thread* new_thread); + + /** + * Pops and returns the next thread from the thread queue + * @return A pointer to the next ready thread + */ + Thread* PopNextReadyThread(); + u32 next_thread_id = 1; + SharedPtr current_thread; + Common::ThreadQueueList ready_queue; + + friend class Thread; + friend class KernelSystem; }; class Thread final : public WaitObject { @@ -238,43 +286,6 @@ private: SharedPtr SetupMainThread(KernelSystem& kernel, u32 entry_point, u32 priority, SharedPtr owner_process); -/** - * Returns whether there are any threads that are ready to run. - */ -bool HaveReadyThreads(); - -/** - * Reschedules to the next available thread (call after current thread is suspended) - */ -void Reschedule(); - -/** - * Arbitrate the highest priority thread that is waiting - * @param address The address for which waiting threads should be arbitrated - */ -Thread* ArbitrateHighestPriorityThread(u32 address); - -/** - * Arbitrate all threads currently waiting. - * @param address The address for which waiting threads should be arbitrated - */ -void ArbitrateAllThreads(u32 address); - -/** - * Gets the current thread - */ -Thread* GetCurrentThread(); - -/** - * Waits the current thread on a sleep - */ -void WaitCurrentThread_Sleep(); - -/** - * Stops the current thread and removes it from the thread_list - */ -void ExitCurrentThread(); - /** * Initialize threading */ diff --git a/src/core/hle/service/fs/file.cpp b/src/core/hle/service/fs/file.cpp index 59635cab8..d4beda2c4 100644 --- a/src/core/hle/service/fs/file.cpp +++ b/src/core/hle/service/fs/file.cpp @@ -71,7 +71,8 @@ void File::Read(Kernel::HLERequestContext& ctx) { rb.PushMappedBuffer(buffer); std::chrono::nanoseconds read_timeout_ns{backend->GetReadDelayNs(length)}; - ctx.SleepClientThread(Kernel::GetCurrentThread(), "file::read", read_timeout_ns, + ctx.SleepClientThread(system.Kernel().GetThreadManager().GetCurrentThread(), "file::read", + read_timeout_ns, [](Kernel::SharedPtr thread, Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) { // Nothing to do here diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp index 4072aac09..735f485a8 100644 --- a/src/core/hle/service/nwm/nwm_uds.cpp +++ b/src/core/hle/service/nwm/nwm_uds.cpp @@ -1231,7 +1231,8 @@ void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx) { static constexpr std::chrono::nanoseconds UDSConnectionTimeout{300000000}; connection_event = ctx.SleepClientThread( - Kernel::GetCurrentThread(), "uds::ConnectToNetwork", UDSConnectionTimeout, + system.Kernel().GetThreadManager().GetCurrentThread(), "uds::ConnectToNetwork", + UDSConnectionTimeout, [](Kernel::SharedPtr thread, Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) { // TODO(B3N30): Add error handling for host full and timeout diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 1217376b1..2402a786d 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -179,7 +179,10 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(u32* cmd_buf, const Funct } void ServiceFrameworkBase::HandleSyncRequest(SharedPtr server_session) { - u32* cmd_buf = Kernel::GetCommandBuffer(); + Kernel::KernelSystem& kernel = Core::System::GetInstance().Kernel(); + auto thread = kernel.GetThreadManager().GetCurrentThread(); + // TODO(wwylele): avoid GetPointer + u32* cmd_buf = reinterpret_cast(Memory::GetPointer(thread->GetCommandBufferAddress())); u32 header_code = cmd_buf[0]; auto itr = handlers.find(header_code); @@ -188,8 +191,7 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr server_ses return ReportUnimplementedFunction(cmd_buf, info); } - Kernel::SharedPtr current_process = - Core::System::GetInstance().Kernel().GetCurrentProcess(); + Kernel::SharedPtr current_process = kernel.GetCurrentProcess(); // TODO(yuriks): The kernel should be the one handling this as part of translation after // everything else is migrated @@ -199,7 +201,6 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr server_ses LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName().c_str(), cmd_buf)); handler_invoker(this, info->handler_callback, context); - auto thread = Kernel::GetCurrentThread(); ASSERT(thread->status == Kernel::ThreadStatus::Running || thread->status == Kernel::ThreadStatus::WaitHleEvent); // Only write the response immediately if the thread is still running. If the HLE handler put diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp index 07b47ea9b..dc7e8297e 100644 --- a/src/core/hle/service/sm/srv.cpp +++ b/src/core/hle/service/sm/srv.cpp @@ -128,8 +128,8 @@ void SRV::GetServiceHandle(Kernel::HLERequestContext& ctx) { if (wait_until_available && client_port.Code() == ERR_SERVICE_NOT_REGISTERED) { LOG_INFO(Service_SRV, "called service={} delayed", name); Kernel::SharedPtr get_service_handle_event = - ctx.SleepClientThread(Kernel::GetCurrentThread(), "GetServiceHandle", - std::chrono::nanoseconds(-1), get_handle); + ctx.SleepClientThread(system.Kernel().GetThreadManager().GetCurrentThread(), + "GetServiceHandle", std::chrono::nanoseconds(-1), get_handle); get_service_handle_delayed_map[name] = std::move(get_service_handle_event); return; } else { From 7fc61920cce7b12cfee8129a4a1ce22a97098c1d Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Tue, 23 Oct 2018 11:57:59 -0400 Subject: [PATCH 059/102] kernel/Thread: move thread wake up table and callback handle into the manager --- src/core/hle/kernel/kernel.cpp | 1 - src/core/hle/kernel/thread.cpp | 29 +++++++++++------------------ src/core/hle/kernel/thread.h | 19 ++++++++++++++----- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 0811fa699..ca68e036a 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -22,7 +22,6 @@ KernelSystem::KernelSystem(u32 system_mode) { resource_limits = std::make_unique(*this); thread_manager = std::make_unique(); - Kernel::ThreadingInit(); Kernel::TimersInit(); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 71817675d..ce035e5a6 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -13,7 +13,6 @@ #include "core/arm/arm_interface.h" #include "core/arm/skyeye_common/armstate.h" #include "core/core.h" -#include "core/core_timing.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" @@ -26,9 +25,6 @@ namespace Kernel { -/// Event type for the thread wake up event -static CoreTiming::EventType* ThreadWakeupEventType = nullptr; - bool Thread::ShouldWait(Thread* thread) const { return status != ThreadStatus::Dead; } @@ -37,8 +33,6 @@ void Thread::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); } -static std::unordered_map wakeup_callback_table; - // Lists all thread ids that aren't deleted/etc. static std::vector> thread_list; @@ -57,8 +51,8 @@ Thread* ThreadManager::GetCurrentThread() const { void Thread::Stop() { // Cancel any outstanding wakeup events for this thread - CoreTiming::UnscheduleEvent(ThreadWakeupEventType, thread_id); - wakeup_callback_table.erase(thread_id); + CoreTiming::UnscheduleEvent(thread_manager.ThreadWakeupEventType, thread_id); + thread_manager.wakeup_callback_table.erase(thread_id); // Clean up thread from ready queue // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) @@ -162,12 +156,7 @@ void ThreadManager::ExitCurrentThread() { thread_list.end()); } -/** - * Callback that will wake up the thread it was scheduled for - * @param thread_id The ID of the thread that's been awoken - * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time - */ -static void ThreadWakeupCallback(u64 thread_id, s64 cycles_late) { +void ThreadManager::ThreadWakeupCallback(u64 thread_id, s64 cycles_late) { SharedPtr thread = wakeup_callback_table.at(thread_id); if (thread == nullptr) { LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", thread_id); @@ -196,7 +185,8 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { if (nanoseconds == -1) return; - CoreTiming::ScheduleEvent(nsToCycles(nanoseconds), ThreadWakeupEventType, thread_id); + CoreTiming::ScheduleEvent(nsToCycles(nanoseconds), thread_manager.ThreadWakeupEventType, + thread_id); } void Thread::ResumeFromWait() { @@ -334,7 +324,7 @@ ResultVal> KernelSystem::CreateThread(std::string name, VAddr thread->wait_objects.clear(); thread->wait_address = 0; thread->name = std::move(name); - wakeup_callback_table[thread->thread_id] = thread.get(); + thread_manager->wakeup_callback_table[thread->thread_id] = thread.get(); thread->owner_process = &owner_process; // Find the next available TLS index, and mark it as used @@ -476,8 +466,11 @@ VAddr Thread::GetCommandBufferAddress() const { //////////////////////////////////////////////////////////////////////////////////////////////////// -void ThreadingInit() { - ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); +ThreadManager::ThreadManager() { + ThreadWakeupEventType = + CoreTiming::RegisterEvent("ThreadWakeupCallback", [this](u64 thread_id, s64 cycle_late) { + ThreadWakeupCallback(thread_id, cycle_late); + }); } void ThreadingShutdown() { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 4a9384bd8..cc229dc18 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -12,6 +12,7 @@ #include "common/common_types.h" #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" +#include "core/core_timing.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/wait_object.h" #include "core/hle/result.h" @@ -56,6 +57,8 @@ enum class ThreadWakeupReason { class ThreadManager { public: + ThreadManager(); + /** * Creates a new thread ID * @return The new thread ID @@ -105,9 +108,20 @@ private: */ Thread* PopNextReadyThread(); + /** + * Callback that will wake up the thread it was scheduled for + * @param thread_id The ID of the thread that's been awoken + * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time + */ + void ThreadWakeupCallback(u64 thread_id, s64 cycles_late); + u32 next_thread_id = 1; SharedPtr current_thread; Common::ThreadQueueList ready_queue; + std::unordered_map wakeup_callback_table; + + /// Event type for the thread wake up event + CoreTiming::EventType* ThreadWakeupEventType = nullptr; friend class Thread; friend class KernelSystem; @@ -286,11 +300,6 @@ private: SharedPtr SetupMainThread(KernelSystem& kernel, u32 entry_point, u32 priority, SharedPtr owner_process); -/** - * Initialize threading - */ -void ThreadingInit(); - /** * Shutdown threading */ From 20ae37ba4f53bf44323d9812c3187174d4a7386a Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Tue, 23 Oct 2018 12:18:35 -0400 Subject: [PATCH 060/102] kernel/Thread: move thread list into the manager --- src/citra_qt/debugger/wait_tree.cpp | 2 +- src/core/gdbstub/gdbstub.cpp | 8 +++++--- src/core/hle/kernel/kernel.cpp | 2 -- src/core/hle/kernel/svc.cpp | 2 +- src/core/hle/kernel/thread.cpp | 12 +++--------- src/core/hle/kernel/thread.h | 19 +++++++++---------- 6 files changed, 19 insertions(+), 26 deletions(-) diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/citra_qt/debugger/wait_tree.cpp index d006128e5..0758cc792 100644 --- a/src/citra_qt/debugger/wait_tree.cpp +++ b/src/citra_qt/debugger/wait_tree.cpp @@ -51,7 +51,7 @@ std::size_t WaitTreeItem::Row() const { } std::vector> WaitTreeItem::MakeThreadItemList() { - const auto& threads = Kernel::GetThreadList(); + const auto& threads = Core::System::GetInstance().Kernel().GetThreadManager().GetThreadList(); std::vector> item_list; item_list.reserve(threads.size()); for (std::size_t i = 0; i < threads.size(); ++i) { diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index f95b3c66e..1296b71b4 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -160,7 +160,7 @@ BreakpointMap breakpoints_write; } // Anonymous namespace static Kernel::Thread* FindThreadById(int id) { - const auto& threads = Kernel::GetThreadList(); + const auto& threads = Core::System::GetInstance().Kernel().GetThreadManager().GetThreadList(); for (auto& thread : threads) { if (thread->GetThreadId() == static_cast(id)) { return thread.get(); @@ -535,7 +535,8 @@ static void HandleQuery() { SendReply(target_xml); } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { std::string val = "m"; - const auto& threads = Kernel::GetThreadList(); + const auto& threads = + Core::System::GetInstance().Kernel().GetThreadManager().GetThreadList(); for (const auto& thread : threads) { val += fmt::format("{:x},", thread->GetThreadId()); } @@ -547,7 +548,8 @@ static void HandleQuery() { std::string buffer; buffer += "l"; buffer += ""; - const auto& threads = Kernel::GetThreadList(); + const auto& threads = + Core::System::GetInstance().Kernel().GetThreadManager().GetThreadList(); for (const auto& thread : threads) { buffer += fmt::format(R"*()*", thread->GetThreadId(), thread->GetThreadId()); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index ca68e036a..1c324e247 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -27,8 +27,6 @@ KernelSystem::KernelSystem(u32 system_mode) { /// Shutdown the kernel KernelSystem::~KernelSystem() { - Kernel::ThreadingShutdown(); - Kernel::TimersShutdown(); Kernel::MemoryShutdown(); } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 840a36ca7..07079fc4d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -154,7 +154,7 @@ static void ExitProcess() { current_process->status = ProcessStatus::Exited; // Stop all the process threads that are currently waiting for objects. - auto& thread_list = GetThreadList(); + auto& thread_list = kernel.GetThreadManager().GetThreadList(); for (auto& thread : thread_list) { if (thread->owner_process != current_process) continue; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ce035e5a6..236e1d7b0 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -33,9 +33,6 @@ void Thread::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); } -// Lists all thread ids that aren't deleted/etc. -static std::vector> thread_list; - u32 ThreadManager::NewThreadId() { return next_thread_id++; } @@ -311,7 +308,7 @@ ResultVal> KernelSystem::CreateThread(std::string name, VAddr SharedPtr thread(new Thread(*this)); - thread_list.push_back(thread); + thread_manager->thread_list.push_back(thread); thread_manager->ready_queue.prepare(priority); thread->thread_id = thread_manager->NewThreadId(); @@ -464,8 +461,6 @@ VAddr Thread::GetCommandBufferAddress() const { return GetTLSAddress() + CommandHeaderOffset; } -//////////////////////////////////////////////////////////////////////////////////////////////////// - ThreadManager::ThreadManager() { ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", [this](u64 thread_id, s64 cycle_late) { @@ -473,14 +468,13 @@ ThreadManager::ThreadManager() { }); } -void ThreadingShutdown() { +ThreadManager::~ThreadManager() { for (auto& t : thread_list) { t->Stop(); } - thread_list.clear(); } -const std::vector>& GetThreadList() { +const std::vector>& ThreadManager::GetThreadList() { return thread_list; } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index cc229dc18..06a7c5f4f 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -58,6 +58,7 @@ enum class ThreadWakeupReason { class ThreadManager { public: ThreadManager(); + ~ThreadManager(); /** * Creates a new thread ID @@ -95,6 +96,11 @@ public: */ void ExitCurrentThread(); + /** + * Get a const reference to the thread list for debug use + */ + const std::vector>& GetThreadList(); + private: /** * Switches the CPU's active thread context to that of the specified thread @@ -123,6 +129,9 @@ private: /// Event type for the thread wake up event CoreTiming::EventType* ThreadWakeupEventType = nullptr; + // Lists all threadsthat aren't deleted. + std::vector> thread_list; + friend class Thread; friend class KernelSystem; }; @@ -300,14 +309,4 @@ private: SharedPtr SetupMainThread(KernelSystem& kernel, u32 entry_point, u32 priority, SharedPtr owner_process); -/** - * Shutdown threading - */ -void ThreadingShutdown(); - -/** - * Get a const reference to the thread list for debug use - */ -const std::vector>& GetThreadList(); - } // namespace Kernel From e5b93741d36d3a432abc64887833544220162b66 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Tue, 23 Oct 2018 14:17:30 -0400 Subject: [PATCH 061/102] kernel/timer: add TimerManager for timer system states --- src/core/hle/kernel/kernel.cpp | 11 +++++++++-- src/core/hle/kernel/kernel.h | 5 +++++ src/core/hle/kernel/timer.cpp | 35 ++++++++++++++-------------------- src/core/hle/kernel/timer.h | 26 ++++++++++++++++++++----- 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1c324e247..c43029c37 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -22,12 +22,11 @@ KernelSystem::KernelSystem(u32 system_mode) { resource_limits = std::make_unique(*this); thread_manager = std::make_unique(); - Kernel::TimersInit(); + timer_manager = std::make_unique(); } /// Shutdown the kernel KernelSystem::~KernelSystem() { - Kernel::TimersShutdown(); Kernel::MemoryShutdown(); } @@ -59,4 +58,12 @@ const ThreadManager& KernelSystem::GetThreadManager() const { return *thread_manager; } +TimerManager& KernelSystem::GetTimerManager() { + return *timer_manager; +} + +const TimerManager& KernelSystem::GetTimerManager() const { + return *timer_manager; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 83f622670..5d27b2df7 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -29,6 +29,7 @@ class ServerSession; class ResourceLimitList; class SharedMemory; class ThreadManager; +class TimerManager; enum class ResetType { OneShot, @@ -191,6 +192,9 @@ public: ThreadManager& GetThreadManager(); const ThreadManager& GetThreadManager() const; + TimerManager& GetTimerManager(); + const TimerManager& GetTimerManager() const; + private: std::unique_ptr resource_limits; std::atomic next_object_id{0}; @@ -205,6 +209,7 @@ private: SharedPtr current_process; std::unique_ptr thread_manager; + std::unique_ptr timer_manager; }; } // namespace Kernel diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index d9d89abd0..07a98a659 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -6,7 +6,6 @@ #include #include "common/assert.h" #include "common/logging/log.h" -#include "core/core_timing.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/thread.h" @@ -14,16 +13,10 @@ namespace Kernel { -/// The event type of the generic timer callback event -static CoreTiming::EventType* timer_callback_event_type = nullptr; - -static u64 next_timer_callback_id; -static std::unordered_map timer_callback_table; - -Timer::Timer(KernelSystem& kernel) : WaitObject(kernel) {} +Timer::Timer(KernelSystem& kernel) : WaitObject(kernel), timer_manager(kernel.GetTimerManager()) {} Timer::~Timer() { Cancel(); - timer_callback_table.erase(callback_id); + timer_manager.timer_callback_table.erase(callback_id); } SharedPtr KernelSystem::CreateTimer(ResetType reset_type, std::string name) { @@ -34,8 +27,8 @@ SharedPtr KernelSystem::CreateTimer(ResetType reset_type, std::string nam timer->name = std::move(name); timer->initial_delay = 0; timer->interval_delay = 0; - timer->callback_id = ++next_timer_callback_id; - timer_callback_table[timer->callback_id] = timer.get(); + timer->callback_id = ++timer_manager->next_timer_callback_id; + timer_manager->timer_callback_table[timer->callback_id] = timer.get(); return timer; } @@ -62,12 +55,13 @@ void Timer::Set(s64 initial, s64 interval) { // Immediately invoke the callback Signal(0); } else { - CoreTiming::ScheduleEvent(nsToCycles(initial), timer_callback_event_type, callback_id); + CoreTiming::ScheduleEvent(nsToCycles(initial), timer_manager.timer_callback_event_type, + callback_id); } } void Timer::Cancel() { - CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_id); + CoreTiming::UnscheduleEvent(timer_manager.timer_callback_event_type, callback_id); } void Timer::Clear() { @@ -92,12 +86,12 @@ void Timer::Signal(s64 cycles_late) { if (interval_delay != 0) { // Reschedule the timer with the interval delay CoreTiming::ScheduleEvent(nsToCycles(interval_delay) - cycles_late, - timer_callback_event_type, callback_id); + timer_manager.timer_callback_event_type, callback_id); } } /// The timer callback event, called when a timer is fired -static void TimerCallback(u64 callback_id, s64 cycles_late) { +void TimerManager::TimerCallback(u64 callback_id, s64 cycles_late) { SharedPtr timer = timer_callback_table.at(callback_id); if (timer == nullptr) { @@ -108,12 +102,11 @@ static void TimerCallback(u64 callback_id, s64 cycles_late) { timer->Signal(cycles_late); } -void TimersInit() { - next_timer_callback_id = 0; - timer_callback_table.clear(); - timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); +TimerManager::TimerManager() { + timer_callback_event_type = + CoreTiming::RegisterEvent("TimerCallback", [this](u64 thread_id, s64 cycle_late) { + TimerCallback(thread_id, cycle_late); + }); } -void TimersShutdown() {} - } // namespace Kernel diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h index 653dacb5b..e0eccaa33 100644 --- a/src/core/hle/kernel/timer.h +++ b/src/core/hle/kernel/timer.h @@ -5,11 +5,30 @@ #pragma once #include "common/common_types.h" +#include "core/core_timing.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/wait_object.h" namespace Kernel { +class TimerManager { +public: + TimerManager(); + +private: + /// The timer callback event, called when a timer is fired + void TimerCallback(u64 callback_id, s64 cycles_late); + + /// The event type of the generic timer callback event + CoreTiming::EventType* timer_callback_event_type = nullptr; + + u64 next_timer_callback_id = 0; + std::unordered_map timer_callback_table; + + friend class Timer; + friend class KernelSystem; +}; + class Timer final : public WaitObject { public: std::string GetTypeName() const override { @@ -74,12 +93,9 @@ private: /// ID used as userdata to reference this object when inserting into the CoreTiming queue. u64 callback_id; + TimerManager& timer_manager; + friend class KernelSystem; }; -/// Initializes the required variables for timers -void TimersInit(); -/// Tears down the timer variables -void TimersShutdown(); - } // namespace Kernel From 0242d2b13a5837afeabfc4a8bf918675ad88a9c5 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 23 Oct 2018 12:21:31 -0400 Subject: [PATCH 062/102] common: Remove memory_util.cpp/.h Everything from here is completely unused and also written with the notion of supporting 32-bit architecture variants in mind. Given the Switch itself is on a 64-bit architecture, we won't be supporting 32-bit architectures. If we need specific allocation functions in the future, it's likely more worthwhile to new functions for that purpose. --- src/common/CMakeLists.txt | 2 -- src/common/memory_util.h | 21 --------------------- 2 files changed, 23 deletions(-) delete mode 100644 src/common/memory_util.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 7a1c5bc4c..21bc5bf81 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -65,8 +65,6 @@ add_library(common STATIC logging/text_formatter.cpp logging/text_formatter.h math_util.h - memory_util.cpp - memory_util.h microprofile.cpp microprofile.h microprofileui.h diff --git a/src/common/memory_util.h b/src/common/memory_util.h deleted file mode 100644 index aad071979..000000000 --- a/src/common/memory_util.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include - -void* AllocateExecutableMemory(std::size_t size, bool low = true); -void* AllocateMemoryPages(std::size_t size); -void FreeMemoryPages(void* ptr, std::size_t size); -void* AllocateAlignedMemory(std::size_t size, std::size_t alignment); -void FreeAlignedMemory(void* ptr); -void WriteProtectMemory(void* ptr, std::size_t size, bool executable = false); -void UnWriteProtectMemory(void* ptr, std::size_t size, bool allowExecute = false); -std::string MemUsage(); - -inline int GetPageSize() { - return 4096; -} From 24b931eca1c839e8db21bd9f58efcce7db13205f Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 23 Oct 2018 12:24:40 -0400 Subject: [PATCH 063/102] CMakeLists: Remove EMU_ARCH_BITS definition This was only ever used by the now-removed memory_util functions. Also, given we don't plan to support 32-bit architectures, this is just a leftover from citra at this point. --- CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8958bf9d..b9656ea50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,9 +179,6 @@ add_definitions(-DSINGLETHREADED) set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$:_DEBUG> $<$>:NDEBUG>) -math(EXPR EMU_ARCH_BITS ${CMAKE_SIZEOF_VOID_P}*8) -add_definitions(-DEMU_ARCH_BITS=${EMU_ARCH_BITS}) - # System imported libraries # ====================== From 452ccf02a6ddc7a810e90e3d8c04222a7b74f8b4 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 24 Oct 2018 08:20:32 -0400 Subject: [PATCH 064/102] game_list: Make game list column headers translatable These are user-facing strings, so they should be marked as translatable --- src/citra_qt/game_list.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp index c28878b88..eab2fba15 100644 --- a/src/citra_qt/game_list.cpp +++ b/src/citra_qt/game_list.cpp @@ -289,11 +289,11 @@ GameList::GameList(GMainWindow* parent) : QWidget{parent} { tree_view->setContextMenuPolicy(Qt::CustomContextMenu); item_model->insertColumns(0, COLUMN_COUNT); - item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, "Name"); - item_model->setHeaderData(COLUMN_COMPATIBILITY, Qt::Horizontal, "Compatibility"); - item_model->setHeaderData(COLUMN_REGION, Qt::Horizontal, "Region"); - item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, "File type"); - item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, "Size"); + item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name")); + item_model->setHeaderData(COLUMN_COMPATIBILITY, Qt::Horizontal, tr("Compatibility")); + item_model->setHeaderData(COLUMN_REGION, Qt::Horizontal, tr("Region")); + item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type")); + item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size")); item_model->setSortRole(GameListItemPath::TitleRole); connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::onUpdateThemedIcons); From f4bd5c3559771dd99aadfbe56cf88d316e603ed4 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 23 Oct 2018 21:46:33 -0400 Subject: [PATCH 065/102] yuzu/configuration/config: Reorganize member variable and function layout Makes the class layout consistent with the others. --- src/citra_qt/configuration/config.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/citra_qt/configuration/config.h b/src/citra_qt/configuration/config.h index 502b1a8c0..1108926c5 100644 --- a/src/citra_qt/configuration/config.h +++ b/src/citra_qt/configuration/config.h @@ -12,16 +12,6 @@ class QSettings; class Config { - QSettings* qt_config; - std::string qt_config_loc; - - void ReadValues(); - void SaveValues(); - QVariant ReadSetting(const QString& name); - QVariant ReadSetting(const QString& name, const QVariant& default_value); - void WriteSetting(const QString& name, const QVariant& value); - void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value); - public: Config(); ~Config(); @@ -31,4 +21,15 @@ public: static const std::array default_buttons; static const std::array, Settings::NativeAnalog::NumAnalogs> default_analogs; + +private: + void ReadValues(); + void SaveValues(); + QVariant ReadSetting(const QString& name); + QVariant ReadSetting(const QString& name, const QVariant& default_value); + void WriteSetting(const QString& name, const QVariant& value); + void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value); + + QSettings* qt_config; + std::string qt_config_loc; }; From bf6dd783247b60e7e372d76e5095e7476223b98e Mon Sep 17 00:00:00 2001 From: Lioncash Date: Tue, 23 Oct 2018 21:49:50 -0400 Subject: [PATCH 066/102] yuzu/configuration/config: Use a std::unique_ptr for qt_config instead of a raw pointer Same behavior, less code. --- src/citra_qt/configuration/config.cpp | 13 ++++++------- src/citra_qt/configuration/config.h | 3 ++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index a7c284471..3004fa936 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -16,11 +16,16 @@ Config::Config() { // TODO: Don't hardcode the path; let the frontend decide where to put the config files. qt_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "qt-config.ini"; FileUtil::CreateFullPath(qt_config_loc); - qt_config = new QSettings(QString::fromStdString(qt_config_loc), QSettings::IniFormat); + qt_config = + std::make_unique(QString::fromStdString(qt_config_loc), QSettings::IniFormat); Reload(); } +Config::~Config() { + Save(); +} + const std::array Config::default_buttons = { Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_T, Qt::Key_G, Qt::Key_F, Qt::Key_H, Qt::Key_Q, Qt::Key_W, Qt::Key_M, Qt::Key_N, Qt::Key_1, Qt::Key_2, Qt::Key_B, @@ -561,9 +566,3 @@ void Config::Reload() { void Config::Save() { SaveValues(); } - -Config::~Config() { - Save(); - - delete qt_config; -} diff --git a/src/citra_qt/configuration/config.h b/src/citra_qt/configuration/config.h index 1108926c5..fdb161c23 100644 --- a/src/citra_qt/configuration/config.h +++ b/src/citra_qt/configuration/config.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include #include "core/settings.h" @@ -30,6 +31,6 @@ private: void WriteSetting(const QString& name, const QVariant& value); void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value); - QSettings* qt_config; + std::unique_ptr qt_config; std::string qt_config_loc; }; From 027197cf1f0e9b0651a25fa962caf94ca79ade58 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 24 Oct 2018 08:10:56 -0400 Subject: [PATCH 067/102] bootmanager: Use QStringLiteral instead of std::string to represent the window title This gets rid of an unnecessary type conversion. We can just use the regular QStringLiteral to already format the string as the type setWindowTitle accepts instead of converting from a std::string instance. --- src/citra_qt/bootmanager.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 9dd2b338e..39115f31e 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -109,9 +109,8 @@ private: GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) : QWidget(parent), child(nullptr), emu_thread(emu_thread) { - std::string window_title = fmt::format("Citra {} | {}-{}", Common::g_build_name, - Common::g_scm_branch, Common::g_scm_desc); - setWindowTitle(QString::fromStdString(window_title)); + setWindowTitle(QStringLiteral("Citra %1 | %2-%3") + .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); setAttribute(Qt::WA_AcceptTouchEvents); InputCommon::Init(); From 452cfb46a92f05b3c1fd685dfda22284d22568f0 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 25 Oct 2018 16:43:42 -0400 Subject: [PATCH 068/102] configure_system: Make public slots private These are only used within this class, so we can make them private to keep their use contained. This also gets rid of the pre-Qt5 'slot' identifier, since Qt 5's connection syntax doesn't require a function to be declared a slot anymore. --- src/citra_qt/configuration/configure_system.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/citra_qt/configuration/configure_system.h b/src/citra_qt/configuration/configure_system.h index 36c7d2e94..bef7793f4 100644 --- a/src/citra_qt/configuration/configure_system.h +++ b/src/citra_qt/configuration/configure_system.h @@ -29,15 +29,14 @@ public: void setConfiguration(); void retranslateUi(); -public slots: - void updateBirthdayComboBox(int birthmonth_index); - void updateInitTime(int init_clock); - void refreshConsoleID(); - private: void ReadSystemSettings(); void ConfigureTime(); + void updateBirthdayComboBox(int birthmonth_index); + void updateInitTime(int init_clock); + void refreshConsoleID(); + std::unique_ptr ui; bool enabled; From 97cdf44ddddecc81f6a4a5897fdb4ebc9a23e4f9 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 25 Oct 2018 16:45:13 -0400 Subject: [PATCH 069/102] configure_system: Add missing override specifier on the destructor --- src/citra_qt/configuration/configure_system.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/citra_qt/configuration/configure_system.h b/src/citra_qt/configuration/configure_system.h index bef7793f4..db32b290e 100644 --- a/src/citra_qt/configuration/configure_system.h +++ b/src/citra_qt/configuration/configure_system.h @@ -23,7 +23,7 @@ class ConfigureSystem : public QWidget { public: explicit ConfigureSystem(QWidget* parent = nullptr); - ~ConfigureSystem(); + ~ConfigureSystem() override; void applyConfiguration(); void setConfiguration(); From 470cc660493b31dbde2ab0e48f859d2796360abb Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 25 Oct 2018 16:47:09 -0400 Subject: [PATCH 070/102] configure_system: Amend function casing --- src/citra_qt/configuration/configure_system.cpp | 16 ++++++++-------- src/citra_qt/configuration/configure_system.h | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/citra_qt/configuration/configure_system.cpp b/src/citra_qt/configuration/configure_system.cpp index 475699b86..4239aea76 100644 --- a/src/citra_qt/configuration/configure_system.cpp +++ b/src/citra_qt/configuration/configure_system.cpp @@ -220,12 +220,12 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui:: ui->setupUi(this); connect(ui->combo_birthmonth, static_cast(&QComboBox::currentIndexChanged), this, - &ConfigureSystem::updateBirthdayComboBox); + &ConfigureSystem::UpdateBirthdayComboBox); connect(ui->combo_init_clock, static_cast(&QComboBox::currentIndexChanged), this, - &ConfigureSystem::updateInitTime); + &ConfigureSystem::UpdateInitTime); connect(ui->button_regenerate_console_id, &QPushButton::clicked, this, - &ConfigureSystem::refreshConsoleID); + &ConfigureSystem::RefreshConsoleID); for (u8 i = 0; i < country_names.size(); i++) { if (country_names.at(i) != "") { ui->combo_country->addItem(tr(country_names.at(i)), i); @@ -270,7 +270,7 @@ void ConfigureSystem::ReadSystemSettings() { // set birthday std::tie(birthmonth, birthday) = cfg->GetBirthday(); ui->combo_birthmonth->setCurrentIndex(birthmonth - 1); - updateBirthdayComboBox( + UpdateBirthdayComboBox( birthmonth - 1); // explicitly update it because the signal from setCurrentIndex is not reliable ui->combo_birthday->setCurrentIndex(birthday - 1); @@ -358,7 +358,7 @@ void ConfigureSystem::applyConfiguration() { Settings::Apply(); } -void ConfigureSystem::updateBirthdayComboBox(int birthmonth_index) { +void ConfigureSystem::UpdateBirthdayComboBox(int birthmonth_index) { if (birthmonth_index < 0 || birthmonth_index >= 12) return; @@ -391,17 +391,17 @@ void ConfigureSystem::ConfigureTime() { this->setConfiguration(); - updateInitTime(ui->combo_init_clock->currentIndex()); + UpdateInitTime(ui->combo_init_clock->currentIndex()); } -void ConfigureSystem::updateInitTime(int init_clock) { +void ConfigureSystem::UpdateInitTime(int init_clock) { const bool is_fixed_time = static_cast(init_clock) == Settings::InitClock::FixedTime; ui->label_init_time->setVisible(is_fixed_time); ui->edit_init_time->setVisible(is_fixed_time); } -void ConfigureSystem::refreshConsoleID() { +void ConfigureSystem::RefreshConsoleID() { QMessageBox::StandardButton reply; QString warning_text = tr("This will replace your current virtual 3DS with a new one. " "Your current virtual 3DS will not be recoverable. " diff --git a/src/citra_qt/configuration/configure_system.h b/src/citra_qt/configuration/configure_system.h index db32b290e..b9936f494 100644 --- a/src/citra_qt/configuration/configure_system.h +++ b/src/citra_qt/configuration/configure_system.h @@ -33,9 +33,9 @@ private: void ReadSystemSettings(); void ConfigureTime(); - void updateBirthdayComboBox(int birthmonth_index); - void updateInitTime(int init_clock); - void refreshConsoleID(); + void UpdateBirthdayComboBox(int birthmonth_index); + void UpdateInitTime(int init_clock); + void RefreshConsoleID(); std::unique_ptr ui; bool enabled; From a74d97b15faf2c5f190fa745fbc66bb5366c8a91 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 25 Oct 2018 16:52:21 -0400 Subject: [PATCH 071/102] configure_system: Default initialize member variables These should be initialized to deterministic values so it's easier to catch improper behavior, as it'll always be reproducable, instead of performing uninitialized reads. --- src/citra_qt/configuration/configure_system.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/citra_qt/configuration/configure_system.h b/src/citra_qt/configuration/configure_system.h index b9936f494..f84457bd6 100644 --- a/src/citra_qt/configuration/configure_system.h +++ b/src/citra_qt/configuration/configure_system.h @@ -38,13 +38,14 @@ private: void RefreshConsoleID(); std::unique_ptr ui; - bool enabled; + bool enabled = false; std::shared_ptr cfg; std::u16string username; - int birthmonth, birthday; - int language_index; - int sound_index; + int birthmonth = 0; + int birthday = 0; + int language_index = 0; + int sound_index = 0; u8 country_code; u16 play_coin; }; From 446989aaaf9e9bd9d77a63b0b0bb6eb41acdd859 Mon Sep 17 00:00:00 2001 From: fearlessTobi Date: Sat, 27 Oct 2018 00:14:23 +0200 Subject: [PATCH 072/102] common: Actually remove memory_util.cpp --- src/common/memory_util.cpp | 178 ------------------------------------- 1 file changed, 178 deletions(-) delete mode 100644 src/common/memory_util.cpp diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp deleted file mode 100644 index f85ebca02..000000000 --- a/src/common/memory_util.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include "common/logging/log.h" -#include "common/memory_util.h" - -#ifdef _WIN32 -#include -// Windows.h needs to be included before psapi.h -#include -#include "common/common_funcs.h" -#include "common/string_util.h" -#else -#include -#include -#endif - -#if !defined(_WIN32) && defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT) -#include -#define PAGE_MASK (getpagesize() - 1) -#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) -#endif - -// This is purposely not a full wrapper for virtualalloc/mmap, but it -// provides exactly the primitive operations that Dolphin needs. - -void* AllocateExecutableMemory(std::size_t size, bool low) { -#if defined(_WIN32) - void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); -#else - static char* map_hint = nullptr; -#if defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT) - // This OS has no flag to enforce allocation below the 4 GB boundary, - // but if we hint that we want a low address it is very likely we will - // get one. - // An older version of this code used MAP_FIXED, but that has the side - // effect of discarding already mapped pages that happen to be in the - // requested virtual memory range (such as the emulated RAM, sometimes). - if (low && (!map_hint)) - map_hint = (char*)round_page(512 * 1024 * 1024); /* 0.5 GB rounded up to the next page */ -#endif - void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANON | MAP_PRIVATE -#if defined(ARCHITECTURE_x86_64) && defined(MAP_32BIT) - | (low ? MAP_32BIT : 0) -#endif - , - -1, 0); -#endif /* defined(_WIN32) */ - -#ifdef _WIN32 - if (ptr == nullptr) { -#else - if (ptr == MAP_FAILED) { - ptr = nullptr; -#endif - LOG_ERROR(Common_Memory, "Failed to allocate executable memory"); - } -#if !defined(_WIN32) && defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT) - else { - if (low) { - map_hint += size; - map_hint = (char*)round_page(map_hint); /* round up to the next page */ - } - } -#endif - -#if EMU_ARCH_BITS == 64 - if ((u64)ptr >= 0x80000000 && low == true) - LOG_ERROR(Common_Memory, "Executable memory ended up above 2GB!"); -#endif - - return ptr; -} - -void* AllocateMemoryPages(std::size_t size) { -#ifdef _WIN32 - void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); -#else - void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - - if (ptr == MAP_FAILED) - ptr = nullptr; -#endif - - if (ptr == nullptr) - LOG_ERROR(Common_Memory, "Failed to allocate raw memory"); - - return ptr; -} - -void* AllocateAlignedMemory(std::size_t size, std::size_t alignment) { -#ifdef _WIN32 - void* ptr = _aligned_malloc(size, alignment); -#else - void* ptr = nullptr; -#ifdef ANDROID - ptr = memalign(alignment, size); -#else - if (posix_memalign(&ptr, alignment, size) != 0) - LOG_ERROR(Common_Memory, "Failed to allocate aligned memory"); -#endif -#endif - - if (ptr == nullptr) - LOG_ERROR(Common_Memory, "Failed to allocate aligned memory"); - - return ptr; -} - -void FreeMemoryPages(void* ptr, std::size_t size) { - if (ptr) { -#ifdef _WIN32 - if (!VirtualFree(ptr, 0, MEM_RELEASE)) - LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n{}", GetLastErrorMsg()); -#else - munmap(ptr, size); -#endif - } -} - -void FreeAlignedMemory(void* ptr) { - if (ptr) { -#ifdef _WIN32 - _aligned_free(ptr); -#else - free(ptr); -#endif - } -} - -void WriteProtectMemory(void* ptr, std::size_t size, bool allowExecute) { -#ifdef _WIN32 - DWORD oldValue; - if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) - LOG_ERROR(Common_Memory, "WriteProtectMemory failed!\n{}", GetLastErrorMsg()); -#else - mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ); -#endif -} - -void UnWriteProtectMemory(void* ptr, std::size_t size, bool allowExecute) { -#ifdef _WIN32 - DWORD oldValue; - if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, - &oldValue)) - LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n{}", GetLastErrorMsg()); -#else - mprotect(ptr, size, - allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); -#endif -} - -std::string MemUsage() { -#ifdef _WIN32 -#pragma comment(lib, "psapi") - DWORD processID = GetCurrentProcessId(); - HANDLE hProcess; - PROCESS_MEMORY_COUNTERS pmc; - std::string Ret; - - // Print information about the memory usage of the process. - - hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); - if (nullptr == hProcess) - return "MemUsage Error"; - - if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) - Ret = fmt::format("{} K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7)); - - CloseHandle(hProcess); - return Ret; -#else - return ""; -#endif -} From 9f6c1b058a160edc1161ce45c160bd195e619594 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 20 Oct 2018 17:08:26 -0400 Subject: [PATCH 073/102] CMakeLists: Use PROJECT_SOURCE_DIR instead of CMAKE_SOURCE_DIR This is more localized to what we want to enforce directory-wise with the project. CMAKE_SOURCE_DIR indicates the root of the source tree, but this would cause the wrong behavior if someone included yuzu as part of a larger buildsystem (for whatever reason). Instead, we want to use the directory where the "project(yuzu)" command was declared as the root path reference. --- CMakeLists.txt | 40 +++++++++++++++++----------------- src/citra_qt/CMakeLists.txt | 10 ++++----- src/web_service/CMakeLists.txt | 2 +- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8958bf9d..2f7b7632c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,21 +24,21 @@ option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF) option(ENABLE_SCRIPTING "Enables scripting support" OFF) -if(NOT EXISTS ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit) +if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit) message(STATUS "Copying pre-commit hook") file(COPY hooks/pre-commit - DESTINATION ${CMAKE_SOURCE_DIR}/.git/hooks) + DESTINATION ${PROJECT_SOURCE_DIR}/.git/hooks) endif() # Sanity check : Check that all submodules are present # ======================================================================= function(check_submodules_present) - file(READ "${CMAKE_SOURCE_DIR}/.gitmodules" gitmodules) + file(READ "${PROJECT_SOURCE_DIR}/.gitmodules" gitmodules) string(REGEX MATCHALL "path *= *[^ \t\r\n]*" gitmodules ${gitmodules}) foreach(module ${gitmodules}) string(REGEX REPLACE "path *= *" "" module ${module}) - if (NOT EXISTS "${CMAKE_SOURCE_DIR}/${module}/.git") + if (NOT EXISTS "${PROJECT_SOURCE_DIR}/${module}/.git") message(SEND_ERROR "Git submodule ${module} not found." "Please run: git submodule update --init --recursive") endif() @@ -46,17 +46,17 @@ function(check_submodules_present) endfunction() check_submodules_present() -configure_file(${CMAKE_SOURCE_DIR}/dist/compatibility_list/compatibility_list.qrc - ${CMAKE_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc +configure_file(${PROJECT_SOURCE_DIR}/dist/compatibility_list/compatibility_list.qrc + ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc COPYONLY) -if (ENABLE_COMPATIBILITY_LIST_DOWNLOAD AND NOT EXISTS ${CMAKE_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) +if (ENABLE_COMPATIBILITY_LIST_DOWNLOAD AND NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) message(STATUS "Downloading compatibility list for citra...") file(DOWNLOAD https://api.citra-emu.org/gamedb/ - "${CMAKE_BINARY_DIR}/dist/compatibility_list/compatibility_list.json" SHOW_PROGRESS) + "${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json" SHOW_PROGRESS) endif() -if (NOT EXISTS ${CMAKE_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) - file(WRITE ${CMAKE_BINARY_DIR}/dist/compatibility_list/compatibility_list.json "") +if (NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) + file(WRITE ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json "") endif() # Detect current compilation architecture and create standard definitions @@ -107,7 +107,7 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # set up output paths for executable binaries -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) if (NOT MSVC) @@ -189,7 +189,7 @@ find_package(Boost 1.66.0 QUIET) if (NOT Boost_FOUND) message(STATUS "Boost 1.66.0 or newer not found, falling back to externals") - set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost") + set(BOOST_ROOT "${PROJECT_SOURCE_DIR}/externals/boost") set(Boost_NO_SYSTEM_PATHS OFF) find_package(Boost QUIET REQUIRED) endif() @@ -290,12 +290,12 @@ set(CLANG_FORMAT_POSTFIX "-6.0") find_program(CLANG_FORMAT NAMES clang-format${CLANG_FORMAT_POSTFIX} clang-format - PATHS ${CMAKE_BINARY_DIR}/externals) + PATHS ${PROJECT_BINARY_DIR}/externals) # if find_program doesn't find it, try to download from externals if (NOT CLANG_FORMAT) if (WIN32) message(STATUS "Clang format not found! Downloading...") - set(CLANG_FORMAT "${CMAKE_BINARY_DIR}/externals/clang-format${CLANG_FORMAT_POSTFIX}.exe") + set(CLANG_FORMAT "${PROJECT_BINARY_DIR}/externals/clang-format${CLANG_FORMAT_POSTFIX}.exe") file(DOWNLOAD https://github.com/yuzu-emu/ext-windows-bin/raw/master/clang-format${CLANG_FORMAT_POSTFIX}.exe "${CLANG_FORMAT}" SHOW_PROGRESS @@ -311,7 +311,7 @@ if (NOT CLANG_FORMAT) endif() if (CLANG_FORMAT) - set(SRCS ${CMAKE_SOURCE_DIR}/src) + set(SRCS ${PROJECT_SOURCE_DIR}/src) set(CCOMMENT "Running clang format against all the .h and .cpp files in src/") if (WIN32) add_custom_target(clang-format @@ -392,22 +392,22 @@ endif() # http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html # http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html if(ENABLE_QT AND UNIX AND NOT APPLE) - install(FILES "${CMAKE_SOURCE_DIR}/dist/citra.desktop" + install(FILES "${PROJECT_SOURCE_DIR}/dist/citra.desktop" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications") - install(FILES "${CMAKE_SOURCE_DIR}/dist/citra.svg" + install(FILES "${PROJECT_SOURCE_DIR}/dist/citra.svg" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps") - install(FILES "${CMAKE_SOURCE_DIR}/dist/citra.xml" + install(FILES "${PROJECT_SOURCE_DIR}/dist/citra.xml" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/mime/packages") endif() if(UNIX) if(ENABLE_SDL2) - install(FILES "${CMAKE_SOURCE_DIR}/dist/citra.6" + install(FILES "${PROJECT_SOURCE_DIR}/dist/citra.6" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man6") endif() if (ENABLE_QT) - install(FILES "${CMAKE_SOURCE_DIR}/dist/citra-qt.6" + install(FILES "${PROJECT_SOURCE_DIR}/dist/citra-qt.6" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man6") endif() endif() diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index f1c937780..20fefa87c 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -140,15 +140,15 @@ set(UIS ) file(GLOB COMPAT_LIST - ${CMAKE_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc - ${CMAKE_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) -file(GLOB_RECURSE ICONS ${CMAKE_SOURCE_DIR}/dist/icons/*) -file(GLOB_RECURSE THEMES ${CMAKE_SOURCE_DIR}/dist/qt_themes/*) + ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc + ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) +file(GLOB_RECURSE ICONS ${PROJECT_SOURCE_DIR}/dist/icons/*) +file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*) qt5_wrap_ui(UI_HDRS ${UIS}) if (ENABLE_QT_TRANSLATION) - set(CITRA_QT_LANGUAGES "${CMAKE_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend") + set(CITRA_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend") option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF) # Update source TS file if enabled diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt index 993ba9ac6..71bf8977d 100644 --- a/src/web_service/CMakeLists.txt +++ b/src/web_service/CMakeLists.txt @@ -12,7 +12,7 @@ add_library(web_service STATIC create_target_directory_groups(web_service) get_directory_property(OPENSSL_LIBS - DIRECTORY ${CMAKE_SOURCE_DIR}/externals/libressl + DIRECTORY ${PROJECT_SOURCE_DIR}/externals/libressl DEFINITION OPENSSL_LIBS) target_compile_definitions(web_service PRIVATE -DCPPHTTPLIB_OPENSSL_SUPPORT) target_link_libraries(web_service PRIVATE common json-headers ${OPENSSL_LIBS} httplib lurlparser) From 494d86d0833de1c499ba1cede403e4c76930fab8 Mon Sep 17 00:00:00 2001 From: fearlessTobi Date: Sat, 27 Oct 2018 00:33:31 +0200 Subject: [PATCH 074/102] graphic_breakpoints: Correct translation of strings in BreakpointModel's data() function tr() will not function properly on static/global data like this, as the object is only ever constructed once, so the strings won't translate if the language is changed without restarting the program, which is undesirable. Instead we can just turn the map into a plain old function that maps the values to their equivalent strings. This is also lessens the memory allocated, since it's only allocating memory for the strings themselves, and not an encompassing map as well. --- .../graphics/graphics_breakpoints.cpp | 41 +++++++++++-------- .../graphics/graphics_breakpoints_p.h | 2 + 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/citra_qt/debugger/graphics/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics/graphics_breakpoints.cpp index d3d32997c..282b3e8de 100644 --- a/src/citra_qt/debugger/graphics/graphics_breakpoints.cpp +++ b/src/citra_qt/debugger/graphics/graphics_breakpoints.cpp @@ -30,23 +30,8 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const { switch (role) { case Qt::DisplayRole: { if (index.column() == 0) { - static const std::map map = { - {Pica::DebugContext::Event::PicaCommandLoaded, tr("Pica command loaded")}, - {Pica::DebugContext::Event::PicaCommandProcessed, tr("Pica command processed")}, - {Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch")}, - {Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch")}, - {Pica::DebugContext::Event::VertexShaderInvocation, tr("Vertex shader invocation")}, - {Pica::DebugContext::Event::IncomingDisplayTransfer, - tr("Incoming display transfer")}, - {Pica::DebugContext::Event::GSPCommandProcessed, tr("GSP command processed")}, - {Pica::DebugContext::Event::BufferSwapped, tr("Buffers swapped")}, - }; - - DEBUG_ASSERT(map.size() == - static_cast(Pica::DebugContext::Event::NumEvents)); - return (map.find(event) != map.end()) ? map.at(event) : QString(); + return DebugContextEventToString(event); } - break; } @@ -128,6 +113,30 @@ void BreakPointModel::OnResumed() { active_breakpoint = context->active_breakpoint; } +QString BreakPointModel::DebugContextEventToString(Pica::DebugContext::Event event) { + switch (event) { + case Pica::DebugContext::Event::PicaCommandLoaded: + return tr("Pica command loaded"); + case Pica::DebugContext::Event::PicaCommandProcessed: + return tr("Pica command processed"); + case Pica::DebugContext::Event::IncomingPrimitiveBatch: + return tr("Incoming primitive batch"); + case Pica::DebugContext::Event::FinishedPrimitiveBatch: + return tr("Finished primitive batch"); + case Pica::DebugContext::Event::VertexShaderInvocation: + return tr("Vertex shader invocation"); + case Pica::DebugContext::Event::IncomingDisplayTransfer: + return tr("Incoming display transfer"); + case Pica::DebugContext::Event::GSPCommandProcessed: + return tr("GSP command processed"); + case Pica::DebugContext::Event::BufferSwapped: + return tr("Buffers swapped"); + case Pica::DebugContext::Event::NumEvents: + break; + } + return tr("Unknown debug context event"); +} + GraphicsBreakPointsWidget::GraphicsBreakPointsWidget( std::shared_ptr debug_context, QWidget* parent) : QDockWidget(tr("Pica Breakpoints"), parent), Pica::DebugContext::BreakPointObserver( diff --git a/src/citra_qt/debugger/graphics/graphics_breakpoints_p.h b/src/citra_qt/debugger/graphics/graphics_breakpoints_p.h index e4711dadc..3a53c06a0 100644 --- a/src/citra_qt/debugger/graphics/graphics_breakpoints_p.h +++ b/src/citra_qt/debugger/graphics/graphics_breakpoints_p.h @@ -29,6 +29,8 @@ public: void OnResumed(); private: + static QString DebugContextEventToString(Pica::DebugContext::Event event); + std::weak_ptr context_weak; bool at_breakpoint; Pica::DebugContext::Event active_breakpoint; From d28233961bb83b155e2ddf25f3a2f3ae3ff6d278 Mon Sep 17 00:00:00 2001 From: fearlessTobi Date: Fri, 26 Oct 2018 17:01:00 +0200 Subject: [PATCH 075/102] Put WebResult into a seperate file --- src/common/CMakeLists.txt | 1 + src/common/announce_multiplayer_room.h | 18 +----------------- src/common/web_result.h | 25 +++++++++++++++++++++++++ src/web_service/web_backend.cpp | 3 ++- 4 files changed, 29 insertions(+), 18 deletions(-) create mode 100644 src/common/web_result.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 7a1c5bc4c..5eb5da8fb 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -90,6 +90,7 @@ add_library(common STATIC timer.cpp timer.h vector_math.h + web_result.h ) if(ARCHITECTURE_x86_64) diff --git a/src/common/announce_multiplayer_room.h b/src/common/announce_multiplayer_room.h index 811f78d8c..5f9fc8ec2 100644 --- a/src/common/announce_multiplayer_room.h +++ b/src/common/announce_multiplayer_room.h @@ -9,23 +9,7 @@ #include #include #include "common/common_types.h" - -namespace Common { -struct WebResult { - enum class Code : u32 { - Success, - InvalidURL, - CredentialsMissing, - LibError, - HttpError, - WrongContent, - NoWebservice, - }; - Code result_code; - std::string result_string; - std::string returned_data; -}; -} // namespace Common +#include "common/web_result.h" namespace AnnounceMultiplayerRoom { diff --git a/src/common/web_result.h b/src/common/web_result.h new file mode 100644 index 000000000..286c2b0f4 --- /dev/null +++ b/src/common/web_result.h @@ -0,0 +1,25 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "common/common_types.h" + +namespace Common { +struct WebResult { + enum class Code : u32 { + Success, + InvalidURL, + CredentialsMissing, + LibError, + HttpError, + WrongContent, + NoWebservice, + }; + Code result_code; + std::string result_string; + std::string returned_data; +}; +} // namespace Common diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp index 6329c6a0c..84d6105d7 100644 --- a/src/web_service/web_backend.cpp +++ b/src/web_service/web_backend.cpp @@ -2,14 +2,15 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include #include #include #include -#include "common/announce_multiplayer_room.h" #include "common/common_types.h" #include "common/logging/log.h" +#include "common/web_result.h" #include "web_service/web_backend.h" namespace WebService { From 5b7d21c3cd5dc3e033fb076340f81464d4a8ee1a Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sat, 27 Oct 2018 00:46:03 -0400 Subject: [PATCH 076/102] FileSys/DelayGenerator: add missing #include and virtual dtor (#4363) * FileSys/DelayGenerator: add missing #include and virtual dtor Added the needed include so that it won't cause error if another file includes this without including the depended files Deleting a virtual class via base type without virtual dtor is UB, which happens inFileBackend. * FileSys/DelayGenerator: move function definition into cpp file/n/nTo avoid generating vtable in all units that includes the header file * filesys/delay_generator: rearrange #include --- src/core/CMakeLists.txt | 1 + src/core/file_sys/delay_generator.cpp | 22 ++++++++++++++++++++++ src/core/file_sys/delay_generator.h | 14 +++++--------- 3 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 src/core/file_sys/delay_generator.cpp diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c30ddcbdd..18833eb0a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -58,6 +58,7 @@ add_library(core STATIC file_sys/disk_archive.h file_sys/errors.h file_sys/file_backend.h + file_sys/delay_generator.cpp file_sys/delay_generator.h file_sys/ivfc_archive.cpp file_sys/ivfc_archive.h diff --git a/src/core/file_sys/delay_generator.cpp b/src/core/file_sys/delay_generator.cpp new file mode 100644 index 000000000..654550061 --- /dev/null +++ b/src/core/file_sys/delay_generator.cpp @@ -0,0 +1,22 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "core/file_sys/delay_generator.h" + +namespace FileSys { + +DelayGenerator::~DelayGenerator() = default; + +u64 DefaultDelayGenerator::GetReadDelayNs(std::size_t length) { + // This is the delay measured for a romfs read. + // For now we will take that as a default + static constexpr u64 slope(94); + static constexpr u64 offset(582778); + static constexpr u64 minimum(663124); + u64 IPCDelayNanoseconds = std::max(static_cast(length) * slope + offset, minimum); + return IPCDelayNanoseconds; +} + +} // namespace FileSys diff --git a/src/core/file_sys/delay_generator.h b/src/core/file_sys/delay_generator.h index c43a5c026..06ef97281 100644 --- a/src/core/file_sys/delay_generator.h +++ b/src/core/file_sys/delay_generator.h @@ -4,10 +4,14 @@ #pragma once +#include +#include "common/common_types.h" + namespace FileSys { class DelayGenerator { public: + virtual ~DelayGenerator(); virtual u64 GetReadDelayNs(std::size_t length) = 0; // TODO (B3N30): Add getter for all other file/directory io operations @@ -15,15 +19,7 @@ public: class DefaultDelayGenerator : public DelayGenerator { public: - u64 GetReadDelayNs(std::size_t length) override { - // This is the delay measured for a romfs read. - // For now we will take that as a default - static constexpr u64 slope(94); - static constexpr u64 offset(582778); - static constexpr u64 minimum(663124); - u64 IPCDelayNanoseconds = std::max(static_cast(length) * slope + offset, minimum); - return IPCDelayNanoseconds; - } + u64 GetReadDelayNs(std::size_t length) override; }; } // namespace FileSys From b7117bf0500d803d7245f5ce22deebdcf28469da Mon Sep 17 00:00:00 2001 From: fearlessTobi Date: Fri, 26 Oct 2018 16:21:45 +0200 Subject: [PATCH 077/102] compatdb: Use a seperate endpoint for testcase submission --- src/citra_qt/compatdb.cpp | 27 +++++++++++++++++++++++++-- src/citra_qt/compatdb.h | 4 ++++ src/common/telemetry.h | 4 ++++ src/core/telemetry_session.cpp | 9 +++++++++ src/core/telemetry_session.h | 6 ++++++ src/web_service/telemetry_json.cpp | 21 ++++++++++++++++----- src/web_service/telemetry_json.h | 1 + 7 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/citra_qt/compatdb.cpp b/src/citra_qt/compatdb.cpp index d6712338c..17dd14310 100644 --- a/src/citra_qt/compatdb.cpp +++ b/src/citra_qt/compatdb.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "citra_qt/compatdb.h" #include "common/telemetry.h" #include "core/core.h" @@ -21,6 +22,8 @@ CompatDB::CompatDB(QWidget* parent) connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext); connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext); connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit); + connect(&testcase_watcher, &QFutureWatcher::finished, this, + &CompatDB::OnTestcaseSubmitted); } CompatDB::~CompatDB() = default; @@ -46,18 +49,38 @@ void CompatDB::Submit() { } break; case CompatDBPage::Final: + back(); LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId()); Core::Telemetry().AddField(Telemetry::FieldType::UserFeedback, "Compatibility", compatibility->checkedId()); - // older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a - // workaround + + button(NextButton)->setEnabled(false); + button(NextButton)->setText(tr("Submitting")); button(QWizard::CancelButton)->setVisible(false); + + testcase_watcher.setFuture(QtConcurrent::run( + [this]() { return Core::System::GetInstance().TelemetrySession().SubmitTestcase(); })); break; default: LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); } } +void CompatDB::OnTestcaseSubmitted() { + if (!testcase_watcher.result()) { + QMessageBox::critical(this, tr("Communication error"), + tr("An error occured while sending the Testcase")); + button(NextButton)->setEnabled(true); + button(NextButton)->setText(tr("Next")); + button(QWizard::CancelButton)->setVisible(true); + } else { + next(); + // older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a + // workaround + button(QWizard::CancelButton)->setVisible(false); + } +} + void CompatDB::EnableNext() { button(NextButton)->setEnabled(true); } diff --git a/src/citra_qt/compatdb.h b/src/citra_qt/compatdb.h index ca0dd11d6..5381f67f7 100644 --- a/src/citra_qt/compatdb.h +++ b/src/citra_qt/compatdb.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include namespace Ui { @@ -19,8 +20,11 @@ public: ~CompatDB(); private: + QFutureWatcher testcase_watcher; + std::unique_ptr ui; void Submit(); + void OnTestcaseSubmitted(); void EnableNext(); }; diff --git a/src/common/telemetry.h b/src/common/telemetry.h index 9439edde4..56dc54007 100644 --- a/src/common/telemetry.h +++ b/src/common/telemetry.h @@ -153,6 +153,7 @@ struct VisitorInterface : NonCopyable { /// Completion method, called once all fields have been visited virtual void Complete() = 0; + virtual bool SubmitTestcase() = 0; }; /** @@ -178,6 +179,9 @@ struct NullVisitor : public VisitorInterface { void Visit(const Field& /*field*/) override {} void Complete() override {} + bool SubmitTestcase() override { + return false; + } }; } // namespace Telemetry diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 9535ffee4..93e17b268 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -203,4 +203,13 @@ TelemetrySession::~TelemetrySession() { backend = nullptr; } +bool TelemetrySession::SubmitTestcase() { +#ifdef ENABLE_WEB_SERVICE + field_collection.Accept(*backend); + return backend->SubmitTestcase(); +#else + return false; +#endif +} + } // namespace Core diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h index e37b6599e..12bb04c43 100644 --- a/src/core/telemetry_session.h +++ b/src/core/telemetry_session.h @@ -31,6 +31,12 @@ public: field_collection.AddField(type, name, std::move(value)); } + /** + * Submits a Testcase. + * @returns A bool indicating whether the submission succeeded + */ + bool SubmitTestcase(); + private: Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session std::unique_ptr backend; ///< Backend interface that logs fields diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp index 0a8f2bd9e..9156ce802 100644 --- a/src/web_service/telemetry_json.cpp +++ b/src/web_service/telemetry_json.cpp @@ -102,16 +102,27 @@ void TelemetryJson::Complete() { impl->SerializeSection(Telemetry::FieldType::App, "App"); impl->SerializeSection(Telemetry::FieldType::Session, "Session"); impl->SerializeSection(Telemetry::FieldType::Performance, "Performance"); - impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback"); impl->SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig"); impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem"); auto content = impl->TopSection().dump(); // Send the telemetry async but don't handle the errors since they were written to the log - Common::DetachedTasks::AddTask( - [host{impl->host}, username{impl->username}, token{impl->token}, content]() { - Client{host, username, token}.PostJson("/telemetry", content, true); - }); + Common::DetachedTasks::AddTask([host{impl->host}, content]() { + Client{host, "", ""}.PostJson("/telemetry", content, true); + }); +} + +bool TelemetryJson::SubmitTestcase() { + impl->SerializeSection(Telemetry::FieldType::App, "App"); + impl->SerializeSection(Telemetry::FieldType::Session, "Session"); + impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback"); + impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem"); + + auto content = impl->TopSection().dump(); + Client client(impl->host, impl->username, impl->token); + auto value = client.PostJson("/gamedb/testcase", content, false); + + return value.result_code == Common::WebResult::Code::Success; } } // namespace WebService diff --git a/src/web_service/telemetry_json.h b/src/web_service/telemetry_json.h index 4b4bef3bc..5b6d3cfb5 100644 --- a/src/web_service/telemetry_json.h +++ b/src/web_service/telemetry_json.h @@ -36,6 +36,7 @@ public: void Visit(const Telemetry::Field& field) override; void Complete() override; + bool SubmitTestcase() override; private: struct Impl; From 236a7dba7e1b06389850473ba75e9ff756d77145 Mon Sep 17 00:00:00 2001 From: fearlessTobi Date: Fri, 26 Oct 2018 16:36:05 +0200 Subject: [PATCH 078/102] Move "Report compatibility" button to Emulation tab --- src/citra_qt/main.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index b5810715f..77ac7e3ac 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui @@ -82,6 +82,8 @@ + + @@ -148,8 +150,6 @@ - - From 96ee82c46411eba35ce2293238ef50e9f7b9dc31 Mon Sep 17 00:00:00 2001 From: fearlessTobi Date: Sat, 27 Oct 2018 22:43:29 +0200 Subject: [PATCH 079/102] configure_general: Add an option to reset defaults --- src/citra_qt/configuration/configure_general.cpp | 16 ++++++++++++++++ src/citra_qt/configuration/configure_general.h | 1 + src/citra_qt/configuration/configure_general.ui | 7 +++++++ 3 files changed, 24 insertions(+) diff --git a/src/citra_qt/configuration/configure_general.cpp b/src/citra_qt/configuration/configure_general.cpp index 3153ff8c8..cd47b135e 100644 --- a/src/citra_qt/configuration/configure_general.cpp +++ b/src/citra_qt/configuration/configure_general.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "citra_qt/configuration/configure_general.h" #include "citra_qt/ui_settings.h" #include "core/core.h" @@ -15,6 +16,8 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent) this->setConfiguration(); ui->updateBox->setVisible(UISettings::values.updater_found); + connect(ui->button_reset_defaults, &QPushButton::clicked, this, + &ConfigureGeneral::ResetDefaults); } ConfigureGeneral::~ConfigureGeneral() = default; @@ -33,6 +36,19 @@ void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) { ui->hotkeysDialog->Populate(registry); } +void ConfigureGeneral::ResetDefaults() { + QMessageBox::StandardButton answer = QMessageBox::question( + this, tr("Citra"), + tr("Are you sure you want to reset your settings and close Citra?"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + + if (answer == QMessageBox::No) + return; + + FileUtil::Delete(FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "qt-config.ini"); + std::exit(0); +} + void ConfigureGeneral::applyConfiguration() { UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); diff --git a/src/citra_qt/configuration/configure_general.h b/src/citra_qt/configuration/configure_general.h index 9e67589bf..ff99c9510 100644 --- a/src/citra_qt/configuration/configure_general.h +++ b/src/citra_qt/configuration/configure_general.h @@ -21,6 +21,7 @@ public: ~ConfigureGeneral(); void PopulateHotkeyList(const HotkeyRegistry& registry); + void ResetDefaults(); void applyConfiguration(); void retranslateUi(); diff --git a/src/citra_qt/configuration/configure_general.ui b/src/citra_qt/configuration/configure_general.ui index 103ac54d3..5979dd95b 100644 --- a/src/citra_qt/configuration/configure_general.ui +++ b/src/citra_qt/configuration/configure_general.ui @@ -147,6 +147,13 @@ + + + + Reset All Settings + + + From f63098ccdfde762acc255d2c34577ffcea397677 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sun, 28 Oct 2018 10:34:08 -0400 Subject: [PATCH 080/102] Kernel/CodeSet: change struct to class Fix a warning where class definition and forward declaration mismatch. CodeSet is a kernel object and have ctor/dtor/private members like others, so in convention it should be a class --- src/core/hle/kernel/process.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index fa04d8c42..d1f529943 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -50,7 +50,8 @@ enum class ProcessStatus { Created, Running, Exited }; class ResourceLimit; struct MemoryRegionInfo; -struct CodeSet final : public Object { +class CodeSet final : public Object { +public: struct Segment { std::size_t offset = 0; VAddr addr = 0; From c97146226a57419791d5a234d8c63f87ef79b57a Mon Sep 17 00:00:00 2001 From: NarcolepticK Date: Mon, 29 Oct 2018 18:35:34 -0400 Subject: [PATCH 081/102] LLE Mapped Buffer: Addressed comments. --- src/core/hle/kernel/ipc.cpp | 107 ++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 40 deletions(-) diff --git a/src/core/hle/kernel/ipc.cpp b/src/core/hle/kernel/ipc.cpp index 9875fc68a..4fe2c9c1d 100644 --- a/src/core/hle/kernel/ipc.cpp +++ b/src/core/hle/kernel/ipc.cpp @@ -14,6 +14,68 @@ namespace Kernel { +void ScanForAndUnmapBuffer(std::array& dst_cmd_buf, + const std::size_t dst_command_size, std::size_t& target_index, + SharedPtr src_process, SharedPtr dst_process, + const VAddr source_address, const VAddr page_start, const u32 num_pages, + const u32 size, const IPC::MappedBufferPermissions permissions) { + while (target_index < dst_command_size) { + u32 desc = dst_cmd_buf[target_index++]; + + if (IPC::GetDescriptorType(desc) == IPC::DescriptorType::CopyHandle || + IPC::GetDescriptorType(desc) == IPC::DescriptorType::MoveHandle) { + u32 num_handles = IPC::HandleNumberFromDesc(desc); + for (u32 j = 0; j < num_handles; ++j) { + target_index += 1; + } + continue; + } + + if (IPC::GetDescriptorType(desc) == IPC::DescriptorType::CallingPid || + IPC::GetDescriptorType(desc) == IPC::DescriptorType::StaticBuffer) { + target_index += 1; + continue; + } + + if (IPC::GetDescriptorType(desc) == IPC::DescriptorType::MappedBuffer) { + VAddr dest_address = dst_cmd_buf[target_index]; + IPC::MappedBufferDescInfo dest_descInfo{desc}; + u32 dest_size = static_cast(dest_descInfo.size); + IPC::MappedBufferPermissions dest_permissions = dest_descInfo.perms; + + if (dest_size == 0) { + target_index += 1; + continue; + } + + ASSERT(permissions == dest_permissions && size == dest_size); + // Readonly buffers do not need to be copied over to the target + // process again because they were (presumably) not modified. This + // behavior is consistent with the real kernel. + if (permissions != IPC::MappedBufferPermissions::R) { + // Copy the modified buffer back into the target process + Memory::CopyBlock(*src_process, *dst_process, source_address, dest_address, size); + } + + VAddr prev_reserve = page_start - Memory::PAGE_SIZE; + VAddr next_reserve = page_start + num_pages * Memory::PAGE_SIZE; + + auto& prev_vma = src_process->vm_manager.FindVMA(prev_reserve)->second; + auto& next_vma = src_process->vm_manager.FindVMA(next_reserve)->second; + ASSERT(prev_vma.meminfo_state == MemoryState::Reserved && + next_vma.meminfo_state == MemoryState::Reserved); + + // Unmap the buffer and guard pages from the source process + ResultCode result = src_process->vm_manager.UnmapRange( + page_start - Memory::PAGE_SIZE, (num_pages + 2) * Memory::PAGE_SIZE); + ASSERT(result == RESULT_SUCCESS); + + target_index += 1; + break; + } + } +} + ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtr dst_thread, VAddr src_address, VAddr dst_address, bool reply) { @@ -148,46 +210,11 @@ ResultCode TranslateCommandBuffer(SharedPtr src_thread, SharedPtr= 1); if (reply) { - // Scan the target's command buffer for the matching mapped buffer - while (target_index < dst_command_size) { - u32 desc = dst_cmd_buf[target_index++]; - - if (IPC::GetDescriptorType(desc) == IPC::DescriptorType::MappedBuffer) { - IPC::MappedBufferDescInfo dest_descInfo{desc}; - VAddr dest_address = dst_cmd_buf[target_index]; - - u32 dest_size = static_cast(dest_descInfo.size); - IPC::MappedBufferPermissions dest_permissions = dest_descInfo.perms; - - ASSERT(permissions == dest_permissions && size == dest_size); - // Readonly buffers do not need to be copied over to the target - // process again because they were (presumably) not modified. This - // behavior is consistent with the real kernel. - if (permissions != IPC::MappedBufferPermissions::R) { - // Copy the modified buffer back into the target process - Memory::CopyBlock(*src_process, *dst_process, source_address, - dest_address, size); - } - - VAddr prev_reserve = page_start - Memory::PAGE_SIZE; - VAddr next_reserve = page_start + num_pages * Memory::PAGE_SIZE; - - auto& prev_vma = src_process->vm_manager.FindVMA(prev_reserve)->second; - auto& next_vma = src_process->vm_manager.FindVMA(next_reserve)->second; - ASSERT(prev_vma.meminfo_state == MemoryState::Reserved && - next_vma.meminfo_state == MemoryState::Reserved); - - // Unmap the buffer and guard pages from the source process - ResultCode result = src_process->vm_manager.UnmapRange( - page_start - Memory::PAGE_SIZE, (num_pages + 2) * Memory::PAGE_SIZE); - ASSERT(result == RESULT_SUCCESS); - - target_index += 1; - break; - } - - target_index += 1; - } + // Scan the target's command buffer for the matching mapped buffer. + // The real kernel panics if you try to reply with an unsolicited MappedBuffer. + ScanForAndUnmapBuffer(dst_cmd_buf, dst_command_size, target_index, src_process, + dst_process, source_address, page_start, num_pages, size, + permissions); i += 1; break; From 2183d0d6be0caa2a82ed2fed24f97b82a8c63ad0 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Tue, 30 Oct 2018 00:35:37 -0400 Subject: [PATCH 082/102] core: use internal kernel pointer directly --- src/core/core.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 695afef4f..be9796aeb 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -59,7 +59,7 @@ System::ResultStatus System::RunLoop(bool tight_loop) { // If we don't have a currently active thread then don't execute instructions, // instead advance to the next event and try to yield to the next thread - if (Kernel().GetThreadManager().GetCurrentThread() == nullptr) { + if (kernel->GetThreadManager().GetCurrentThread() == nullptr) { LOG_TRACE(Core_ARM11, "Idling"); CoreTiming::Idle(); CoreTiming::Advance(); From 95790218f2a965cbdbc128795c78194a41f7ad5e Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 25 Oct 2018 10:27:42 -0400 Subject: [PATCH 083/102] HLE: move config_mem to kernel ConfigMem is initialized in kernel and only used by kernel. It is also likely how it works on real 3DS --- src/core/CMakeLists.txt | 4 ++-- src/core/hle/{ => kernel}/config_mem.cpp | 2 +- src/core/hle/{ => kernel}/config_mem.h | 0 src/core/hle/kernel/kernel.cpp | 2 +- src/core/hle/kernel/memory.cpp | 2 +- src/core/hle/kernel/wait_object.cpp | 1 - 6 files changed, 5 insertions(+), 6 deletions(-) rename src/core/hle/{ => kernel}/config_mem.cpp (95%) rename src/core/hle/{ => kernel}/config_mem.h (100%) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 18833eb0a..236655688 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -103,8 +103,6 @@ add_library(core STATIC hle/applets/mint.h hle/applets/swkbd.cpp hle/applets/swkbd.h - hle/config_mem.cpp - hle/config_mem.h hle/function_wrappers.h hle/ipc.h hle/ipc_helpers.h @@ -114,6 +112,8 @@ add_library(core STATIC hle/kernel/client_port.h hle/kernel/client_session.cpp hle/kernel/client_session.h + hle/kernel/config_mem.cpp + hle/kernel/config_mem.h hle/kernel/errors.h hle/kernel/event.cpp hle/kernel/event.h diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/kernel/config_mem.cpp similarity index 95% rename from src/core/hle/config_mem.cpp rename to src/core/hle/kernel/config_mem.cpp index 038af7909..91c044192 100644 --- a/src/core/hle/config_mem.cpp +++ b/src/core/hle/kernel/config_mem.cpp @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #include -#include "core/hle/config_mem.h" +#include "core/hle/kernel/config_mem.h" //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/config_mem.h b/src/core/hle/kernel/config_mem.h similarity index 100% rename from src/core/hle/config_mem.h rename to src/core/hle/kernel/config_mem.h diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index c43029c37..74b1f596a 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -2,7 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "core/hle/config_mem.h" +#include "core/hle/kernel/config_mem.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/memory.h" diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp index 3615e0a55..ff4c06cab 100644 --- a/src/core/hle/kernel/memory.cpp +++ b/src/core/hle/kernel/memory.cpp @@ -12,7 +12,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" -#include "core/hle/config_mem.h" +#include "core/hle/kernel/config_mem.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/vm_manager.h" #include "core/hle/result.h" diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index 12699f85e..17902d76c 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -5,7 +5,6 @@ #include #include "common/assert.h" #include "common/logging/log.h" -#include "core/hle/config_mem.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/memory.h" From 773ec47629ccb46681d789667ddca8aea1f2537f Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 25 Oct 2018 10:51:00 -0400 Subject: [PATCH 084/102] Kernel: make config_mem and MapSharedPages members of KernelSystem --- src/core/hle/kernel/config_mem.cpp | 8 +++++--- src/core/hle/kernel/config_mem.h | 9 +++++++-- src/core/hle/kernel/kernel.cpp | 4 +--- src/core/hle/kernel/kernel.h | 11 +++++++++++ src/core/hle/kernel/memory.cpp | 18 ++++++++++-------- src/core/hle/kernel/memory.h | 2 -- src/core/hle/kernel/process.cpp | 2 +- src/tests/core/memory/memory.cpp | 4 ++-- 8 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/core/hle/kernel/config_mem.cpp b/src/core/hle/kernel/config_mem.cpp index 91c044192..58bef4110 100644 --- a/src/core/hle/kernel/config_mem.cpp +++ b/src/core/hle/kernel/config_mem.cpp @@ -9,9 +9,7 @@ namespace ConfigMem { -ConfigMemDef config_mem; - -void Init() { +Handler::Handler() { std::memset(&config_mem, 0, sizeof(config_mem)); // Values extracted from firmware 11.2.0-35E @@ -28,4 +26,8 @@ void Init() { config_mem.firm_ctr_sdk_ver = 0x0000F297; } +ConfigMemDef& Handler::GetConfigMem() { + return config_mem; +} + } // namespace ConfigMem diff --git a/src/core/hle/kernel/config_mem.h b/src/core/hle/kernel/config_mem.h index 1840d1760..ecb97c6bd 100644 --- a/src/core/hle/kernel/config_mem.h +++ b/src/core/hle/kernel/config_mem.h @@ -49,8 +49,13 @@ struct ConfigMemDef { static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, "Config Memory structure size is wrong"); -extern ConfigMemDef config_mem; +class Handler { +public: + Handler(); + ConfigMemDef& GetConfigMem(); -void Init(); +private: + ConfigMemDef config_mem; +}; } // namespace ConfigMem diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 74b1f596a..e491dfa50 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -16,9 +16,7 @@ namespace Kernel { /// Initialize the kernel KernelSystem::KernelSystem(u32 system_mode) { - ConfigMem::Init(); - - Kernel::MemoryInit(system_mode); + MemoryInit(system_mode); resource_limits = std::make_unique(*this); thread_manager = std::make_unique(); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 5d27b2df7..e001fa8b7 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -12,6 +12,10 @@ #include "common/common_types.h" #include "core/hle/result.h" +namespace ConfigMem { +class Handler; +} + namespace Kernel { class AddressArbiter; @@ -30,6 +34,7 @@ class ResourceLimitList; class SharedMemory; class ThreadManager; class TimerManager; +class VMManager; enum class ResetType { OneShot, @@ -195,7 +200,11 @@ public: TimerManager& GetTimerManager(); const TimerManager& GetTimerManager() const; + void MapSharedPages(VMManager& address_space); + private: + void MemoryInit(u32 mem_type); + std::unique_ptr resource_limits; std::atomic next_object_id{0}; @@ -210,6 +219,8 @@ private: std::unique_ptr thread_manager; std::unique_ptr timer_manager; + + std::unique_ptr config_mem_handler; }; } // namespace Kernel diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp index ff4c06cab..e8c326569 100644 --- a/src/core/hle/kernel/memory.cpp +++ b/src/core/hle/kernel/memory.cpp @@ -41,7 +41,7 @@ static const u32 memory_region_sizes[8][3] = { {0x0B200000, 0x02E00000, 0x02000000}, // 7 }; -void MemoryInit(u32 mem_type) { +void KernelSystem::MemoryInit(u32 mem_type) { // TODO(yuriks): On the n3DS, all o3DS configurations (<=5) are forced to 6 instead. ASSERT_MSG(mem_type <= 5, "New 3DS memory configuration aren't supported yet!"); ASSERT(mem_type != 1); @@ -64,7 +64,8 @@ void MemoryInit(u32 mem_type) { // We must've allocated the entire FCRAM by the end ASSERT(base == Memory::FCRAM_SIZE); - using ConfigMem::config_mem; + config_mem_handler = std::make_unique(); + auto& config_mem = config_mem_handler->GetConfigMem(); config_mem.app_mem_type = mem_type; // app_mem_malloc does not always match the configured size for memory_region[0]: in case the // n3DS type override is in effect it reports the size the game expects, not the real one. @@ -152,12 +153,13 @@ void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mappin mapping.read_only ? VMAPermission::Read : VMAPermission::ReadWrite); } -void MapSharedPages(VMManager& address_space) { - auto cfg_mem_vma = address_space - .MapBackingMemory(Memory::CONFIG_MEMORY_VADDR, - reinterpret_cast(&ConfigMem::config_mem), - Memory::CONFIG_MEMORY_SIZE, MemoryState::Shared) - .Unwrap(); +void KernelSystem::MapSharedPages(VMManager& address_space) { + auto cfg_mem_vma = + address_space + .MapBackingMemory(Memory::CONFIG_MEMORY_VADDR, + reinterpret_cast(&config_mem_handler->GetConfigMem()), + Memory::CONFIG_MEMORY_SIZE, MemoryState::Shared) + .Unwrap(); address_space.Reprotect(cfg_mem_vma, VMAPermission::Read); auto shared_page_vma = diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h index da6bb3563..a39a53977 100644 --- a/src/core/hle/kernel/memory.h +++ b/src/core/hle/kernel/memory.h @@ -20,12 +20,10 @@ struct MemoryRegionInfo { std::shared_ptr> linear_heap_memory; }; -void MemoryInit(u32 mem_type); void MemoryShutdown(); MemoryRegionInfo* GetMemoryRegion(MemoryRegion region); void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping); -void MapSharedPages(VMManager& address_space); extern MemoryRegionInfo memory_regions[3]; } // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 21204eeb8..9b45c77f1 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -143,7 +143,7 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { memory_region->used += stack_size; // Map special address mappings - MapSharedPages(vm_manager); + kernel.MapSharedPages(vm_manager); for (const auto& mapping : address_mappings) { HandleSpecialMapping(vm_manager, mapping); } diff --git a/src/tests/core/memory/memory.cpp b/src/tests/core/memory/memory.cpp index d5f96e1f2..de1848007 100644 --- a/src/tests/core/memory/memory.cpp +++ b/src/tests/core/memory/memory.cpp @@ -25,7 +25,7 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { SECTION("CONFIG_MEMORY_VADDR and SHARED_PAGE_VADDR should be valid after mapping them") { auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); - Kernel::MapSharedPages(process->vm_manager); + kernel.MapSharedPages(process->vm_manager); CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true); CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true); } @@ -47,7 +47,7 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { SECTION("Unmapping a VAddr should make it invalid") { auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); - Kernel::MapSharedPages(process->vm_manager); + kernel.MapSharedPages(process->vm_manager); process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE); CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false); } From 263290d48caa86f1149e6f2f9a570a36188362c2 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 25 Oct 2018 11:23:52 -0400 Subject: [PATCH 085/102] HLE: move SharedPage into Kernel similar to config_mem, kernel is responsible for setting up this --- src/core/CMakeLists.txt | 4 ++-- src/core/core.cpp | 1 - src/core/core.h | 8 -------- src/core/hle/kernel/kernel.cpp | 10 +++++++++- src/core/hle/kernel/kernel.h | 8 ++++++++ src/core/hle/kernel/memory.cpp | 11 ++++++----- src/core/hle/{ => kernel}/shared_page.cpp | 2 +- src/core/hle/{ => kernel}/shared_page.h | 0 src/core/hle/kernel/wait_object.cpp | 1 - src/core/hle/service/gsp/gsp_gpu.cpp | 3 ++- src/core/hle/service/nwm/nwm_uds.cpp | 5 +++-- src/tests/core/memory/memory.cpp | 2 +- 12 files changed, 32 insertions(+), 23 deletions(-) rename src/core/hle/{ => kernel}/shared_page.cpp (99%) rename src/core/hle/{ => kernel}/shared_page.h (100%) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 236655688..2ccdaea27 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -144,6 +144,8 @@ add_library(core STATIC hle/kernel/session.h hle/kernel/shared_memory.cpp hle/kernel/shared_memory.h + hle/kernel/shared_page.cpp + hle/kernel/shared_page.h hle/kernel/svc.cpp hle/kernel/svc.h hle/kernel/thread.cpp @@ -386,8 +388,6 @@ add_library(core STATIC hle/service/ssl_c.h hle/service/y2r_u.cpp hle/service/y2r_u.h - hle/shared_page.cpp - hle/shared_page.h hw/aes/arithmetic128.cpp hw/aes/arithmetic128.h hw/aes/ccm.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index be9796aeb..a06a9b549 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -194,7 +194,6 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { #endif service_manager = std::make_shared(*this); - shared_page_handler = std::make_shared(); archive_manager = std::make_unique(*this); HW::Init(); diff --git a/src/core/core.h b/src/core/core.h index ea986f433..0cb53475f 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -8,7 +8,6 @@ #include #include "common/common_types.h" #include "core/frontend/applets/swkbd.h" -#include "core/hle/shared_page.h" #include "core/loader/loader.h" #include "core/memory.h" #include "core/perf_stats.h" @@ -203,10 +202,6 @@ public: return registered_swkbd; } - std::shared_ptr GetSharedPageHandler() const { - return shared_page_handler; - } - private: /** * Initialize the emulated system. @@ -246,9 +241,6 @@ private: std::unique_ptr rpc_server; #endif - /// Shared Page - std::shared_ptr shared_page_handler; - std::unique_ptr archive_manager; public: // HACK: this is temporary exposed for tests, diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e491dfa50..8b5621ca6 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -8,9 +8,9 @@ #include "core/hle/kernel/memory.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" +#include "core/hle/kernel/shared_page.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" -#include "core/hle/shared_page.h" namespace Kernel { @@ -64,4 +64,12 @@ const TimerManager& KernelSystem::GetTimerManager() const { return *timer_manager; } +SharedPage::Handler& KernelSystem::GetSharedPageHandler() { + return *shared_page_handler; +} + +const SharedPage::Handler& KernelSystem::GetSharedPageHandler() const { + return *shared_page_handler; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index e001fa8b7..69e7fdbd9 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -16,6 +16,10 @@ namespace ConfigMem { class Handler; } +namespace SharedPage { +class Handler; +} + namespace Kernel { class AddressArbiter; @@ -202,6 +206,9 @@ public: void MapSharedPages(VMManager& address_space); + SharedPage::Handler& GetSharedPageHandler(); + const SharedPage::Handler& GetSharedPageHandler() const; + private: void MemoryInit(u32 mem_type); @@ -221,6 +228,7 @@ private: std::unique_ptr timer_manager; std::unique_ptr config_mem_handler; + std::unique_ptr shared_page_handler; }; } // namespace Kernel diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp index e8c326569..caa30c837 100644 --- a/src/core/hle/kernel/memory.cpp +++ b/src/core/hle/kernel/memory.cpp @@ -14,6 +14,7 @@ #include "core/core.h" #include "core/hle/kernel/config_mem.h" #include "core/hle/kernel/memory.h" +#include "core/hle/kernel/shared_page.h" #include "core/hle/kernel/vm_manager.h" #include "core/hle/result.h" #include "core/memory.h" @@ -72,6 +73,8 @@ void KernelSystem::MemoryInit(u32 mem_type) { config_mem.app_mem_alloc = memory_region_sizes[mem_type][0]; config_mem.sys_mem_alloc = memory_regions[1].size; config_mem.base_mem_alloc = memory_regions[2].size; + + shared_page_handler = std::make_unique(); } void MemoryShutdown() { @@ -164,11 +167,9 @@ void KernelSystem::MapSharedPages(VMManager& address_space) { auto shared_page_vma = address_space - .MapBackingMemory( - Memory::SHARED_PAGE_VADDR, - reinterpret_cast( - &Core::System::GetInstance().GetSharedPageHandler()->GetSharedPage()), - Memory::SHARED_PAGE_SIZE, MemoryState::Shared) + .MapBackingMemory(Memory::SHARED_PAGE_VADDR, + reinterpret_cast(&shared_page_handler->GetSharedPage()), + Memory::SHARED_PAGE_SIZE, MemoryState::Shared) .Unwrap(); address_space.Reprotect(shared_page_vma, VMAPermission::Read); } diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/kernel/shared_page.cpp similarity index 99% rename from src/core/hle/shared_page.cpp rename to src/core/hle/kernel/shared_page.cpp index 962293609..831782458 100644 --- a/src/core/hle/shared_page.cpp +++ b/src/core/hle/kernel/shared_page.cpp @@ -5,8 +5,8 @@ #include #include #include "core/core_timing.h" +#include "core/hle/kernel/shared_page.h" #include "core/hle/service/ptm/ptm.h" -#include "core/hle/shared_page.h" #include "core/movie.h" #include "core/settings.h" diff --git a/src/core/hle/shared_page.h b/src/core/hle/kernel/shared_page.h similarity index 100% rename from src/core/hle/shared_page.h rename to src/core/hle/kernel/shared_page.h diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index 17902d76c..d64b7def7 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -12,7 +12,6 @@ #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" -#include "core/hle/shared_page.h" namespace Kernel { diff --git a/src/core/hle/service/gsp/gsp_gpu.cpp b/src/core/hle/service/gsp/gsp_gpu.cpp index a6b4826e2..8ed79ebca 100644 --- a/src/core/hle/service/gsp/gsp_gpu.cpp +++ b/src/core/hle/service/gsp/gsp_gpu.cpp @@ -11,6 +11,7 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/shared_page.h" #include "core/hle/result.h" #include "core/hle/service/gsp/gsp_gpu.h" #include "core/hw/gpu.h" @@ -731,7 +732,7 @@ void GSP_GPU::SetLedForceOff(Kernel::HLERequestContext& ctx) { u8 state = rp.Pop(); - system.GetSharedPageHandler()->Set3DLed(state); + system.Kernel().GetSharedPageHandler().Set3DLed(state); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp index 735f485a8..92d712263 100644 --- a/src/core/hle/service/nwm/nwm_uds.cpp +++ b/src/core/hle/service/nwm/nwm_uds.cpp @@ -20,6 +20,7 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/shared_page.h" #include "core/hle/lock.h" #include "core/hle/result.h" #include "core/hle/service/nwm/nwm_uds.h" @@ -1407,8 +1408,8 @@ NWM_UDS::NWM_UDS(Core::System& system) : ServiceFramework("nwm::UDS"), system(sy } } - system.GetSharedPageHandler()->SetMacAddress(mac); - system.GetSharedPageHandler()->SetWifiLinkLevel(SharedPage::WifiLinkLevel::BEST); + system.Kernel().GetSharedPageHandler().SetMacAddress(mac); + system.Kernel().GetSharedPageHandler().SetWifiLinkLevel(SharedPage::WifiLinkLevel::BEST); } NWM_UDS::~NWM_UDS() { diff --git a/src/tests/core/memory/memory.cpp b/src/tests/core/memory/memory.cpp index de1848007..150ec8f66 100644 --- a/src/tests/core/memory/memory.cpp +++ b/src/tests/core/memory/memory.cpp @@ -6,7 +6,7 @@ #include "core/core_timing.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/process.h" -#include "core/hle/shared_page.h" +#include "core/hle/kernel/shared_page.h" #include "core/memory.h" TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { From ece96807c4bbf65f0a0a57987e3086442d4b53dd Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 25 Oct 2018 21:07:15 -0400 Subject: [PATCH 086/102] Kernel: move memory_regions into Kernel instance --- src/core/hle/kernel/kernel.cpp | 4 +--- src/core/hle/kernel/kernel.h | 6 ++++++ src/core/hle/kernel/memory.cpp | 14 ++------------ src/core/hle/kernel/memory.h | 7 ++----- src/core/hle/kernel/process.cpp | 2 +- src/core/hle/kernel/svc.cpp | 14 ++++++++------ src/core/memory.cpp | 2 +- 7 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 8b5621ca6..704b7b709 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -24,9 +24,7 @@ KernelSystem::KernelSystem(u32 system_mode) { } /// Shutdown the kernel -KernelSystem::~KernelSystem() { - Kernel::MemoryShutdown(); -} +KernelSystem::~KernelSystem() = default; ResourceLimitList& KernelSystem::ResourceLimit() { return *resource_limits; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 69e7fdbd9..7d7560e50 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -4,12 +4,14 @@ #pragma once +#include #include #include #include #include #include #include "common/common_types.h" +#include "core/hle/kernel/memory.h" #include "core/hle/result.h" namespace ConfigMem { @@ -209,6 +211,10 @@ public: SharedPage::Handler& GetSharedPageHandler(); const SharedPage::Handler& GetSharedPageHandler() const; + MemoryRegionInfo* GetMemoryRegion(MemoryRegion region); + + std::array memory_regions; + private: void MemoryInit(u32 mem_type); diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp index caa30c837..3a2e9957a 100644 --- a/src/core/hle/kernel/memory.cpp +++ b/src/core/hle/kernel/memory.cpp @@ -14,6 +14,7 @@ #include "core/core.h" #include "core/hle/kernel/config_mem.h" #include "core/hle/kernel/memory.h" +#include "core/hle/kernel/process.h" #include "core/hle/kernel/shared_page.h" #include "core/hle/kernel/vm_manager.h" #include "core/hle/result.h" @@ -24,8 +25,6 @@ namespace Kernel { -MemoryRegionInfo memory_regions[3]; - /// Size of the APPLICATION, SYSTEM and BASE memory regions (respectively) for each system /// memory configuration type. static const u32 memory_region_sizes[8][3] = { @@ -77,16 +76,7 @@ void KernelSystem::MemoryInit(u32 mem_type) { shared_page_handler = std::make_unique(); } -void MemoryShutdown() { - for (auto& region : memory_regions) { - region.base = 0; - region.size = 0; - region.used = 0; - region.linear_heap_memory = nullptr; - } -} - -MemoryRegionInfo* GetMemoryRegion(MemoryRegion region) { +MemoryRegionInfo* KernelSystem::GetMemoryRegion(MemoryRegion region) { switch (region) { case MemoryRegion::APPLICATION: return &memory_regions[0]; diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h index a39a53977..14a38bdb9 100644 --- a/src/core/hle/kernel/memory.h +++ b/src/core/hle/kernel/memory.h @@ -5,11 +5,12 @@ #pragma once #include +#include #include "common/common_types.h" -#include "core/hle/kernel/process.h" namespace Kernel { +struct AddressMapping; class VMManager; struct MemoryRegionInfo { @@ -20,10 +21,6 @@ struct MemoryRegionInfo { std::shared_ptr> linear_heap_memory; }; -void MemoryShutdown(); -MemoryRegionInfo* GetMemoryRegion(MemoryRegion region); - void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping); -extern MemoryRegionInfo memory_regions[3]; } // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 9b45c77f1..c41d4ebd9 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -115,7 +115,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) { } void Process::Run(s32 main_thread_priority, u32 stack_size) { - memory_region = GetMemoryRegion(flags.memory_region); + memory_region = kernel.GetMemoryRegion(flags.memory_region); auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 07079fc4d..9dc6f2700 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1233,22 +1233,24 @@ static ResultCode AcceptSession(Handle* out_server_session, Handle server_port_h static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) { LOG_TRACE(Kernel_SVC, "called type={} param={}", type, param); + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + switch ((SystemInfoType)type) { case SystemInfoType::REGION_MEMORY_USAGE: switch ((SystemInfoMemUsageRegion)param) { case SystemInfoMemUsageRegion::ALL: - *out = GetMemoryRegion(MemoryRegion::APPLICATION)->used + - GetMemoryRegion(MemoryRegion::SYSTEM)->used + - GetMemoryRegion(MemoryRegion::BASE)->used; + *out = kernel.GetMemoryRegion(MemoryRegion::APPLICATION)->used + + kernel.GetMemoryRegion(MemoryRegion::SYSTEM)->used + + kernel.GetMemoryRegion(MemoryRegion::BASE)->used; break; case SystemInfoMemUsageRegion::APPLICATION: - *out = GetMemoryRegion(MemoryRegion::APPLICATION)->used; + *out = kernel.GetMemoryRegion(MemoryRegion::APPLICATION)->used; break; case SystemInfoMemUsageRegion::SYSTEM: - *out = GetMemoryRegion(MemoryRegion::SYSTEM)->used; + *out = kernel.GetMemoryRegion(MemoryRegion::SYSTEM)->used; break; case SystemInfoMemUsageRegion::BASE: - *out = GetMemoryRegion(MemoryRegion::BASE)->used; + *out = kernel.GetMemoryRegion(MemoryRegion::BASE)->used; break; default: LOG_ERROR(Kernel_SVC, "unknown GetSystemInfo type=0 region: param={}", param); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 0054dc75e..eed279c9a 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -305,7 +305,7 @@ u8* GetPhysicalPointer(PAddr address) { target_pointer = Core::DSP().GetDspMemory().data() + offset_into_region; break; case FCRAM_PADDR: - for (const auto& region : Kernel::memory_regions) { + for (const auto& region : Core::System::GetInstance().Kernel().memory_regions) { if (offset_into_region >= region.base && offset_into_region < region.base + region.size) { target_pointer = From fc84091d88ce131be7cbb143b4cd458bb0d1da51 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Fri, 26 Oct 2018 10:27:13 -0400 Subject: [PATCH 087/102] Service, Kernel: move named port list to kernel --- src/core/core.cpp | 1 - src/core/hle/kernel/kernel.cpp | 5 +++++ src/core/hle/kernel/kernel.h | 7 +++++++ src/core/hle/kernel/svc.cpp | 10 +++++----- src/core/hle/service/service.cpp | 15 +-------------- src/core/hle/service/service.h | 10 ---------- 6 files changed, 18 insertions(+), 30 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index a06a9b549..78585380c 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -256,7 +256,6 @@ void System::Shutdown() { // Shutdown emulation session GDBStub::Shutdown(); VideoCore::Shutdown(); - Service::Shutdown(); kernel.reset(); HW::Shutdown(); telemetry_session.reset(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 704b7b709..1c174d2ea 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/config_mem.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" @@ -70,4 +71,8 @@ const SharedPage::Handler& KernelSystem::GetSharedPageHandler() const { return *shared_page_handler; } +void KernelSystem::AddNamedPort(std::string name, SharedPtr port) { + named_ports.emplace(std::move(name), std::move(port)); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 7d7560e50..f010cd388 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include "common/common_types.h" @@ -215,6 +216,12 @@ public: std::array memory_regions; + /// Adds a port to the named port table + void AddNamedPort(std::string name, SharedPtr port); + + /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort + std::unordered_map> named_ports; + private: void MemoryInit(u32 mem_type); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9dc6f2700..f23b569d7 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -235,8 +235,10 @@ static ResultCode ConnectToPort(Handle* out_handle, VAddr port_name_address) { LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); - auto it = Service::g_kernel_named_ports.find(port_name); - if (it == Service::g_kernel_named_ports.end()) { + KernelSystem& kernel = Core::System::GetInstance().Kernel(); + + auto it = kernel.named_ports.find(port_name); + if (it == kernel.named_ports.end()) { LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); return ERR_NOT_FOUND; } @@ -247,9 +249,7 @@ static ResultCode ConnectToPort(Handle* out_handle, VAddr port_name_address) { CASCADE_RESULT(client_session, client_port->Connect()); // Return the client session - CASCADE_RESULT(*out_handle, - Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Create( - client_session)); + CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(client_session)); return RESULT_SUCCESS; } diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 2402a786d..d4112fc21 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -61,8 +61,6 @@ using Kernel::SharedPtr; namespace Service { -std::unordered_map> g_kernel_named_ports; - const std::array service_module_map{ {{"FS", 0x00040130'00001102, FS::InstallInterfaces}, {"PM", 0x00040130'00001202, PM::InstallInterfaces}, @@ -149,7 +147,7 @@ void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelSystem& kernel) { SharedPtr client_port; std::tie(server_port, client_port) = kernel.CreatePortPair(max_sessions, service_name); server_port->SetHleHandler(shared_from_this()); - AddNamedPort(service_name, std::move(client_port)); + kernel.AddNamedPort(service_name, std::move(client_port)); } void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { @@ -214,11 +212,6 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr server_ses //////////////////////////////////////////////////////////////////////////////////////////////////// // Module interface -// TODO(yuriks): Move to kernel -void AddNamedPort(std::string name, SharedPtr port) { - g_kernel_named_ports.emplace(std::move(name), std::move(port)); -} - static bool AttemptLLE(const ServiceModuleInfo& service_module) { if (!Settings::values.lle_modules.at(service_module.name)) return false; @@ -247,10 +240,4 @@ void Init(Core::System& core) { LOG_DEBUG(Service, "initialized OK"); } -/// Shutdown ServiceManager -void Shutdown() { - - g_kernel_named_ports.clear(); - LOG_DEBUG(Service, "shutdown OK"); -} } // namespace Service diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 5cb4fbf23..5f36f98de 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -8,7 +8,6 @@ #include #include #include -#include #include #include "common/common_types.h" #include "core/hle/kernel/hle_ipc.h" @@ -187,12 +186,6 @@ private: /// Initialize ServiceManager void Init(Core::System& system); -/// Shutdown ServiceManager -void Shutdown(); - -/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. -extern std::unordered_map> g_kernel_named_ports; - struct ServiceModuleInfo { std::string name; u64 title_id; @@ -201,7 +194,4 @@ struct ServiceModuleInfo { extern const std::array service_module_map; -/// Adds a port to the named port table -void AddNamedPort(std::string name, Kernel::SharedPtr port); - } // namespace Service From edb7ef5e5f22c90230861099ea10e26303c4d205 Mon Sep 17 00:00:00 2001 From: Hexagon12 Date: Fri, 2 Nov 2018 19:07:29 +0200 Subject: [PATCH 088/102] Updated translations (18/11/02) --- dist/languages/da_DK.ts | 851 +++++++++------ dist/languages/de.ts | 1049 ++++++++++++------- dist/languages/es_ES.ts | 855 +++++++++------ dist/languages/fr.ts | 919 ++++++++++------ dist/languages/hu_HU.ts | 851 +++++++++------ dist/languages/id.ts | 1306 ++++++++++++++--------- dist/languages/it.ts | 1127 ++++++++++++-------- dist/languages/ja_JP.ts | 851 +++++++++------ dist/languages/ko_KR.ts | 875 ++++++++++------ dist/languages/lt_LT.ts | 921 ++++++++++------ dist/languages/nb.ts | 1140 ++++++++++++-------- dist/languages/nl.ts | 2193 +++++++++++++++++++++++++++++++-------- dist/languages/pl_PL.ts | 853 +++++++++------ dist/languages/pt_BR.ts | 1205 ++++++++++++--------- dist/languages/pt_PT.ts | 851 +++++++++------ dist/languages/ru_RU.ts | 853 +++++++++------ dist/languages/tr_TR.ts | 861 +++++++++------ dist/languages/vi_VN.ts | 1035 +++++++++++------- dist/languages/zh_CN.ts | 857 +++++++++------ dist/languages/zh_TW.ts | 853 +++++++++------ 20 files changed, 13408 insertions(+), 6898 deletions(-) diff --git a/dist/languages/da_DK.ts b/dist/languages/da_DK.ts index ccd2e9d4a..5a35a8301 100644 --- a/dist/languages/da_DK.ts +++ b/dist/languages/da_DK.ts @@ -70,45 +70,50 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Pica-kommando indlæst - + Pica command processed Pica-kommando behandlet - + Incoming primitive batch Kommende primitivt parti - + Finished primitive batch Færdiggjort primitivt parti - + Vertex shader invocation Aktivering af vertex-shader - + Incoming display transfer Kommende displayoverførsel - + GSP command processed GSP-kommando behandlet - + Buffers swapped Buffers byttet + + + Unknown debug context event + + CalibrationConfigurationDialog @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } Spil - - + + Block Player - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected Forbundet - + Disconnected Afbrudt - + %1 (%2/%3 members) - connected %1 (%2/%3 medlemmer) - forbundet @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! Tak for din indsendelse! + + + Submitting + + + + + Communication error + + + + + An error occured while sending the Testcase + + + + + Next + + ConfigureAudio @@ -340,9 +365,9 @@ p, li { white-space: pre-wrap; } - - - %1 % + + %1% + Volume percentage (e.g. 50%) @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration Konfiguration af Citra - + + + General Generelt - + + + System System - + + + Input Input - + + + Graphics Grafik - + + + Audio Lyd - + + + Camera Kamera - + + + Debug Fejlfinding - + + + Web Web + + + + + UI + + + + + Controls + + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } Bekræft afslutning når emulatoren kører - - Interface language - Sprog i grænsefladen - - - + Updates Opdateringer - + Check for updates on start Tjek efter opdateringer ved opstart - + Silently auto update after closing Opdater automatisk i baggrunden efter lukning - + Emulation Emulering - + Region: Region: - + Auto-select Vælg automatisk - - Theme - Tema: - - - - Theme: - Tema: - - - + Hotkeys Genvejstaster - - <System> - <System> + + Reset All Settings + - - English - Engelsk + + Citra + + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick Indstil analogstik @@ -1067,11 +1110,44 @@ p, li { white-space: pre-wrap; } + Clear All + + + + Restore Defaults Gendan standarder - + + + Clear + + + + + + [not set] + + + + + + Restore Default + + + + + Information + + + + + After pressing OK, first move your joystick horizontally, and then vertically. + + + + [press key] [tryk på tast] @@ -1440,17 +1516,27 @@ p, li { white-space: pre-wrap; } - + + yyyy-MM-ddTHH:mm:ss + + + + + Play Coins: + + + + Console ID: Konsol-id: - + Regenerate Generer nyt - + System settings are available only when game is not running. Systemindstillinger kan kun ændres når et spil ikke kører. @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } - - + + Console ID: 0x%1 Konsol-id: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? Dette erstatter din nuværende virtuelle 3DS med en ny. Din nuværende virtuelle 3DS vil ikke kunne genskabes. Dette kan have uventede effekter i spil. Dette fejler måske hvis du bruger et forældet config-lager. Fortsæt? - + Warning Advarsel + + ConfigureUi + + + Form + + + + + General + + + + + Interface language: + + + + + Theme: + + + + + Game List + + + + + Icon Size: + + + + + + None + + + + + Small (24x24) + + + + + Large (48x48) + + + + + Row 1 Text: + + + + + + File Name + + + + + + Full Path + + + + + + Title Name + + + + + + Title ID + + + + + Row 2 Text: + + + + + Hide Titles without Icon + + + + + <System> + + + + + English + + + ConfigureWeb @@ -2155,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify Bekræft @@ -2215,48 +2399,48 @@ p, li { white-space: pre-wrap; } - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Lær mere</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Opret konto</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">Hvad er min token?</span></a> - - + + Telemetry ID: 0x%1 Telemetri-id: 0x%1 - + Username and token not verified Brugernavn og token er ikke bekræftet - + Username and token were not verified. The changes to your username and/or token have not been saved. Dit brugernavn og token blev ikke bekræftet. Ændringerne til dit brugernavn eller token er bliver blevet gemt. - + Verifying Bekræfter - + Verification failed Bekræftelse mislykkedes - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. Bekræftelse mislykkedes. Kontroller, at du har indtastet dit brugernavn og token korrekt og at din internetforbindelse virker. @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting Forbinder - + Connect Forbind @@ -2330,413 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? - + Telemetry - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Nuværende emuleringshastighed. Værdier højere eller lavere end 100% indikerer at emuleringen kører hurtigere eller langsommere end en 3DS. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Hvor mange billeder pr sekund spillet vises med. Dette vil variere fra spil til spil og scene til scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tid det tog at emulere en 3DS-skærmbillede, hastighedsbegrænsning og v-sync er tille talt med. For emulering med fuld hastighed skal dette højest være 16,67ms. - + Clear Recent Files - + F9 F9 - + F10 F10 - + CTRL+F Ctrl+F - + Update Available - + An update is available. Would you like to install it now? - + No Update Found - + No update is found. - - + + OpenGL 3.3 Unsupported + + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + + + + + Invalid ROM Format - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + ROM Corrupted - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + ROM Encrypted - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - - + + Video Core Error - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. - + Error while loading ROM! Kunne ikke indlæse ROM! - + An unknown error occured. Please see the log for more details. En ukendt fejl opstod. Kig i logfilen for flere detaljer. - + Start Start - + Error Opening %1 Folder Fejl ved åbning af %1-mappen - - + + Folder does not exist! Mappen findes ikke! - + Error Opening %1 - + Select Directory Vælg mappe - - 3DS Executable - 3DS-programfil + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + - - - All Files (*.*) - Alle filer (*.*) - - - + Load File Indlæs fil - + Load Files Indlæs filer - + 3DS Installation File (*.CIA*) 3DS-installationsfil (*.CIA) - + + All Files (*.*) + Alle filer (*.*) + + + %1 has been installed successfully. %1 blev succesfuldt installeret. - + Unable to open File Kunne ikke åbne filen - + Could not open %1 Kunne ikke åbne %1 - + Installation aborted Installation afbrudt - + The installation of %1 was aborted. Please see the log for more details Installationen af %1 blev afbrudt. Se logfilen for flere detaljer. - + Invalid File Ugyldig fil - + %1 is not a valid CIA %1 er ikke en gyldig CIA - + Encrypted File Krypteret fil - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 skal dekrypteres før brug i Citra. En rigtig 3DS skal bruges. - + File not found Filen blev ikke fundet - + File "%1" not found Filen "%1" blev ikke fundet - - - + + + Continue Fortsæt - + Missing Citra Account Manglende Citra-konto - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. - - - + + Amiibo File (%1);; All Files (*.*) + + + + + Load Amiibo + + + + + + + Record Movie - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + + + + + Citra TAS Movie (*.ctm) - + Recording will start once you boot a game. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. - + Revision Dismatch - + Game Dismatch - - + + Invalid Movie File - + + Play Movie - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + + + + Game Not Found - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. - + Movie recording cancelled. - + Movie Saved - + The movie is successfully saved. - + Speed: %1% / %2% Hastighed: %1%/%2% - + Speed: %1% Hastighed: %1% - + Game: %1 FPS Spil: %1FPS - + Frame: %1 ms Billede: %1ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + System Archive Not Found Systemarkiver blev ikke fundet - + Fatal Error Alvorlig fejl - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Abort - - + + Citra Citra - + Would you like to exit now? - + The game is still running. Would you like to stop emulation? - + Playback Completed - + Movie playback completed. - + Citra %1 - + Citra %1| %2 @@ -2799,37 +3015,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + + + + + Compatibility + + + + + Region + + + + + File type + + + + + Size + + + + Open Save Data Location Åbn mappe til spildata - + + Open Extra Data Location + + + + Open Application Location Åbn programmappe - + Open Update Data Location Åbn mappe til opdateringsdata - + Navigate to GameDB entry Naviger til GameDB-side - + Scan Subfolders - + Remove Game Directory - + Open Directory Location @@ -2837,77 +3083,77 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. - + Bad - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot - + The game crashes when attempting to startup. - + Not Tested - + The game has not yet been tested. @@ -2915,7 +3161,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the game list @@ -2923,27 +3169,27 @@ Screen. GameListSearchField - + of - + result - + results - + Filter: - + Enter pattern to filter @@ -2951,23 +3197,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Pica-breakpoints - - + + Emulation running Emulering kører - + Resume Fortsæt - + Emulation halted at breakpoint Emuleringen stoppet ved breakpoint @@ -3384,42 +3630,42 @@ Screen. Genopfrisk lobby - + Password Required to Join Adgangskode krævet for deltagelse - + Password: Adgangskode: - + Room Name Rumnavn - + Preferred Game Foretrukket spil - + Host Vært - + Players Spillere - + Refreshing Genopfrisker - + Refresh List Genopfrisk liste @@ -3442,220 +3688,245 @@ Screen. Seneste filer - + + Amiibo + + + + &Emulation &Emulering - + &View &Vis - + Debugging Fejlfinding - + Screen Layout Skærmlayout - + Movie - + Multiplayer Multiplayer - + &Help &Hjælp - + Load File... Indlæs fil… - + Install CIA... Installer CIA… - + Load Symbol Map... Indlæs symbolliste… - + E&xit A&fslut - + &Start &Start - + &Pause &Pause - + &Stop &Stop - + FAQ FAQ - + About Citra Om Citra - + Single Window Mode Tilstand med enkelt vindue - + Configure... Konfigurer… - + Display Dock Widget Headers Vis titler på dokbare widgets - + Show Filter Bar Vis filterlinje - + Show Status Bar Vis statuslinje - + Select Game Directory... Vælg spilmappe… - + Selects a folder to display in the game list Vælger en mappe, der bliver vist i spillisten - + Create Pica Surface Viewer Opret Pica-overfladeviser - + Record Movie - + Play Movie - + Stop Recording / Playback - + + Enable Frame Advancing + + + + + Advance Frame + + + + Browse Public Game Lobby Gennemse offentlig spillobby - + Create Room Opret rum - + Leave Room Forlad rum - + Direct Connect to Room Forbind direkte til rum - + Show Current Room Vis nuværende rum - + Fullscreen Fuld skærm - + Modify Citra Install Modificer Citra-installation - + Opens the maintenance tool to modify your Citra installation Åben vedligeholdelsesværktøjet for at modificere din installation af Citra - + Default Standard - + Single Screen Enkelt skærm - + Large Screen Stor skærm - + Side by Side Side om side - + Swap Screens Byt om på skærme - + Check for Updates Tjek efter opdateringer - + Report Compatibility Rapporter kompatibilitet - + Restart + + + Load... + + + + + Remove + + MicroProfileDialog @@ -3681,23 +3952,23 @@ Screen. - + Connected Forbundet - + Not Connected Ikke forbundet - + Error Fejl - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: Kunne ikke annoncere om rummet i den offentlige lobby. For at køre et offentligt rum skal du have en gyldig Citra-konto sat op i Emulering -> Konfiguration -> Web. Hvis du ikke har lyst til at at offentliggøre et rum i lobbyen, vælg i stedet "ikke listet". @@ -3816,106 +4087,106 @@ Fejlfindingsbesked: %1 spiller %2 - - + + Invalid region Ugyldig region - + Japan Japan - + North America Nordamerika - + Europe Europa - + Australia Australien - + China Kina - + Korea Korea - + Taiwan Taiwan - + Region free Regionsfri - + Invalid Region Ugyldig region - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [ikke sat] - + Hat %1 %2 - + Axis %1%2 - + Button %1 - - + + [unknown] [ukendt] - + [unused] [ubrugt] - - + + Axis %1 diff --git a/dist/languages/de.ts b/dist/languages/de.ts index 925cffc0c..b7de72426 100644 --- a/dist/languages/de.ts +++ b/dist/languages/de.ts @@ -70,52 +70,57 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Pica-Befehl geladen - + Pica command processed Pica-Befehl verarbeitet - + Incoming primitive batch Eingehender primitiver Stapel - + Finished primitive batch Fertiger primitiver Stapel - + Vertex shader invocation Vertex Shader Aufruf - + Incoming display transfer Eingehende Anzeigeübertragung - + GSP command processed GSP-Befehl verarbeitet - + Buffers swapped Puffer getauscht + + + Unknown debug context event + + CalibrationConfigurationDialog Communicating with the server... - Kommuniziere mit Server... + Kommuniziere mit dem Server... @@ -130,12 +135,12 @@ p, li { white-space: pre-wrap; } Now touch the bottom right corner <br>of your touchpad. - Jetzt berühre die untere rechte Ecke <br>deines Touchpads. + Berühre jetzt die untere rechte Ecke <br>deines Touchpads. Configuration completed! - Konfiguration erfolgreich! + Konfiguration abgeschlossen! @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } Spiel - - + + Block Player Spieler blockieren - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? Wenn du einen Spieler blockierst, kannst du keine Chatnachrichten mehr von dem Spieler empfangen.<br><br> Bist du sicher, dass du %1 blockieren möchtest? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected Verbunden - + Disconnected Nicht verbunden - + %1 (%2/%3 members) - connected %1 (%2/%3 Nutzer) - verbunden @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! Vielen Dank für deinen Beitrag! + + + Submitting + + + + + Communication error + + + + + An error occured while sending the Testcase + + + + + Next + + ConfigureAudio @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + %1% @@ -600,56 +625,84 @@ p, li { white-space: pre-wrap; } Enable CPU JIT - CPU JIT einschalten + CPU JIT aktivieren ConfigureDialog - + Citra Configuration Citra-Konfiguration - + + + General Allgemein - + + + System System - + + + Input Eingabe - + + + Graphics Grafik - + + + Audio Audio - + + + Camera Kamera - + + + Debug Debug - + + + Web Web + + + + + UI + Nutzeroberfläche + + + + Controls + Steuerung + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } Verlassen bestätigen, wenn Emulation läuft - - Interface language - Benutzeroberflächensprache - - - + Updates Updates - + Check for updates on start Beim Start auf Updates überprüfen - + Silently auto update after closing Nach dem Beenden im Hintergrund automatisch updaten - + Emulation Emulation - + Region: Region: - + Auto-select Automatisch auswählen - - Theme - Design - - - - Theme: - Design: - - - + Hotkeys Tastenkürzel - - <System> - <System> + + Reset All Settings + Alle Einstellungen zurücksetzen - - English - Englisch + + Citra + Citra + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + Bist du dir sicher, dass du <b>die Einstellungen zurücksetzen</b> und Citra beenden möchtest? @@ -925,7 +968,7 @@ p, li { white-space: pre-wrap; } Hardware Shader support is broken on macOS, and will cause graphical issues like showing a black screen.<br><br>The option is only there for test/development purposes. If you experience graphical issues with Hardware Shader, please turn it off. - Hardware Shader support funktioniert nicht unter macOS und wird grafische Fehler, wie zum Beispiel das Anzeigen eines schwarzen Bildschirms hervorrufen. <br><br>Die Option ist nur für Test- und Entwicklungszwecke vorhanden. Bitte schalte es aus, wenn du grafische Fehler mit Hardware Shadern feststellst. + Hardware Shader Support funktioniert unter MacOS nicht wie vorhergesehen und verursacht Grafikfehler, wie zum Beispiel das Anzeigen eines schwarzen Bildschirms. <br><br>Die Option ist nur für Test- und Entwicklungszwecke vorhanden. Bitte deaktiviere die Option, wenn du Grafikfehler feststellst. @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick Analog-Stick festlegen @@ -1063,15 +1106,48 @@ p, li { white-space: pre-wrap; } Motion / Touch... - + Bewegungssteuerung / Toucheingaben... + Clear All + Alle zurücksetzen + + + Restore Defaults Standardwerte wiederherstellen - + + + Clear + Zurücksetzen + + + + + [not set] + [Nicht konfiguriert] + + + + + Restore Default + Standard wiederherstellen + + + + Information + Information + + + + After pressing OK, first move your joystick horizontally, and then vertically. + Drücke OK und bewege den Joystick anschließend zuerst in horizontale, dann in vertikale Richtung. + + + [press key] [Taste drücken] @@ -1081,165 +1157,165 @@ p, li { white-space: pre-wrap; } Configure Motion / Touch - + Bewegungssteuerung / Toucheingaben konfigurieren Motion - + Bewegungssteuerung Motion Provider: - + Quelle Bewegungsdaten: Sensitivity: - + Empfindlichkeit: Touch - + Touch Touch Provider: - + Quelle Toucheingaben: Calibration: - + Kalibrierung: (100, 50) - (1800, 850) - + (100, 50) - (1800, 850) Configure - + Konfigurieren CemuhookUDP Config - + CemuhookUDP Konfiguration You may use any Cemuhook compatible UDP input source to provide motion and touch input. - + Du kannst jede mit Cemuhook kompatible UDP Quelle verwenden, um Touch- und Bewegungseingaben bereitzustellen. Server: - + Server: Port: - + Port: Pad: - + Pad: Pad 1 - + Pad 1 Pad 2 - + Pad 2 Pad 3 - + Pad 3 Pad 4 - + Pad 4 Learn More - + Mehr erfahren Test - + Test Mouse (Right Click) - + Maus (Rechtsklick) CemuhookUDP - + CemuhookUDP Emulator Window - + Emulator Fenster <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - + <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Mehr erfahren</span></a> Testing - + Test läuft Configuring - + Wird konfiguriert Test Successful - + Test erfolgreich Successfully received data from the server. - + Daten wurden erfolgreich vom Server empfangen. Test Failed - + Test gescheitert Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. - + Keine gültigen Daten vom Server empfangen. Bitte versichere dich, dass der Server korrekt eingerichtet ist und die Serveradresse und der Port richtig sind. Citra - + Citra UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. - + UDP Test oder Kalibrierung werden gerade ausgeführt.<br>Bitte warte, bis sie abgeschlossen sind. @@ -1437,20 +1513,30 @@ p, li { white-space: pre-wrap; } Startup time - + Zum Start benötigte Zeit - + + yyyy-MM-ddTHH:mm:ss + yyyy-MM-ddTHH:mm:ss + + + + Play Coins: + Spielemünzen + + + Console ID: Konsolen-ID: - + Regenerate Wiederherstellen - + System settings are available only when game is not running. Systemeinstellungen sind nur verfügbar wenn kein Spiel läuft. @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } Bermudas - - + + Console ID: 0x%1 Konsolen-ID: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? Dies wird deinen jetziger virtueller 3DS wird mit einem neuen ersetzt. Dein jetziger virtueller 3DS kann nicht wiederhergestellt werden. Es könnte unerwartete Effekte in Spielen haben. Es könnte fehlschlagen, wenn du einen veralteten Konfigurationspeicherstand benutzt. Fortfahren? - + Warning Warnung + + ConfigureUi + + + Form + + + + + General + Allgemein + + + + Interface language: + Oberflächensprache + + + + Theme: + Thema: + + + + Game List + Spieleliste + + + + Icon Size: + Icongröße + + + + + None + + + + + Small (24x24) + Klein (24x24) + + + + Large (48x48) + Groß (48x48) + + + + Row 1 Text: + Text Zeile 1: + + + + + File Name + Dateiname + + + + + Full Path + Vollständiger Pfad + + + + + Title Name + Titelname + + + + + Title ID + Titel ID + + + + Row 2 Text: + Text Zeile 2: + + + + Hide Titles without Icon + Titel ohne Icon verbergen + + + + <System> + <System> + + + + English + Englisch + + ConfigureWeb @@ -2155,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify Verifizieren @@ -2207,56 +2391,56 @@ p, li { white-space: pre-wrap; } Discord Presence - + Discord Presence Show Current Game in your Discord Status - + Aktuelles Spiel in deinem Discordstatus anzeigen - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Mehr erfahren</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Registrieren</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Anmelden</span></a> - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">Was ist mein Token?</span></a> - - + + Telemetry ID: 0x%1 Telemetrie-ID: 0x%1 - + Username and token not verified Benutzername und Token nicht verifiziert - + Username and token were not verified. The changes to your username and/or token have not been saved. Nutzername und Token wurden nicht verifiziert. Die Änderungen an deinem Nutzernamen und/oder Token wurden nicht gespeichert. - + Verifying Verifiziere - + Verification failed Verifizierung fehlgeschlagen - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. Verifizierung fehlgeschlagen. Überprüfe, dass du deinen Nutzernamen und Token korrekt eingegeben hast und deine Internetverbindung funktioniert. @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting Verbinden - + Connect Verbinden @@ -2330,413 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? - + Möchtest du <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>anonyme Nutzungsdaten</a> mit dem Citra-Team teilen und so helfen, Citra weiter zu verbessern? - + Telemetry Telemetrie - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Derzeitige Emulationsgeschwindigkeit. Werte höher oder niedriger als 100% zeigen, dass die Emulation schneller oder langsamer läuft als auf einem 3DS. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Die Anzahl der Bilder pro Sekunde die das Spiel gerade darstellt. Dies wird von Spiel zu Spiel und von Szene zu Szene variieren. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Die benötigte Zeit um ein 3DS-Einzelbild zu emulieren (V-Sync oder Bildratenbegrenzung nicht mitgezählt). Für eine Emulation in Echtzeit sollte dies maximal 16,67 ms betragen. - + Clear Recent Files - + Kürzlich verwendete Dateien zurücksetzten - + F9 F9 - + F10 F10 - + CTRL+F STRG+F - + Update Available Update verfügbar - + An update is available. Would you like to install it now? Ein Update ist verfügbar. Möchtest du es jetzt installieren? - + No Update Found - Kein Update + Kein Update gefunden - + No update is found. Kein Update gefunden. - - + + OpenGL 3.3 Unsupported + OpenGL 3.3 wird nicht unterstützt + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + Dein Grafiktreiber unterstützt OpenGL 3.3 möglicherweise nicht, oder der Grafiktreiber ist nicht aktuell. + + + + Invalid ROM Format Ungültiges ROM-Format - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - Dieses ROM-Format wird nicht unterstützt.<br/>Bitte befolge die Guides um deine <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>Karten</a> oder <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installierte Titel</a>neu zu dumpen. + Dieses ROM-Format wird nicht unterstützt.<br/>Bitte befolge die Guides, um deine <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>Spielekarten</a> oder <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installierten Titel</a>erneut zu dumpen. - + ROM Corrupted - Korrupte ROM + ROM beschädigt - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - Deine ROM ist korrupt. <br/>Bitte befolge die Guides um deine <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>Karten</a> oder <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installierte Titel</a>neu zu dumpen. + Dieses ROM ist korrupt. <br/>Bitte befolge die Guides, um deine <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>Karten</a> oder <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installierten Titel</a> erneut zu dumpen. - + ROM Encrypted ROM verschlüsselt - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - Deine ROM ist verschlüsselt. <br/>Bitte befolge die Guides um deine <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>Karten</a> oder <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installierte Titel</a>neu zu dumpen. + Deine ROM ist verschlüsselt. <br/>Bitte befolge die Guides, um deine <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>Spielekarten</a> oder <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installierten Titel</a>erneut zu dumpen. - - + + Video Core Error Video Kern Fehler - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. - Ein Fehler ist aufgetreten. Bitte <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>schau in den Log</a> für mehr Details. Stelle sicher, dass du die neuesten Grafiktreiber für deine GPU hast. + Ein Fehler ist aufgetreten. Weitere Details findest du in der <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Logdatei</a>. Stelle sicher, dass du den aktuellsten Grafiktreiber für deine GPU installiert hast. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. Du benutzt die vorinstallierten Windows Treiber für deine GPU. Du musst die richtigen Treiber für deine Grafikkarte von der Herstellerseite laden und installieren. - + Error while loading ROM! Fehler beim Laden des ROMs! - + An unknown error occured. Please see the log for more details. Ein unbekannter Fehler ist aufgetreten. Bitte schau für mehr Details in den Log. - + Start Start - + Error Opening %1 Folder Fehler beim Öffnen des Ordners %1 - - + + Folder does not exist! Ordner existiert nicht! - + Error Opening %1 Fehler beim Öffnen von %1 - + Select Directory Ordner auswählen - - 3DS Executable - 3DS-Executable + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + 3DS Programmdatei (%1);;Alle Dateien (*.*) - - - All Files (*.*) - Alle Dateien (*.*) - - - + Load File Datei laden - + Load Files Dateien laden - + 3DS Installation File (*.CIA*) 3DS Installationsdatei (*.CIA*) - + + All Files (*.*) + Alle Dateien (*.*) + + + %1 has been installed successfully. %1 wurde erfolgreich installiert. - + Unable to open File Datei konnte nicht geöffnet werden - + Could not open %1 Konnte %1 nicht öffnen - + Installation aborted Installation abgebrochen - + The installation of %1 was aborted. Please see the log for more details Die Installation von %1 wurde abgebrochen. Weitere Details dazu im Log. - + Invalid File Ungültige Datei - + %1 is not a valid CIA %1 ist kein gültiges CIA - + Encrypted File Verschlüsselte Datei - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 muss entschlüsselt werden, bevor es mit Citra verwendet werden kann. Hierzu ist ein 3DS ist notwendig. - + File not found Datei nicht gefunden - + File "%1" not found Datei "%1" nicht gefunden - - - + + + Continue Fortsetzen - + Missing Citra Account Fehlender Citra-Account - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. Du musst deinen deinen Citra-Account verknüpfen, um Tests hochzuladen.<br/>Gehe zu Emulation &gt; Configure... &gt; Web um das zu tun. - - - + + Amiibo File (%1);; All Files (*.*) + Amiibo Datei (%1);; Alle Dateien (*.*) + + + + Load Amiibo + Amiibo laden + + + + + + Record Movie Aufnahme - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + Um unterschiedliche Ergebnisse bei zufallsbasierten Ereignissen zu vermeiden, sollte eine Aufnahme zusammen mit dem dem Spiel gestartet werden. <br>Möchtest du die Aufnahme dennoch jetzt starten? + + + + Citra TAS Movie (*.ctm) Citra TAS Movie (*.ctm) - + Recording will start once you boot a game. - Die Aufnahme startet sobald du ein Spiel startest. + Die Aufnahme startet, sobald du ein Spiel startest. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? - Die gewünschte Movie Datei wurde mit einer anderen Version von Citra erstellt.<br/>Citra hatte seitdem einige Änderungen, und das Playback könnte nicht synchron oder fehlerhaft sein.<br/><br/>Soll die Datei trotzdem geladen werden? + Die gewünschte Aufnahme wurde mit einer anderen Version von Citra erstellt.<br/>Citra hat seitdem einige Änderungen durchlaufen und die Aufnahme könnte asynchron oder fehlerhaft sein.<br/><br/>Soll sie trotzdem geladen werden? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? - Die gewünschte Movie Datei wurde mit einem anderen Spiel aufgenommen.<br/>Die Wiedergabe könnte unerwartete Fehler beinhalten.<br/><br/>Soll die Datei trotzdem geladen werden? + Die gewünschte Aufnahme wurde mit einem anderen Spiel aufgenommen.<br/>Die Wiedergabe könnte unerwartete Fehler verursachen.<br/><br/>Soll sie dennoch geladen werden? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. - Die gewünschte Movie Datei ist fehlerhaft.<br/>Entweder ist die Datei korrupt oder Citra hatte große Änderungen im Movie-Modul.<br/><br/>Bitte wähle eine andere Movie-Datei und versuche es noch einmal. + Die gewünschte Aufnahme ist ungültig.<br/>Die Datei ist entweder beschädigt, oder es wurden große Veränderungen an Citra's Aufnahme-Modul vorgenommen.<br/><br/>Bitte wähle eine andere Aufnahme und versuche es noch einmal. - + Revision Dismatch - + Revision stimmt nicht überein - + Game Dismatch - + Spiel stimmt nicht überein - - + + Invalid Movie File - Fehlerhafte Movie-Datei + Ungültige Aufnahme - + + Play Movie - Movie abspielen + Aufnahme abspielen - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + Um unterschiedliche Ergebnisse bei zufallsbasierten Ereignissen während der Wiedergabe einer Aufnahme zu vermeiden, sollte die Wiedergabe immer zusammen mit dem Spiel gestartet werden. <br>Möchtest du die Aufnahme dennoch jetzt wiedergeben? + + + Game Not Found Spiel nicht gefunden - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. - Das gewünschte Movie ist von einem Spiel, das nicht in der Liste ist. Falls du das Spiel besitzt, bitte füge es zum Spiele-Ordner hinzu und versuche nochmal, es abzuspielen. + Die gewünschte Aufnahme ist von einem Spiel, das nicht in der Liste ist. Wenn du das Spiel besitzt, füge den entsprechenden Ordner zur Spieleliste hinzu und versuche es erneut. - + Movie recording cancelled. Aufnahme abgebrochen. - + Movie Saved - Movie gespeichert + Aufnahme gespeichert - + The movie is successfully saved. - Das Movie wurde erfolgreich gespeichert. + Die Aufnahme wurde erfolgreich gespeichert. - + Speed: %1% / %2% Geschwindigkeit: %1% / %2% - + Speed: %1% Geschwindigkeit: %1% - + Game: %1 FPS Spiel: %1 FPS - + Frame: %1 ms Einzelbild: %1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + %1 Fehlt. <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>Bitte dumpe deine Systemarchive</a>. <br/>Das Fortsetzen der Emulation könnte zu einem Absturz oder Bugs führen. - + System Archive Not Found Systemarchiv nicht gefunden - + Fatal Error Fataler Fehler - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Ein schwerwiegender Fehler ist aufgetreten. Weitere Details findest du in der <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Logdatei</a>.<br/>Das fortsetzten der Emulation könnte zu einem Absturz oder Bugs führen. - + Abort Abbrechen - - + + Citra Citra - + Would you like to exit now? - + Möchtest du die Anwendung jetzt verlassen? - + The game is still running. Would you like to stop emulation? - + Das Spiel läuft noch. Willst du die Emulation stoppen? - + Playback Completed - + Wiedergabe abgeschlossen - + Movie playback completed. - + Wiedergabe der Aufnahme abgeschlossen. - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2799,37 +3015,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + Name + + + + Compatibility + Kompatibilität + + + + Region + Region + + + + File type + Dateityp + + + + Size + Größe + + + Open Save Data Location Ort der Speicherdaten öffnen - + + Open Extra Data Location + + + + Open Application Location Ort der Applikationsdaten öffnen - + Open Update Data Location Ort der Updatedaten öffnen - + Navigate to GameDB entry Navigiere zum GameDB Eintrag - + Scan Subfolders Unterordner scannen - + Remove Game Directory Spieleverzeichnis entfernen - + Open Directory Location Verzeichnispfad öffnen @@ -2837,77 +3083,79 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect Perfekt - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - Das Spiel funktioniert fehlerfrei ohne Audio- oder Grafikfehler und sämtliche getestete Funktionalität funktioniert wie vorhergesehen ohne Workarounds. - - - - Great - - - - - Game functions with minor graphical or audio glitches and is playable from start to finish. May require some -workarounds. - - - - - Okay - - - - - Game functions with major graphical or audio glitches, but game is playable from start to finish with -workarounds. - + Das Spiel funktioniert fehlerfrei, ohne Audio- oder Grafikfehler, und sämtliche getestete Funktionalität funktioniert wie vorhergesehen ohne Workarounds. + Great + Super + + + + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some +workarounds. + Das Spiel funktioniert mit kleineren Audio- oder Grafikfehlern und lässt sich bis zum Ende durchspielen. +Eventuell sind einige Workarounds notwendig. + + + + Okay + Okay + + + + Game functions with major graphical or audio glitches, but game is playable from start to finish with +workarounds. + Das Spiel funktioniert mit größern Audio- oder Grafikfehlern, +lässt sich aber mit Workarounds bis zum Ende durchspielen. + + + Bad Schlecht - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - Das Spiel funktioniert, aber mit größeren Audio- oder Grafikfehlern. Fortschritt ist in manchen Gebieten durch Glitches unmöglich, sogar mit Workarounds. + Das Spiel funktioniert, aber mit größeren Audio- oder Grafikfehlern. Spielfortschritt ist aufgrund von Glitches zum Teil unmöglich, auch nicht mit Workarounds. - + Intro/Menu Intro/Menü - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - Das Spiel ist wegen schwerwiegenden Audio- oder Grafikfehlern komplett unspielbar. Kein Fortschritt nach dem Startbildschirm möglich. + Das Spiel ist wegen schwerwiegenden Audio- oder Grafikfehlern unspielbar. Das Spiel lässt sich lediglich starten. - + Won't Boot Startet nicht - + The game crashes when attempting to startup. - Das Spiel crasht beim Versuch es zu starten. + Das Spiel stürzt beim Versuch es zu starten ab. - + Not Tested Nicht getestet - + The game has not yet been tested. Das Spiel wurde noch nicht getestet. @@ -2915,7 +3163,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the game list Doppelklicken, um einen neuen Ordner zur Spieleliste hinzuzufügen @@ -2923,27 +3171,27 @@ Screen. GameListSearchField - + of von - + result - resultat + Ergebnis - + results Ergebnisse - + Filter: Filter: - + Enter pattern to filter Gib Wörter zum Filtern ein @@ -2951,23 +3199,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Pica-Haltepunkt - - + + Emulation running Emulation läuft - + Resume Fortsetzen - + Emulation halted at breakpoint Emulation angehalten am Haltepunkt @@ -3343,7 +3591,7 @@ Falls nein, werden die aufgenommmen Daten verworfen. Toggle LLE Service Modules - + LLE Servicemodule aktivieren / deaktivieren @@ -3385,42 +3633,42 @@ Falls nein, werden die aufgenommmen Daten verworfen. Lobby aktualisieren - + Password Required to Join Passwort zum Beitreten benötigt - + Password: Passwort: - + Room Name Raumname - + Preferred Game Bevorzugtes Spiel - + Host Host - + Players Spieler - + Refreshing Neu Laden - + Refresh List Liste aktualisieren @@ -3443,220 +3691,245 @@ Falls nein, werden die aufgenommmen Daten verworfen. Kürzliche Dateien - + + Amiibo + Amiibo + + + &Emulation &Emulation - + &View &Anzeige - + Debugging Debugging - + Screen Layout Bildschirmanordnung - + Movie - + Aufnahme - + Multiplayer Mehrspieler - + &Help &Hilfe - + Load File... Datei laden... - + Install CIA... CIA installieren... - + Load Symbol Map... Symbolkarte laden... - + E&xit V&erlassen - + &Start &Start - + &Pause &Pause - + &Stop &Stop - + FAQ FAQ - + About Citra Über Citra - + Single Window Mode Einzelfenstermodus - + Configure... Konfigurieren... - + Display Dock Widget Headers Dock Widget Header anzeigen - + Show Filter Bar Filterleiste anzeigen - + Show Status Bar Statusleiste anzeigen - + Select Game Directory... Spieleverzeichnis auswählen... - + Selects a folder to display in the game list Wählt einen Ordner aus, der in der Spieleliste angezeigt werden soll. - + Create Pica Surface Viewer Pica-Oberflächenansicht - + Record Movie - + Aufnahme starten - + Play Movie - + Aufnahme wiedergeben - + Stop Recording / Playback + Aufnahme anhalten + + + + Enable Frame Advancing - + + Advance Frame + + + + Browse Public Game Lobby Durchsuche Lobby für Öffentliche Spiele - + Create Room Raum erstellen - + Leave Room Raum verlassen - + Direct Connect to Room Direkt zum Raum Verbinden - + Show Current Room Zeige derzeitigen Raum an - + Fullscreen Vollbild - + Modify Citra Install Citra-Installation modifizieren - + Opens the maintenance tool to modify your Citra installation Öffnet das Wartungstool, um deine Citra-Installation zu modifizieren - + Default Standard - + Single Screen Einzelner Bildschirm - + Large Screen Großer Bildschirm - + Side by Side Seite an Seite - + Swap Screens Bildschirme tauschen - + Check for Updates Auf Updates prüfen - + Report Compatibility Kompatibilität melden - + Restart Neustart + + + Load... + Laden... + + + + Remove + + MicroProfileDialog @@ -3682,23 +3955,23 @@ Falls nein, werden die aufgenommmen Daten verworfen. - + Connected Verbunden - + Not Connected Nicht verbunden - + Error Fehler - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: Konnte den Raum nicht an der öffentlichen Lobby anmelden. Um einen Raum öffentlich zu betreiben muss ein gültiger Citra Account unter Emulation -> Konfiguration -> Web angegeben sein. Wenn der Raum nicht veröffentlicht werden soll, bitte "nicht-gelistet" auswählen. @@ -3817,108 +4090,108 @@ Debug Meldung: %1 spielt %2 - - + + Invalid region Ungültiges Gebiet - + Japan Japan - + North America Nord Amerika - + Europe Europa - + Australia Australien - + China China - + Korea Korea - + Taiwan Taiwan - + Region free Regionsfrei - + Invalid Region Ungültiges Gebiet - + Shift Umschalttaste - + Ctrl Strg - + Alt Alt - - + + [not set] [nicht gesetzt] - + Hat %1 %2 - + Hat %1 %2 - + Axis %1%2 - + Achse %1%2 - + Button %1 - + Taste %1 - - + + [unknown] [unbekannt] - + [unused] [ungenutzt] - - + + Axis %1 - + Achse %1 @@ -3946,7 +4219,7 @@ Debug Meldung: Text length is not correct (should be %1 characters) - Textlänge ist nicht korrekt (Soll %1 Buchstaben sein) + Textlänge ist nicht korrekt (Soll %1 Buchstabe(n) sein) diff --git a/dist/languages/es_ES.ts b/dist/languages/es_ES.ts index 074c66559..bcf2c6ea5 100644 --- a/dist/languages/es_ES.ts +++ b/dist/languages/es_ES.ts @@ -70,45 +70,50 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Comando de Pica cargado - + Pica command processed Comando de Pica procesado - + Incoming primitive batch Iniciando lote primitivo - + Finished primitive batch Lote primitivo terminado - + Vertex shader invocation Invocación del Sombreado de vértices - + Incoming display transfer Iniciando transferencia de pantalla - + GSP command processed Comando de GSP procesado - + Buffers swapped Buffers intercambiados + + + Unknown debug context event + Evento de depuración desconocido + CalibrationConfigurationDialog @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } Juego - - + + Block Player Bloquear jugador - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? Cuando bloquees a un jugador, ya no recibirás más mensajes de chat de éste.<br><br>¿Estás seguro de que quieres bloquear a %1? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected Conectado - + Disconnected Desconectado - + %1 (%2/%3 members) - connected %1 (%2/%3 miembros) - conectado @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! ¡Gracias por su colaboración! + + + Submitting + Enviando + + + + Communication error + Error de comunicación + + + + An error occured while sending the Testcase + Ha ocurrido un error mientras se enviaba la prueba. + + + + Next + Siguiente + ConfigureAudio @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + %1% @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration Configuración de Citra - + + + General General - + + + System Sistema - + + + Input Controles - + + + Graphics Gráficos - + + + Audio Audio - + + + Camera Cámara - + + + Debug Depuración - + + + Web Web + + + + + UI + UI + + + + Controls + Controles + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } Confirmar salida durante la emulación - - Interface language - Idioma de la interfaz - - - + Updates Actualizaciones - + Check for updates on start Buscar actualizaciones al iniciar - + Silently auto update after closing Actualizar automáticamente de forma silenciosa después de cerrar - + Emulation Emulación - + Region: Región: - + Auto-select Auto-elegir - - Theme - Tema - - - - Theme: - Tema: - - - + Hotkeys Teclas de atajo: - - <System> - <System> + + Reset All Settings + Reiniciar Toda la Configuración - - English - Inglés + + Citra + Citra + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + ¿Estás seguro de que quieres <b>restablecer tu configuración</b> y cerrar Citra? @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick Configurar Palanca Analógica @@ -1067,11 +1110,44 @@ p, li { white-space: pre-wrap; } + Clear All + Reiniciar todo + + + Restore Defaults Restablecer - + + + Clear + Reiniciar + + + + + [not set] + [no establecido] + + + + + Restore Default + Restablecer + + + + Information + Información + + + + After pressing OK, first move your joystick horizontally, and then vertically. + Después de pulsar Aceptar, mueve tu joystick horizontalmente, y luego verticalmente. + + + [press key] [pulsa un botón] @@ -1440,17 +1516,27 @@ p, li { white-space: pre-wrap; } Tiempo del Inicio - + + yyyy-MM-ddTHH:mm:ss + aaaa-mm-ddTHH:mm:ss + + + + Play Coins: + Monedas de Juego: + + + Console ID: ID de Consola: - + Regenerate Regenerar - + System settings are available only when game is not running. La Configuración de la Consola sólo está disponible cuando no se está emulando ningún juego. @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } Bermudas - - + + Console ID: 0x%1 ID de Consola: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? - Esto reemplazará tu 3DS virtual con una nueva. Tu 3DS virtual actual será irrecuperable. Esto puede tener efectos inesperados en ciertos juegos. Si usas un archivo de configuración anticuado, esto puede fallar. ¿Desea continuar? + Esto reemplazará tu 3DS virtual por una nueva. Tu 3DS virtual actual será irrecuperable. Esto puede tener efectos inesperados en determinados juegos. Si usas un archivo de configuración obsoleto, esto podría fallar. ¿Desea continuar? - + Warning Advertencia + + ConfigureUi + + + Form + Formulario + + + + General + General + + + + Interface language: + Idioma de la Interfaz + + + + Theme: + Tema: + + + + Game List + Lista de Juegos + + + + Icon Size: + Tamaño de Icono: + + + + + None + Ninguno + + + + Small (24x24) + Pequeño (24x24) + + + + Large (48x48) + Grande (48x48) + + + + Row 1 Text: + Texto de Fila 1: + + + + + File Name + Nombre de Archivo + + + + + Full Path + Ruta Completa + + + + + Title Name + Nombre del Título + + + + + Title ID + ID del Título + + + + Row 2 Text: + Texto de Fila 2: + + + + Hide Titles without Icon + Ocultar Títulos sin Icono + + + + <System> + <System> + + + + English + Inglés (English) + + ConfigureWeb @@ -2155,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify Verificar @@ -2215,48 +2399,48 @@ p, li { white-space: pre-wrap; } Mostrar Juego Actual en el Estado de Discord - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Más información</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Regístrate</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Regístrate</span></a> - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">¿Cuál es mi token?</span></a> - - + + Telemetry ID: 0x%1 ID de Telemetría: 0x%1 - + Username and token not verified Nombre de usuario y token no verificados - + Username and token were not verified. The changes to your username and/or token have not been saved. El nombre de usuario y el token no han sido verificados. Los cambios de tu nombre de usuario y/o del token no han sido guardados. - + Verifying Verificando - + Verification failed La verificación falló - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. La verificación falló. Comprueba que has introducido tu nombre de usuario y tu token correctamente, y que tu conexión internet funcione correctamente. @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting Conectando - + Connect Conectar @@ -2330,413 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Se recogen datos anónimos</a> para ayudar a mejorar Citra. <br/><br/>¿Quieres compartir tus datos de uso con nosotros? - + Telemetry Telemetría - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. La velocidad de emulación actual. Valores mayores o menores de 100% indican que la velocidad de emulación funciona más rápida o lentamente que en una 3DS. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Los fotogramas por segundo que está mostrando el juego. Variarán de juego en juego y de escena a escena. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. El tiempo que lleva emular un fotograma de 3DS, sin tener en cuenta el limitador de fotogramas, ni la sincronización vertical. Para una emulación óptima, este valor no debe superar los 16.67 ms. - + Clear Recent Files Limpiar Archivos Recientes - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available Actualización Disponible - + An update is available. Would you like to install it now? Hay una actualización disponible. ¿Quieres instalarla ahora? - + No Update Found Actualización No Encontrada - + No update is found. No se han encontrado actualizaciones. - - + + OpenGL 3.3 Unsupported + Tu gráfica no soporta OpenGL 3.3 + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + Tu tarjeta gráfica no soporta OpenGL 3.3, o no tienes los últimos controladores gráficos para tu tarjeta. + + + + Invalid ROM Format Formato de ROM no válido - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Tu formato de ROM no es válido.<br/>Por favor, sigue las instrucciones para volver a volcar tus <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>cartuchos de juego</a> y/o <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>títulos instalados</a>. - + ROM Corrupted ROM Corrupto - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Tu ROM está corrupto. <br/>Por favor, sigue las instrucciones para volver a volcar tus<a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>cartuchos de juego</a> y/o <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>títulos instalados</a>. - + ROM Encrypted ROM Encriptado - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Tu ROM está encriptado. <br/>Por favor, sigue las instrucciones para volver a volcar tus<a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>cartuchos de juego</a> y/o <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>títulos instalados</a>. - - + + Video Core Error Error en el Núcleo de Vídeo - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. Ha ocurrido un error. Por favor,<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>mira el log</a> para más detalles. Asegúrese de tener los últimos drivers de tu tarjeta gráfica instalados. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. Estás usando los controladores por defecto de Windows para tu GPU. Necesitas instalar los controladores de tu tarjeta gráfica de la página del fabricante. - + Error while loading ROM! ¡Error al cargar la ROM! - + An unknown error occured. Please see the log for more details. Un error desconocido ha ocurrido. Por favor, mira el log para más detalles. - + Start Iniciar - + Error Opening %1 Folder Error al abrir la carpeta %1 - - + + Folder does not exist! ¡La carpeta no existe! - + Error Opening %1 Error al abrir %1 - + Select Directory Seleccionar directorio - - 3DS Executable - Ejecutable de 3DS + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + Ejecutable 3DS(%1);;Todos los archivos(*.*) - - - All Files (*.*) - Todos los archivos (*.*) - - - + Load File Cargar Archivo - + Load Files Cargar archivos - + 3DS Installation File (*.CIA*) Archivo de Instalación de 3DS (*.CIA*) - + + All Files (*.*) + Todos los archivos (*.*) + + + %1 has been installed successfully. %1 ha sido instalado con éxito. - + Unable to open File No se pudo abrir el Archivo - + Could not open %1 No se pudo abrir %1 - + Installation aborted Instalación interrumpida - + The installation of %1 was aborted. Please see the log for more details La instalación de %1 ha sido cancelada. Por favor, consulte los registros para más información. - + Invalid File Archivo no válido - + %1 is not a valid CIA %1 no es un archivo CIA válido - + Encrypted File Archivo Encriptado - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 debe ser desencriptado antes de ser usado en Citra. Se requiere de una 3DS real. - + File not found Archivo no encontrado - + File "%1" not found Archivo "%1" no encontrado - - - + + + Continue Continuar - + Missing Citra Account Falta la cuenta de Citra - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. Debes vincular tu cuenta de Citra para enviar casos de pruebas.<br/>Ve a Emulación &gt; Configurar... &gt; Web para hacerlo. - - - + + Amiibo File (%1);; All Files (*.*) + Archivo de Amiibo(%1);; Todos los archivos (*.*) + + + + Load Amiibo + Cargar Amiibo + + + + + + Record Movie Grabar Película - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + Para mantener la consistencia con el RNG, se recomienda grabar la película desde el inicio del juego.<br>¿Estás seguro de que quieres grabar una película ahora? + + + + Citra TAS Movie (*.ctm) Citra TAS Movie (*.ctm) - + Recording will start once you boot a game. La grabación comenzará una vez que inicies un juego. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? La película que estás intentando cargar se creó en una revisión distinta de Citra.<br/>Citra ha tenido cambios durante ese tiempo, y la reproducción puede desincronizarse o no funcionar de la forma esperada.<br/><br/>¿Quiere seguir cargando el archivo de la película? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? La película que está intentando cargar fue grabada con otro juego.<br/>La reproducción puede no funcionar bien, y puede derivar en resultados inesperados.<br/><br/>¿Quiere seguir reproduciendo la película? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. La película que estás intentando cargar no es válida.<br/>O el archivo está corrupto, o Citra ha hecho muchos cambios al módulo Película.<br/> Por favor, elija una película distinta e inténtalo de nuevo. - + Revision Dismatch No coincide la revisión - + Game Dismatch No coincide el juego - - + + Invalid Movie File Película No Válida - + + Play Movie Reproducir Película - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + Para mantener la constancia con el RNG, se recomienda reproducir la película desde el inicio del juego.<br>¿Estás seguro de que quieres reproducir una película ahora? + + + Game Not Found Juego No Encontrado - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. La película que intenta reproducir es de un juego que no está en su lista de juegos. Si tienes el juego, por favor, añade el juego a su lista de juegos e intente reproducir la película de nuevo. - + Movie recording cancelled. Grabación de película cancelada. - + Movie Saved Película Guardada - + The movie is successfully saved. Película guardada con éxito. - + Speed: %1% / %2% Velocidad: %1% / %2% - + Speed: %1% Velocidad: %1% - + Game: %1 FPS Juego: %1 FPS - + Frame: %1 ms Frame: %1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. Falta %1. Por favor, <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>vuelca tus archivos de sistema</a>.<br/>Continuar la emulación puede resultar en cuelgues y errores. - + System Archive Not Found Archivo de Sistema no encontrado - + Fatal Error Error Fatal - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. Ha ocurrido un error fatal. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Mira el log</a> para más detalles.<br/>Continuar la emulación puede resultar en cuelgues y errores. - + Abort Abortar - - + + Citra Citra - + Would you like to exit now? ¿Quiere salir ahora? - + The game is still running. Would you like to stop emulation? El juego sigue ejecutándose. ¿Quiere parar la emulación? - + Playback Completed Reproducción Completada - + Movie playback completed. Reproducción de película completada. - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2799,37 +3015,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + Nombre + + + + Compatibility + Compatibilidad + + + + Region + Región + + + + File type + Tipo de Archivo + + + + Size + Tamaño + + + Open Save Data Location Abrir ubicación de los archivos de guardado - + + Open Extra Data Location + Abrir ubicación de los Datos Adicionales + + + Open Application Location Abrir ubicación de la aplicación - + Open Update Data Location Abrir ubicación de los archivos de actualización - + Navigate to GameDB entry Ir a la base de datos de los juegos - + Scan Subfolders Escanear subdirectorios - + Remove Game Directory Eliminar directorio de juegos - + Open Directory Location Abrir ubicación del directorio @@ -2837,82 +3083,82 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect Perfecto - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. El juego funciona a la perfección, sin problemas de sonido o gráficos, todas las funcionalidades probadas funcionan según lo previsto sin la necesidad de soluciones temporales. - + Great Excelente - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. El juego funciona con pequeños problemas gráficos o de sonido y es jugable de principio a fin. Podría requerir de soluciones temporales. - + Okay Bien - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. El juego funciona con importantes problemas gráficos o de sonido, pero el juego es jugable de principio a fin con soluciones temporales. - + Bad Mal - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. El juego funciona, pero con notables problemas gráficos o de sonido. Es imposible avanzar en zonas específicas debido a fallos incluso con soluciones temporales. - + Intro/Menu Intro/Menú - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. No es posible jugar al juego debido a importantes problemas gráficos o de sonido. Es imposible avanzar más allá de la pantalla de inicio. - + Won't Boot No inicia - + The game crashes when attempting to startup. El juego se bloquea al intentar iniciarse. - + Not Tested Sin probar - + The game has not yet been tested. El juego todavía no ha sido testeado. @@ -2920,7 +3166,7 @@ más allá de la pantalla de inicio. GameListPlaceholder - + Double-click to add a new folder to the game list Haz doble click para añadir una nueva carpeta a la lista de juegos @@ -2928,27 +3174,27 @@ más allá de la pantalla de inicio. GameListSearchField - + of de - + result resultado - + results resultados - + Filter: Filtro: - + Enter pattern to filter Introduzca un patrón para filtrar @@ -2956,23 +3202,23 @@ más allá de la pantalla de inicio. GraphicsBreakPointsWidget - + Pica Breakpoints Pica Breakpoints - - + + Emulation running Ejecutando emulación - + Resume Reanudar - + Emulation halted at breakpoint Emulación parada en un breakpoint @@ -3389,42 +3635,42 @@ más allá de la pantalla de inicio. Actualizar Lobby - + Password Required to Join Contraseña Necesaria para Unirse - + Password: Contraseña: - + Room Name Nombre de Sala - + Preferred Game Juego Preferente - + Host Host - + Players Jugadores - + Refreshing Actualizando - + Refresh List Actualizar Lista @@ -3447,220 +3693,245 @@ más allá de la pantalla de inicio. Archivos Recientes - + + Amiibo + Amiibo + + + &Emulation &Emulación - + &View &Ver - + Debugging Depuración - + Screen Layout Estilo de pantalla - + Movie Película - + Multiplayer Multijugador - + &Help &Ayuda - + Load File... Cargar Archivo... - + Install CIA... Instalar CIA... - + Load Symbol Map... Cargar Mapa de Símbolos... - + E&xit S&alir - + &Start &Iniciar - + &Pause &Pausar - + &Stop &Parar - + FAQ FAQ - + About Citra Acerca de Citra - + Single Window Mode Modo Ventana Única - + Configure... Configurar... - + Display Dock Widget Headers Mostrar Títulos de Widgets del Dock - + Show Filter Bar Mostrar Barra de Filtro - + Show Status Bar Mostrar Barra de Estado - + Select Game Directory... Seleccionar Directorio de Juego... - + Selects a folder to display in the game list Selecciona una carpeta para mostrar en la lista de juegos - + Create Pica Surface Viewer Crear Observador de Superficie de Pica - + Record Movie Grabar Película - + Play Movie Reproducir Película - + Stop Recording / Playback Dejar de Grabar / Reproducir - + + Enable Frame Advancing + Activar Avance de Fotogramas + + + + Advance Frame + Avanzar Fotograma + + + Browse Public Game Lobby Buscar Salas Públicas - + Create Room Crear Sala - + Leave Room Abandonar Sala - + Direct Connect to Room Conectar Directamente a Sala - + Show Current Room Mostrar Sala Actual - + Fullscreen Pantalla Completa - + Modify Citra Install Modificar Instalación de Citra - + Opens the maintenance tool to modify your Citra installation Abre la herramienta de mantenimiento para modificar tu traducción de Citra - + Default Por defecto - + Single Screen Pantalla única - + Large Screen Pantalla amplia - + Side by Side Conjunta - + Swap Screens Intercambiar pantallas - + Check for Updates Buscar Actualizaciones - + Report Compatibility Informar de compatibilidad - + Restart Reiniciar + + + Load... + Cargar... + + + + Remove + Quitar + MicroProfileDialog @@ -3686,23 +3957,23 @@ más allá de la pantalla de inicio. - + Connected Conectado - + Not Connected No conectado - + Error Error - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: No se ha podido anunciar la sala en el lobby público. Para ser el anfitrión de una sala pública, debes tener una cuenta de Citra válida configurada en Emulación -> Configurar -> Web. Si no deseas publicar una sala en el lobby público, entonces seleccione Privada. @@ -3821,106 +4092,106 @@ Mensaje de Depuración: %1 está jugando a %2 - - + + Invalid region Región no válida - + Japan Japón - + North America Norteamérica - + Europe Europa - + Australia Australia - + China China - + Korea Corea - + Taiwan Taiwán - + Region free Region free - + Invalid Region Región no válida - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [no establecido] - + Hat %1 %2 Rotación %1 %2 - + Axis %1%2 Axis %1%2 - + Button %1 Botón %1 - - + + [unknown] [desconocido] - + [unused] [sin usar] - - + + Axis %1 Axis %1 diff --git a/dist/languages/fr.ts b/dist/languages/fr.ts index d902a6b93..ee478d782 100644 --- a/dist/languages/fr.ts +++ b/dist/languages/fr.ts @@ -70,45 +70,50 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Pica command loaded - + Pica command processed Pica command processed - + Incoming primitive batch Incoming primitive batch - + Finished primitive batch Finished primitive batch - + Vertex shader invocation Vertex shader invocation - + Incoming display transfer Incoming display transfer - + GSP command processed GSP command processed - + Buffers swapped Buffers swapped + + + Unknown debug context event + Événement contextuel de débogage inconnu + CalibrationConfigurationDialog @@ -130,12 +135,12 @@ p, li { white-space: pre-wrap; } Now touch the bottom right corner <br>of your touchpad. - Maintenant touchez le coin inférieur droite <br> de votre pavé tactile. + Maintenant touchez le coin inférieur droit <br> de votre pavé tactile. Configuration completed! - Configuration terminée! + Configuration terminée ! @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } Jeu - - + + Block Player Bloquer un joueur - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? Lorsque vous bloquez un joueur, vous ne recevrez plus de message de sa part.<br><br>Êtes-vous sûr de vouloir bloquer %1? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected Connecté - + Disconnected Déconnecté - + %1 (%2/%3 members) - connected %1 (%2/%3 membres) - connecté @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! Merci pour votre contribution! + + + Submitting + Transmission + + + + Communication error + Erreur de communication + + + + An error occured while sending the Testcase + Une erreur s'est produite pendant l'envoi du cas test. + + + + Next + Suivant + ConfigureAudio @@ -312,7 +337,7 @@ p, li { white-space: pre-wrap; } Output Engine: - Moteur de sortie: + Moteur de sortie : @@ -327,12 +352,12 @@ p, li { white-space: pre-wrap; } Audio Device: - Périphérique Audio: + Périphérique Audio : Volume: - Volume: + Volume : @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + %1% @@ -367,7 +392,7 @@ p, li { white-space: pre-wrap; } Camera to configure: - Caméra à configurer: + Caméra à configurer : @@ -388,7 +413,7 @@ p, li { white-space: pre-wrap; } Camera mode: - Mode de la caméra: + Mode de la caméra : @@ -409,7 +434,7 @@ p, li { white-space: pre-wrap; } Camera position: - Position de la caméra: + Position de la caméra : @@ -455,7 +480,7 @@ p, li { white-space: pre-wrap; } File: - Fichier: + Fichier : @@ -471,7 +496,7 @@ p, li { white-space: pre-wrap; } Camera: - Caméra: + Caméra : @@ -487,7 +512,7 @@ p, li { white-space: pre-wrap; } Flip: - Basculement: + Basculement : @@ -527,7 +552,7 @@ p, li { white-space: pre-wrap; } Resolution: 512*384 - Définition: 512*384 + Résolution : 512*384 @@ -537,7 +562,7 @@ p, li { white-space: pre-wrap; } Resolution: - Définition: + Définition : @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration Configuration de Citra - + + + General Général - + + + System Système - + + + Input Contrôles - + + + Graphics Graphiques - + + + Audio Son - + + + Camera - Caméra: + Caméra : - + + + Debug Débug - + + + Web Web + + + + + UI + Interface + + + + Controls + Contrôles + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } Confirmer la fermeture du programme pendant l'exécution de l'émulation - - Interface language - Langage de l'interface - - - + Updates Mises à Jour - + Check for updates on start Vérifier les mises à jour au démarrage - + Silently auto update after closing Mise à jour automatique après la fermeture - + Emulation Émulation - + Region: - Région: + Région : - + Auto-select Sélection Automatique - - Theme - Thème - - - - Theme: - Thème: - - - + Hotkeys Raccourcis - - <System> - <System> + + Reset All Settings + Réinitialiser tous les paramètres - - English - Anglais + + Citra + Citra + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + Êtes-vous sûr de vouloir <b> réinitialiser vos paramètres </b> et fermer Citra? @@ -915,7 +958,7 @@ p, li { white-space: pre-wrap; } Background Color: - Couleur d'arrière-plan: + Couleur d'arrière-plan : @@ -943,22 +986,22 @@ p, li { white-space: pre-wrap; } A: - A + A : B: - B + B : X: - X + X : Y: - Y + Y : @@ -970,28 +1013,28 @@ p, li { white-space: pre-wrap; } Up: - Haut + Haut : Down: - Bas: + Bas : Left: - Gauche + Gauche : Right: - Droit + Droite : @@ -1001,22 +1044,22 @@ p, li { white-space: pre-wrap; } L: - L + L : R: - R + R : ZL: - ZL + ZL : ZR: - ZR + ZR : @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick Configurer le stick analogique @@ -1058,7 +1101,7 @@ p, li { white-space: pre-wrap; } Circle Mod: - Circle Mod: + Circle Mod : @@ -1067,11 +1110,44 @@ p, li { white-space: pre-wrap; } + Clear All + Tout effacer + + + Restore Defaults Restaurer les paramètres par défaut - + + + Clear + Effacer + + + + + [not set] + [non définie] + + + + + Restore Default + Réinitialiser + + + + Information + Information + + + + After pressing OK, first move your joystick horizontally, and then vertically. + Après avoir appuyé sur OK, déplacez votre joystick horizontalement, puis verticalement. + + + [press key] [appuyer sur une touche] @@ -1096,7 +1172,7 @@ p, li { white-space: pre-wrap; } Sensitivity: - Sensibilité: + Sensibilité : @@ -1106,12 +1182,12 @@ p, li { white-space: pre-wrap; } Touch Provider: - Gestion du tactile: + Gestion du tactile : Calibration: - Calibration: + Calibration : @@ -1440,17 +1516,27 @@ p, li { white-space: pre-wrap; } Heure au démarrage - + + yyyy-MM-ddTHH:mm:ss + aaaa-MM-jjTHH:mm:ss + + + + Play Coins: + Pièces de jeu: + + + Console ID: Console ID: - + Regenerate Regénérer - + System settings are available only when game is not running. Les paramètres systèmes ne sont disponibles que lorsque l'émulation n'est pas en cours. @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } Bermudes - - + + Console ID: 0x%1 Console ID: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? Ceci va remplacer votre 3DS virtuelle actuelle avec une nouvelle. Votre 3DS virtuelle actuelle ne sera plus récupérable. Cela pourrait avoir des effets inattendus pour certains jeux. Cela pourrait échouer, si vous utilisez une ancienne sauvegarde de jeu. Continuer? - + Warning Avertissement + + ConfigureUi + + + Form + Formulaire + + + + General + Générale + + + + Interface language: + Langue de l'interface: + + + + Theme: + Thème: + + + + Game List + Liste de jeux + + + + Icon Size: + Talle de l'icône: + + + + + None + Aucun + + + + Small (24x24) + Petite (24x24) + + + + Large (48x48) + Grande (48x48) + + + + Row 1 Text: + Texte de la ligne 1: + + + + + File Name + Nom du fichier + + + + + Full Path + Chemin complet + + + + + Title Name + Nom du titre + + + + + Title ID + ID du titre + + + + Row 2 Text: + Texte de la ligne 2: + + + + Hide Titles without Icon + Masquer les titres sans icône + + + + <System> + <System> + + + + English + Anglais + + ConfigureWeb @@ -2155,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify Vérifier @@ -2215,48 +2399,48 @@ p, li { white-space: pre-wrap; } Afficher votre jeu en cours dans votre statut Discord - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">En savoir plus</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">S'inscrire</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">S'inscrire</span></a> - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">Quel est mon jeton?</span></a> - - + + Telemetry ID: 0x%1 ID de télémétrie: 0x%1 - + Username and token not verified Nom d'utilisateur et token non vérifiés - + Username and token were not verified. The changes to your username and/or token have not been saved. Le nom d'utilisateur et le token n'ont pas été vérifiés. Les modifications apportées à votre nom d'utilisateur et / ou token n'ont pas été enregistrées. - + Verifying Vérification en cours - + Verification failed Échec de la vérification - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. Échec de la vérification. Vérifiez que vous avez correctement entré votre nom d'utilisateur et votre token, et que votre connexion Internet fonctionne. @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting Connexion en cours - + Connect Connecter @@ -2330,413 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Des données anonymes sont collectées</a> afin d'aider à l'amélioration de Citra. <br/><br/>Voulez-vous nous communiquer vos données? - + Telemetry Télémétrie - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Vitesse actuelle d'émulation. Les valeurs supérieures ou inférieures à 100% indiquent que l'émulation est plus rapide ou plus lente qu'une 3DS. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Nombre d'images par seconde le jeu affiche actuellement. Cela varie d'un jeu à l'autre et d'une scène à l'autre. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Temps nécessaire pour émuler une trame 3DS, sans compter la limitation de trame ou la synchronisation verticale V-Sync. Pour une émulation à pleine vitesse, cela ne devrait pas dépasser 16,67 ms. - + Clear Recent Files Effacer les fichiers récents - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available Mise à jour disponible - + An update is available. Would you like to install it now? Une mise à jour est disponible. Voulez-vous l'installer maintenant? - + No Update Found Aucune mise à jour trouvée - + No update is found. Aucune mise à jour n'a été trouvée. - - + + OpenGL 3.3 Unsupported + OpenGL 3.3 n'est pas supporté + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + Votre carte graphique ne supporte pas OpenGL 3.3, ou vous n'avez pas le dernier pilote disponible. + + + + Invalid ROM Format Format de ROM non valide - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Le format de votre ROM n'est pas supporté.<br/>Veuillez suivre les guides afin de dumper (copier) vos <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>cartouches de jeu</a> ou <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>les titres installés</a> - + ROM Corrupted ROM corrompue - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Votre ROM est corrompue. <br/>Veuilez suivre les guides afin de dumper vos<a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>cartouches de jeu</a> ou <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>les titres installés</a>. - + ROM Encrypted ROM chiffrée - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Votre ROM est chiffrée. <br/>Veuillez suivre les guides afin de redumper vos <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>cartouches de jeu</a> ou <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>titres installés</a>. - - + + Video Core Error Erreur du moteur graphique - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. Une erreur s'est produite. Veuillez <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>consulter les journaux</a>pour plus de détails. Faîtes en sorte d'avoir les derniers pilotes graphiques pour votre carte. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. Votre carte graphique utilise les pilotes Windows par défaut. Vous devez installer les pilotes adaptés à votre carte à partir du site du fabricant. - + Error while loading ROM! Erreur lors du chargement de la ROM! - + An unknown error occured. Please see the log for more details. Une erreur inconnue est survenue. Veuillez consulter le journal pour plus de détails. - + Start Démarrer - + Error Opening %1 Folder Erreur lors de l'ouverture du dossier %1 - - + + Folder does not exist! Le répertoire n'existe pas! - + Error Opening %1 Erreur lors de l'ouverture de %1 - + Select Directory Sélectionner un répertoire - - 3DS Executable - Fichier exécutable 3DS + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + Exécutable 3DS (%1);;Tous les fichiers (*.*) - - - All Files (*.*) - Tous les fichiers (*.*) - - - + Load File Charger un fichier - + Load Files Charger les fichiers - + 3DS Installation File (*.CIA*) Fichier d'installation 3DS (*.CIA*) - + + All Files (*.*) + Tous les fichiers (*.*) + + + %1 has been installed successfully. %1 a été installé avec succès. - + Unable to open File Impossible d'ouvrir le fichier - + Could not open %1 Impossible d'ouvrir %1 - + Installation aborted Installation annulée - + The installation of %1 was aborted. Please see the log for more details L'installation de %1 a été interrompue. Veuillez consulter le fichier log pour plus de détails. - + Invalid File Fichier invalide - + %1 is not a valid CIA %1 n'est pas un CIA valide - + Encrypted File Fichier encrypté - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 doit être décrypté avant de fonctionner avec Citra. Une véritable 3DS est requise. - + File not found Fichier non trouvé - + File "%1" not found Le fichier "%1" n'a pas été trouvé - - - + + + Continue Continuer - + Missing Citra Account Compte Citra absent - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. Vous devez rattacher votre compte Citra pour soumettre des cas test.<br/>Allez sur Emulation &gt; Configurer... &gt; Web pour procéder. - - - + + Amiibo File (%1);; All Files (*.*) + Fichier Amiibo (%1);; Tous les fichiers (*.*) + + + + Load Amiibo + Charger un Amiibo + + + + + + Record Movie Enregistrer une vidéo - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + Pour être cohérent avec le RNG, nous recommandons d'enregistrer votre fichier vidéo depuis le début du jeu<br>Etes-vous sûr de vouloir enregistrer la vidéo maintenant? + + + + Citra TAS Movie (*.ctm) Citra TAS Movie (*.ctm) - + Recording will start once you boot a game. L'enregistrement démarrera au lancement d'un jeu. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? Le fichier vidéo que vous essayez de charger a été crée sur une version différente de Citra.<br/>Citra a été modifié entre-temps, et la lecture peut être désynchronisée ou ne pas fonctionner comme prévu.<br/><br/>Etes-vous sûr de vouloir lancer le fichier vidéo? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? Le fichier vidéo que vous essayez de charger a été enregistré avec un jeu différent.<br/>La lecture peut ne pas fonctionner comme prévu, et provoquer des résultats inattendus.<br/><br/>Etes-vous sûr de vouloir lancer le fichier vidéo? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. Le fichier vidéo que vous essayez de charger n'est pas valide.<br/>Le fichier est corrompu, ou le module Vidéo de Citra a connu de profonds changements.<br/>Veuillez choisir un fichier vidéo différent puis réessayez. - + Revision Dismatch Incohérence de la version - + Game Dismatch Incohérence du jeu - - + + Invalid Movie File Fichier Vidéo invalide - + + Play Movie Jouer une vidéo - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + Pour être cohérent avec le RNG, nous recommandons de lire votre fichier vidéo depuis le début du jeu.<br>Etes-vous sûr de vouloir lire la vidéo maintenant? + + + Game Not Found Jeu non trouvé - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. La vidéo que vous essayez de lire vient d'un jeu absent de la liste de jeux. Si vous possédez le jeu, veuillez ajouter le dossier du jeu à la liste de jeux et réessayez la lecture. - + Movie recording cancelled. Enregistrement de la vidéo annulé. - + Movie Saved Vidéo enregistrée - + The movie is successfully saved. La vidéo a été enregistrée avec succès. - + Speed: %1% / %2% Vitesse: %1% / %2% - + Speed: %1% Vitesse: %1% - + Game: %1 FPS Jeux: %1 FPS - + Frame: %1 ms Trame: %1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. %1 est manquant. Merci de <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dumper vos archives système</a>.<br/>Continuer l'émulation peut entrainer des plantages et des bugs. - + System Archive Not Found Archive système non trouvé - + Fatal Error Erreur fatale - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. Une erreur fatale s'est produite. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Consultez les journaux</a>pour plus de détails.<br/>Continuer l'émulation peut entrainer des plantages et des bugs. - + Abort Abandonner - - + + Citra Citra - + Would you like to exit now? Voulez-vous quitter maintenant? - + The game is still running. Would you like to stop emulation? Le jeu est en cours de fonctionnement. Voulez-vous arrêter l'émulation? - + Playback Completed Lecture terminée - + Movie playback completed. Lecture de la vidéo terminée. - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2799,37 +3015,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + Nom + + + + Compatibility + Compatibilité + + + + Region + Région + + + + File type + Type de fichier + + + + Size + Taille + + + Open Save Data Location Ouvrir l'emplacement des données de sauvegarde - + + Open Extra Data Location + Ouvrir un emplacement de données supplémentaire + + + Open Application Location Ouvrir l'emplacement de l'application - + Open Update Data Location Ouvrir l'emplacement des données de mise à jour - + Navigate to GameDB entry Naviguer jusqu'à l'entrée de la GameDB - + Scan Subfolders Scanner les sous-dossiers - + Remove Game Directory Supprimer ce répertoire de jeu - + Open Directory Location Ouvrir l'emplacement de ce répertoire @@ -2837,77 +3083,77 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect Parfait - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. Le jeu fonctionne parfaitement sans bug audio ni graphique, toutes les fonctionnalités testées marchent comme prévu sans besoin de correctif. - + Great Bien - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. Le jeu fonctionne avec des bugs audio ou graphiques mineurs et est jouable du début à la fin. Peut nécessiter certains ajustements. - + Okay Ok - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. Le jeu fonctionne avec des bugs audio ou graphiques majeurs, mais il est jouable du début à la fin avec des ajustements. - + Bad Mauvais - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. Le jeu fonctionne, mais avec des bugs audio ou graphiques majeurs. Impossible de se rendre dans certaines zones à cause des bugs même avec des ajustements. - + Intro/Menu Intro/Menu - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. Le jeu est totalement injouable à cause de bugs graphiques ou audio majeurs. Impossible de dépasser l'écran titre. - + Won't Boot Ne se lance pas - + The game crashes when attempting to startup. Le jeu plante au démarrage. - + Not Tested Non testé - + The game has not yet been tested. Le jeu n'a pas encore été testé. @@ -2915,7 +3161,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the game list Faites un double-clic pour ajouter un nouveau dossier à la liste de jeux @@ -2923,27 +3169,27 @@ Screen. GameListSearchField - + of sur - + result résultat - + results résultats - + Filter: Filtre: - + Enter pattern to filter Entrer le motif de filtrage @@ -2951,23 +3197,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Points d'arrêt PICA - - + + Emulation running Émulation en cours - + Resume Reprendre - + Emulation halted at breakpoint L'émulation s'est arrêtée au point d'arrêt @@ -3384,42 +3630,42 @@ Screen. Rafraîchir le hall - + Password Required to Join Mot de passe nécessaire pour devenir membre - + Password: Mot de passe: - + Room Name Nom du salon - + Preferred Game Jeu préféré - + Host Hôte - + Players Joueurs - + Refreshing Rafraîchissement - + Refresh List Rafraîchir la liste @@ -3442,220 +3688,245 @@ Screen. Fichiers récents - + + Amiibo + Amiibo + + + &Emulation &Émulation - + &View &Voir - + Debugging Débogguer - + Screen Layout Disposition de l'écran - + Movie Vidéo - + Multiplayer Multijoueurs - + &Help &Aide - + Load File... Charger un fichier... - + Install CIA... Installer un fichier CIA... - + Load Symbol Map... Charger Configuration des Boutons... - + E&xit A&rrêter - + &Start &Commencer - + &Pause &Pause - + &Stop &Stop - + FAQ FAQ - + About Citra À propos - + Single Window Mode Mode fenêtre unique - + Configure... Configurer... - + Display Dock Widget Headers Display Dock Widget Headers - + Show Filter Bar Montrer la barre des Filtres - + Show Status Bar Montrer la barre de Statut - + Select Game Directory... Sélectionnez un dossier... - + Selects a folder to display in the game list Sélectionnez un dossier pour apparaître dans la liste - + Create Pica Surface Viewer Créer une surface Pica - + Record Movie Enregistrer une vidéo - + Play Movie Jouer une vidéo - + Stop Recording / Playback Arrêter l'enregistrement / la lecture - + + Enable Frame Advancing + Activer l'avancement de trame + + + + Advance Frame + Avancer la trame + + + Browse Public Game Lobby Naviguer dans le hall de jeux publics - + Create Room Créer un salon - + Leave Room Quitter le salon - + Direct Connect to Room Connexion directe à un salon - + Show Current Room Afficher le salon actuel - + Fullscreen Plein écran - + Modify Citra Install Modifier l'installation de Citra - + Opens the maintenance tool to modify your Citra installation Lancez l'outil de maintenance pour modifier l'installation de Citra - + Default Par défaut - + Single Screen Un seul écran - + Large Screen Écran large - + Side by Side Côte à côte - + Swap Screens Permuter les écrans - + Check for Updates Rechercher les mises à jour - + Report Compatibility Faire un rapport de compatibilité - + Restart Redémarrer + + + Load... + Charger... + + + + Remove + Supprimer + MicroProfileDialog @@ -3681,23 +3952,23 @@ Screen. - + Connected Connecté - + Not Connected Non connecté - + Error Erreur - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: L'introduction du salon dans le hall public a échoué. Pour héberger un salon public, vous devez configurer un compte Citra valide dans Emulation -> Configurer... -> Web. Si vous ne souhaitez pas publier un salon dans le hall public, choisissez Non Listé à la place. @@ -3816,106 +4087,106 @@ Message de debug: %1 joue à %2 - - + + Invalid region Région Invalide - + Japan Japon - + North America Amérique du Nord - + Europe Europe - + Australia Australie - + China Chine - + Korea Corée - + Taiwan Taiwan - + Region free Dézoné - + Invalid Region Région Invalide - + Shift Maj - + Ctrl Ctrl - + Alt Alt - - + + [not set] [non défini] - + Hat %1 %2 - + Hat %1 %2 - + Axis %1%2 Axe %1%2 - + Button %1 Bouton %1 - - + + [unknown] [inconnu] - + [unused] [inutilisé] - - + + Axis %1 Axe %1 diff --git a/dist/languages/hu_HU.ts b/dist/languages/hu_HU.ts index 072e6d768..3b2153aba 100644 --- a/dist/languages/hu_HU.ts +++ b/dist/languages/hu_HU.ts @@ -70,45 +70,50 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Pica parancs betöltve - + Pica command processed Pica parancs feldolgozva - + Incoming primitive batch Bejövő primitív tétel - + Finished primitive batch Befejezett primitív tétel - + Vertex shader invocation Vertex Shader invokáció - + Incoming display transfer Bejövő megjelenítés átvitel - + GSP command processed GSP parancs feldolgozva - + Buffers swapped Pufferek cserélve + + + Unknown debug context event + + CalibrationConfigurationDialog @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } Játék - - + + Block Player - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected Kapcsolódva - + Disconnected Lecsatlakozva - + %1 (%2/%3 members) - connected %1 (%2/%3 members) - kapcsolva @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! Köszönjük a beküldést! + + + Submitting + + + + + Communication error + + + + + An error occured while sending the Testcase + + + + + Next + + ConfigureAudio @@ -340,9 +365,9 @@ p, li { white-space: pre-wrap; } - - - %1 % + + %1% + Volume percentage (e.g. 50%) @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration Citra Konfiguráció - + + + General Általános - + + + System Rendszer - + + + Input Bevitel - + + + Graphics Grafika - + + + Audio Hang - + + + Camera Kamera - + + + Debug Debug - + + + Web Web + + + + + UI + + + + + Controls + + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } Kilépés megerősítése amikor az emuláció fut - - Interface language - Kezelőfelület nyelve - - - + Updates Frissítések - + Check for updates on start Frissítések keresése induláskor - + Silently auto update after closing Auto frissítés a háttérben bezárás után - + Emulation Emuláció - + Region: Régió: - + Auto-select Autó-kiválasztás - - Theme - Téma - - - - Theme: - Téma: - - - + Hotkeys Gyorsbillentyűk: - - <System> - <System> + + Reset All Settings + - - English - English + + Citra + + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick Analóg Pad beállítása @@ -1067,11 +1110,44 @@ p, li { white-space: pre-wrap; } + Clear All + + + + Restore Defaults Visszaállítás Alapértelmezettre - + + + Clear + + + + + + [not set] + + + + + + Restore Default + + + + + Information + + + + + After pressing OK, first move your joystick horizontally, and then vertically. + + + + [press key] [nyomj meg egy gombot] @@ -1440,17 +1516,27 @@ p, li { white-space: pre-wrap; } - + + yyyy-MM-ddTHH:mm:ss + + + + + Play Coins: + + + + Console ID: Konzol ID: - + Regenerate Regenerálás - + System settings are available only when game is not running. A rendszer-beállítások csak akkor érhetőek el, amikor a játék nem fut. @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } - - + + Console ID: 0x%1 Konzol ID: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? Ez ki fogja cserélni a jelenlegi virtuális 3DS-edet egy újra. A jelenlegi virtuális 3DS-edetet ne lehet majd később visszaállítani. Ez lehet, hogy váratlan hatást okoz a játékokban. Ez lehet hogy nem fog sikerülni, ha egy elavult konfigurációs mentésfájlt használsz. Folytatod? - + Warning Figyelem + + ConfigureUi + + + Form + + + + + General + + + + + Interface language: + + + + + Theme: + + + + + Game List + + + + + Icon Size: + + + + + + None + + + + + Small (24x24) + + + + + Large (48x48) + + + + + Row 1 Text: + + + + + + File Name + + + + + + Full Path + + + + + + Title Name + + + + + + Title ID + + + + + Row 2 Text: + + + + + Hide Titles without Icon + + + + + <System> + + + + + English + + + ConfigureWeb @@ -2155,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify Ellenőrzés @@ -2215,48 +2399,48 @@ p, li { white-space: pre-wrap; } - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Tudj meg többet</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Regisztráció</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">Mi a tokenem?</span></a> - - + + Telemetry ID: 0x%1 Telemetria ID: 0x%1 - + Username and token not verified Felhasználónév és token nincs leellenőrizve - + Username and token were not verified. The changes to your username and/or token have not been saved. A felhasználónév és token nem lett leellenőrizve. A felhasználóneveddel és/vagy a tokeneddel történt változások nem lettek elmentve. - + Verifying Ellenőrzés - + Verification failed Ellenőrzés sikertelen - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. Ellenőrzés sikertelen. Ellenőrizd le hogy jól írtad-e a felhasználóneved és tokenedet, és hogy működik-e az internetkapcsolatod. @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting Kapcsolódás - + Connect Kapcsolás @@ -2330,413 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? - + Telemetry - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Jelenlegi emulációs sebesség. A 100%-nál nagyobb vagy kisebb értékek azt mutatják, hogy az emuláció egy 3DS-nél gyorsabban vagy lassabban fut. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Mennyi képkocka/másodpercet jelez a játék jelenleg. Ez játékról játékra és helyszínről helyszínre változik. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Mennyi idő szükséges egy 3DS képkocka emulálásához, képkocka-limit vagy V-Syncet leszámítva. Teljes sebességű emulációnál ez maximum 16.67 ms-nek kéne lennie. - + Clear Recent Files - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available - + An update is available. Would you like to install it now? - + No Update Found - + No update is found. - - + + OpenGL 3.3 Unsupported + + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + + + + + Invalid ROM Format - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + ROM Corrupted - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + ROM Encrypted - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - - + + Video Core Error - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. - + Error while loading ROM! Hiba a ROM betöltése közben! - + An unknown error occured. Please see the log for more details. Egy ismeretlen hiba történt. Kérjük olvasd el a naplót több részletért. - + Start Indít - + Error Opening %1 Folder Hiba %1 Mappa Megnyitásában - - + + Folder does not exist! A mappa nem létezik! - + Error Opening %1 Hiba Indulás %1 - + Select Directory Könyvtár Kiválasztása - - 3DS Executable - 3DS Végrehajtható + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + - - - All Files (*.*) - Minden fájl (*.*) - - - + Load File Fájl Betöltése - + Load Files Fájlok Betöltése - + 3DS Installation File (*.CIA*) 3DS Telepítési Fájl (*.CIA*) - + + All Files (*.*) + Minden fájl (*.*) + + + %1 has been installed successfully. %1 sikeresen fel lett telepítve. - + Unable to open File A fájl megnyitása sikertelen - + Could not open %1 Nem lehet megnyitni: %1 - + Installation aborted Telepítés megszakítva - + The installation of %1 was aborted. Please see the log for more details %1 telepítése meg lett szakítva. Kérjük olvasd el a naplót több részletért. - + Invalid File Ismeretlen Fájl - + %1 is not a valid CIA %1 nem érvényes CIA - + Encrypted File Titkosított Fájl - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 vissza kell legyen fejtve mielőtt a Citrával lehetne használni. Egy igazi 3DS-re is szükség van. - + File not found A fájl nem található - + File "%1" not found Fájl "%1" nem található - - - + + + Continue Folytatás - + Missing Citra Account Hiányzó Citra Fiók - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. - - - + + Amiibo File (%1);; All Files (*.*) + + + + + Load Amiibo + + + + + + + Record Movie - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + + + + + Citra TAS Movie (*.ctm) - + Recording will start once you boot a game. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. - + Revision Dismatch - + Game Dismatch - - + + Invalid Movie File - + + Play Movie - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + + + + Game Not Found - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. - + Movie recording cancelled. - + Movie Saved - + The movie is successfully saved. - + Speed: %1% / %2% Sebesség: %1% / %2% - + Speed: %1% Sebesség: %1% - + Game: %1 FPS Játék: %1 FPS - + Frame: %1 ms Képkocka: %1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + System Archive Not Found Rendszerarchívum Nem Található - + Fatal Error Kritikus Hiba - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Abort - - + + Citra Citra - + Would you like to exit now? - + The game is still running. Would you like to stop emulation? - + Playback Completed - + Movie playback completed. - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2799,37 +3015,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + + + + + Compatibility + + + + + Region + + + + + File type + + + + + Size + + + + Open Save Data Location Mentésadat Helyének Megnyitása - + + Open Extra Data Location + + + + Open Application Location Alkalmazás Helyének Megnyitása - + Open Update Data Location Frissítésadat Helyének Megnyitása - + Navigate to GameDB entry GameDB helyéhez menni - + Scan Subfolders - + Remove Game Directory - + Open Directory Location @@ -2837,77 +3083,77 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. - + Bad - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot - + The game crashes when attempting to startup. - + Not Tested - + The game has not yet been tested. @@ -2915,7 +3161,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the game list @@ -2923,27 +3169,27 @@ Screen. GameListSearchField - + of - + result - + results - + Filter: - + Enter pattern to filter @@ -2951,23 +3197,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Pica Töréspontok - - + + Emulation running Emuláció fut - + Resume Folytatás - + Emulation halted at breakpoint Emuláció a törésponton leállt @@ -3384,42 +3630,42 @@ Screen. Lobby Frissítése - + Password Required to Join A Csatlakozáshoz Szükséges Jelszó - + Password: Jelszó: - + Room Name Szoba Neve - + Preferred Game Preferált Játék - + Host Gazda - + Players Játékosok - + Refreshing Frissítés - + Refresh List Lista Frissítése @@ -3442,220 +3688,245 @@ Screen. Legutóbbi Fájlok - + + Amiibo + + + + &Emulation &Emuláció - + &View &Nézet - + Debugging Hibakeresés - + Screen Layout Képernyő Elrendezése - + Movie - + Multiplayer Többjátékos - + &Help &Segítség - + Load File... Fájl Betöltése... - + Install CIA... CIA Telepítése... - + Load Symbol Map... Szimbólumtérkép Betöltése... - + E&xit &Kilépés - + &Start &Indítás - + &Pause &Szünet - + &Stop &Megállítás - + FAQ Gyakori Kérdések - + About Citra A Citráról - + Single Window Mode Egyablakos Mód - + Configure... Konfiguráció... - + Display Dock Widget Headers Dokk Modul Fejlécek Megjelenítése - + Show Filter Bar Filtersáv Megjelenítése - + Show Status Bar Állapotsáv Megjelenítése - + Select Game Directory... Játékkönyvtár Kiválasztása... - + Selects a folder to display in the game list Egy mappát választ ki, amely megjelenik a játéklistában - + Create Pica Surface Viewer Pica Felülnézegető Létrehozása - + Record Movie - + Play Movie - + Stop Recording / Playback - + + Enable Frame Advancing + + + + + Advance Frame + + + + Browse Public Game Lobby Nyilvános Játék Lobby Böngészése - + Create Room Szoba Létrehozása - + Leave Room Szoba Elhagyása - + Direct Connect to Room Közvetlen Kapcsolódás Szobához - + Show Current Room Jelenlegi Szoba Mutatása - + Fullscreen Teljes Képernyő - + Modify Citra Install Citra Telepítés Módosítása - + Opens the maintenance tool to modify your Citra installation Megnyitja a karbantartási eszközt, amivel a Citra telepítést módosíthatod - + Default Alapértelmezett - + Single Screen Egy Képernyő - + Large Screen Nagy Képernyő - + Side by Side Egymás Mellett - + Swap Screens Képernyők Cseréje - + Check for Updates Frissítések Keresése - + Report Compatibility Kompatibilitás Jelentése - + Restart + + + Load... + + + + + Remove + + MicroProfileDialog @@ -3681,23 +3952,23 @@ Screen. - + Connected Kapcsolódva - + Not Connected Nincs Kapcsolódva - + Error Hiba - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: A szoba bejelentése a nyilvános lobbyba sikertelen. Ahhoz, hogy tudj egy szobát hosztolni nyilvánosan, szükséged lesz egy hiteles Citra fiókra, az Emuláció -> Konfigurálás -> Web helyen. Ha nem szeretnél fiókot hosztolni a nyilvános lobbyban, akkor válaszd a Nem listázott menüpontot. @@ -3816,106 +4087,106 @@ Debug Üzenet: %1 játszik ezzel: %2 - - + + Invalid region Érvénytelen régió - + Japan Japán - + North America Észak-Amerika - + Europe Európa - + Australia Ausztrália - + China Kína - + Korea Korea - + Taiwan Tajvan - + Region free Régiómentes - + Invalid Region Érvénytelen Régió - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [nincs megadva] - + Hat %1 %2 - + Axis %1%2 - + Button %1 - - + + [unknown] [ismeretlen] - + [unused] [nem használt] - - + + Axis %1 diff --git a/dist/languages/id.ts b/dist/languages/id.ts index 1af80cfcc..5f5fae12f 100644 --- a/dist/languages/id.ts +++ b/dist/languages/id.ts @@ -54,7 +54,7 @@ p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">Citra adalah emulator 3DS gratis dan open source dengan lisensi GPLv2.0 atau versi setelahnya.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">Software ini seharusnya tidak digunakan untuk memainkan permainan yang didapatkan secara illegal.</span></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">Software ini seharusnya tidak digunakan untuk memainkan permainan games yang didapatkan secara illegal.</span></p></body></html> @@ -70,77 +70,82 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Perintah Pica dimuat - + Pica command processed Perintah Pica terproses - + Incoming primitive batch Batch primitif masuk - + Finished primitive batch Batch primitif selesai - + Vertex shader invocation - Memanggil shader Vertex + Permintaan Shader Vertex - + Incoming display transfer Transfer tampilan masuk - + GSP command processed Perintah GSP terproses - + Buffers swapped Buffer ditukar + + + Unknown debug context event + + CalibrationConfigurationDialog Communicating with the server... - + Berkomunikasi dengan server... Cancel - + Batalkan Touch the top left corner <br>of your touchpad. - + Sentuh bagian pojok kiri atas <br>dari touchpad anda. Now touch the bottom right corner <br>of your touchpad. - + Sekarang sentuh bagian pojok kanan bawah<br>dari touchpad anda. Configuration completed! - + Pengaturan Telah Selesai OK - + OK @@ -148,7 +153,7 @@ p, li { white-space: pre-wrap; } Room Window - Jendela Ruang + Jendela Grup @@ -171,15 +176,15 @@ p, li { white-space: pre-wrap; } Permainan - - + + Block Player Blokir Pemain - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? - Ketika Anda memblokir seorang pemain, Anda tidak lagi akan menerima pesan dari mereka. <br><br>Apakah Anda yakin ingin memblokir pemain %1? + Ketika Anda memblokir seorang pemain, Anda tidak dapat lagi menerima pesan chat dari mereka. <br><br>Apakah Anda yakin ingin memblokir pemain %1? @@ -187,28 +192,28 @@ p, li { white-space: pre-wrap; } Room Window - Jendela Ruang + Jendela Grup Leave Room - Tinggalkan Ruangan + Tinggalkan Grup ClientRoomWindow - + Connected Terhubung - + Disconnected Terputus - + %1 (%2/%3 members) - connected %1 (%2/%3 anggota) - terhubung @@ -229,7 +234,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p><span style=" font-size:10pt;">Should you choose to submit a test case to the </span><a href="https://citra-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Citra Compatibility List</span></a><span style=" font-size:10pt;">, The following information will be collected and displayed on the site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware Information (CPU / GPU / Operating System)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Which version of Citra you are running</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The connected Citra account</li></ul></body></html> - <html><head/><body><p><span style=" font-size:10pt;">Jika kamu memilih untuk memberikan test case ke </span><a href="https://citra-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Daftar Kompatibilitas Citra</span></a><span style=" font-size:10pt;">, Informasi berikut akan dikumpulkan dan ditampilkan pada situs: </span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Informasi perangkat keras (CPU / GPU / Sistem Operasi) </li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Versi Citra yang Anda jalankan </li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Akun Citra yang terhubung </li></ul></body></html> + <html><head/><body><p><span style=" font-size:10pt;">Jika kamu memilih untuk memberikan test case ke </span><a href="https://citra-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Daftar Kompatibilitas Citra</span></a><span style=" font-size:10pt;">, Informasi berikut ini akan dikumpulkan dan ditampilkan pada situs: </span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Informasi perangkat keras (CPU / GPU / Sistem Operasi) </li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Versi Citra apa saja yang Anda jalankan </li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Akun Citra yang terhubung </li></ul></body></html> @@ -239,7 +244,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Game functions flawlessly with no audio or graphical glitches.</p></body></html> - <html><head/><body><p> Permainan berfungsi dengan mulus tanpa kecacatan audiovisual </p></body></html> + <html><head/><body><p> Permainan berfungsi dengan lancar tanpa kecacatan audio atau gambar </p></body></html> @@ -249,17 +254,17 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.</p></body></html> - <html><head/><body><p>Permainan berfungsi dengan sedikit kecacatan audiovisual dan dapat dimainkan dari awal hingga akhir. Mungkin membutuhkan beberapa solusi tambahan. </p></body></html> + <html><head/><body><p>Permainan berfungsi dengan sedikit kecacatan audio atau gambar dan dapat dimainkan dari awal hingga akhir. Mungkin membutuhkan beberapa perbaikan tambahan. </p></body></html> Okay - Baik + Oke <html><head/><body><p>Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.</p></body></html> - <html><head/><body><p>Permainan berfungsi dengan banyak kecacatan audiovisual, tapi permainan dapat dimainkan dari awal hingga akhir dengan solusi tambahan. </p></body></html> + <html><head/><body><p>Permainan berfungsi dengan banyak kecacatan audi atau gambar, tapi permainan dapat dimainkan dari awal hingga akhir dengan perbaikan tambahan. </p></body></html> @@ -269,7 +274,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.</p></body></html> - <html><head/><body><p>Permainan berfungsi, tapi dengan banyak kecacatan audiovisual. Tidak dapat berjalan di beberapa daerah karena cacat bahkan dengan solusi tambahan. </p></body></html> + <html><head/><body><p>Permainan berfungsi, tapi dengan banyak kecacatan besar audio dan gambar. Tidak dapat berjalan di beberapa daerah karena cacat bahkan dengan perbaikan tambahan. </p></body></html> @@ -279,28 +284,48 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.</p></body></html> - <html><head/><body><p>Permainan benar-benar tidak bisa dimainkan karena banyak kecacatan audiovisual. Tidak dapat melewati Layar Mulai.</p></body></html> + <html><head/><body><p>Permainan secara total tidak bisa dimainkan karena banyak kecacatan besar audio dan gambar. Tidak dapat melewati Layar Mulai.</p></body></html> Won't Boot - Tidak mau mulai + Tidak Mau Memulai <html><head/><body><p>The game crashes when attempting to startup.</p></body></html> - <html><head/><body><p>Permainan berhenti ketika mencoba untuk dimulai. </p></body></html> + <html><head/><body><p>Permainan ini tiba-tiba berhenti ketika mencoba untuk dimulai. </p></body></html> <html><head/><body><p>Independent of speed or performance, how well does this game play from start to finish on this version of Citra?</p></body></html> - <html><head/><body><p>Terlepas dari kelajuan atau performa, bagaimana permainan ini berjalan dari awal hingga akhir di versi Citra ini?</p></body></html> + <html><head/><body><p>Terlepas dari kelajuan atau performa, seberapa baik permainan ini berjalan dari awal hingga akhir di versi Citra ini?</p></body></html> Thank you for your submission! Terima kasih atas masukannya! + + + Submitting + + + + + Communication error + + + + + An error occured while sending the Testcase + + + + + Next + + ConfigureAudio @@ -312,17 +337,17 @@ p, li { white-space: pre-wrap; } Output Engine: - Output Engine: + Mesin Pengeluaran: This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Pasca-pemrosesan ini dilakukan untuk menyesuaikan kelajuan audio agar sesuai dengan kelajuan emulasi dan mencegah terjadinya gagap audio. Namun proses ini meningkatkan latensi audio. + Efek pasca-pemrosesan ini dilakukan untuk menyesuaikan kecepatan audio agar sesuai dengan kecepatan emulasi dan mencegah terjadinya audio stutter. Namun proses ini meningkatkan latensi audio. Enable audio stretching - Aktifkan peregangan audio + Aktifkan audio stretching @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + %1% @@ -362,7 +387,7 @@ p, li { white-space: pre-wrap; } Select the camera to configure - Pilih kamera untuk diatur + Pilih kamera untuk di atur @@ -404,7 +429,7 @@ p, li { white-space: pre-wrap; } Select the position of camera to configure - Pilih posisi kamera untuk diatur + Pilih posisi kamera untuk di atur @@ -430,7 +455,7 @@ p, li { white-space: pre-wrap; } Select where the image of the emulated camera comes from. It may be an image or a real camera. - Pilih darimana gambar dari kamera yang diemulasi datang. Bisa dari gambar atau kamera asli. + Pilih di mana gambar dari kamera yang di emulasi datang berasal. Bisa dari gambar atau kamera asli. @@ -455,7 +480,7 @@ p, li { white-space: pre-wrap; } File: - Berkas: + File: @@ -492,7 +517,7 @@ p, li { white-space: pre-wrap; } None - Tidak ada + Tidak Ada @@ -512,17 +537,17 @@ p, li { white-space: pre-wrap; } Select an image file every time before the camera is loaded - Pilih berkas gambar setiap kali sebelum kamera dimuat + Pilih file gambar setiap kali sebelum kamera di muat Prompt before load - Tampilkan sebelum dimuat + Tampilkan sebelum di muat Preview - Pratinjau + Peninjauan @@ -532,7 +557,7 @@ p, li { white-space: pre-wrap; } Click to preview - Klik untuk pratinjau + Klik untuk meninjau @@ -542,12 +567,12 @@ p, li { white-space: pre-wrap; } Supported image files (%1) - Berkas gambar yang disupport (%1) + File gambar yang di dukung (%1) Open File - Buka Berkas + Buka File @@ -585,7 +610,7 @@ p, li { white-space: pre-wrap; } Show Log Console (Windows Only) - Tampilkan Log Konsol (Hanya Jendela) + Tampilkan Log Konsol (Hanya Jendela Windows) @@ -595,61 +620,89 @@ p, li { white-space: pre-wrap; } Miscellaneous - Lain-lain + Tambahan Lain-lain Enable CPU JIT - Aktifkan JIT CPU + Aktifkan CPU JIT ConfigureDialog - + Citra Configuration Konfigurasi Citra - + + + General Umum - + + + System Sistem - + + + Input - Input + Masukan - + + + Graphics Grafis - + + + Audio Audio - + + + Camera Kamera - + + + Debug Debug - + + + Web Web + + + + + UI + + + + + Controls + Kontrol + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } Konfirmasi keluar saat emulasi berjalan - - Interface language - Bahasa Tampilan - - - + Updates Pembaruan - + Check for updates on start Periksa pembaruan ketika memulai - + Silently auto update after closing Otomatis memperbarui setelah menutup - + Emulation Emulasi - + Region: - Region: + Wilayah: - + Auto-select - Otomatis + Otomatis Pilih - - Theme - Tema - - - - Theme: - Tema: - - - + Hotkeys - Hotkey + Hotkeys - - <System> - <System> + + Reset All Settings + - - English - Inggris + + Citra + + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + @@ -765,7 +808,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Use OpenGL to accelerate rendering.</p><p>Disable to debug graphics-related problem.</p></body></html> - <html><head/><body><p>Gunakan OpenGL untuk mengakselerasi proses render.</p><p>Nonaktifkan untuk men-debug isu terkait grafis</p></body></html> + <html><head/><body><p>Gunakan OpenGL untuk mempercepat proses render.</p><p>Nonaktifkan untuk men-debug isu terkait grafis</p></body></html> @@ -775,12 +818,12 @@ p, li { white-space: pre-wrap; } Internal Resolution - Resolusi Internal + Resolusi Bawaan Auto (Window Size) - Otomatis (Ukuran Jendela) + Otomatis (Ukuran Jendela Window) @@ -835,27 +878,27 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Use OpenGL to accelerate shader emulation.</p><p>Requires a relatively powerful GPU for better performance.</p></body></html> - <html><head/><body><p>Gunakan OpenGL untuk mengakselerasi emulasi shader</p><p>Membutuhkan GPU yang relatif kuat untuk performa yang lebih baik.</p></body></html> + <html><head/><body><p>Gunakan OpenGL untuk mempercepat emulasi shader</p><p>Membutuhkan GPU yang relatif kuat untuk performa yang lebih baik.</p></body></html> Enable Hardware Shader - Gunakan Shader Hardware + Gunakan Hardware Shader <html><head/><body><p>Correctly handle all edge cases in multiplication operation in shaders. </p><p>Some games requires this to be enabled for the hardware shader to render properly.</p><p>However this would reduce performance in most games.</p></body></html> - <html><head/><body><p>Menangani segala kasus tepian dalam operasi perkalian didalam shader secara tepat.</p><p>Beberapa permainan membutuhkan fitur ini untuk merender secara benar.</p><p>Namun fitur ini akan mengurangi performa dalam banyak permainan.</p></body></html> + <html><head/><body><p>Menangani semua kasus tepian dalam operasi penggandaan dalam shader secara tepat.</p><p>Beberapa game membutuhkan fitur ini di aktifkan untuk merender hardware shader secara benar.</p><p>Namun fitur ini akan mengurangi performa dalam kebanyakan game.</p></body></html> Accurate Multiplication - Perkalian Akurat + Penggandaan Akurat <html><head/><body><p>Force to fall back to software shader emulation when geometry shaders are used. </p><p>Some games require this to be enabled for the hardware shader to render properly.</p><p>However this might reduce performance in some games</p></body></html> - <html><head/><body><p>Paksa kembali ke emulasi shader software ketika shader geometri digunakan. </p><p>Beberapa permainan membutuhkan ini untuk digunakan agar shader hardware bekerja dengan baik.</p><p>Namun ini dapat mengakibatkan berkurangnya performa dalam beberapa permainan</p></body></html> + <html><head/><body><p>Paksa kembalikan kepada emulasi shader software ketika shader geometri digunakan. </p><p>Beberapa permainan membutuhkan filtur ini untuk di aktifkan agar hardware shader bekerja dengan baik.</p><p>Namun ini dapat mengakibatkan berkurangnya performa dalam beberapa game</p></body></html> @@ -865,12 +908,12 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Use the JIT engine instead of the interpreter for software shader emulation. </p><p>Enable this for better performance.</p></body></html> - <html><head/><body><p>Gunakan JIT sebagai ganti interperter untuk emulasi shader software.</p><p>Gunakan ini untuk performa yang lebih baik.</p></body></html> + <html><head/><body><p>Gunakan JIT Engine sebagai ganti interperter untuk emulasi shader software.</p><p>Gunakan ini untuk performa yang lebih baik.</p></body></html> Enable Shader JIT - Gunakan Shader JIT + Aktifkan Shader JIT @@ -880,7 +923,7 @@ p, li { white-space: pre-wrap; } Enable Stereoscopic 3D - Gunakan Stereoscopic 3D + Aktifkan Stereoskopik 3D @@ -905,7 +948,7 @@ p, li { white-space: pre-wrap; } Side by Side - Bersebelahan + Saling Bersebelahan @@ -920,12 +963,12 @@ p, li { white-space: pre-wrap; } Hardware Shader Warning - Peringatan Shader Perangkat Keras + Peringatan Hardware Shader Hardware Shader support is broken on macOS, and will cause graphical issues like showing a black screen.<br><br>The option is only there for test/development purposes. If you experience graphical issues with Hardware Shader, please turn it off. - Shader Perangkat Keras tidak berfungsi di macOS, dan akan menyebabkan berbagai masalah pada tampilan seperti layar hitam.<br><br>Pilihan tersebut ada hanya untuk tujuan pengetesan/pengembangan. Apabila Anda mengalami masalah pada tampilan ketika Shader Perangkat Keras menyala, tolong matikan fitur tersebut. + Dukungan Hardware Shader tidak berfungsi di macOS, dan akan menyebabkan berbagai masalah pada tampilan seperti layar berwarna hitam.<br><br>Pilihan tersebut ada hanya untuk tujuan pengujian/pengembangan. Jika Anda mengalami masalah pada tampilan dengan Hardware Shader, tolong matikan fitur tersebut. @@ -938,7 +981,7 @@ p, li { white-space: pre-wrap; } Face Buttons - Face Buttons + Tombol Face Buttons @@ -996,7 +1039,7 @@ p, li { white-space: pre-wrap; } Shoulder Buttons - Shoulder Buttons + Tombol Shoulder Buttons @@ -1021,14 +1064,14 @@ p, li { white-space: pre-wrap; } Circle Pad - Circle Pad + Tombol Circle Pad - + Set Analog Stick - Set Analog Stick + Tentukan Analog Stick @@ -1043,12 +1086,12 @@ p, li { white-space: pre-wrap; } Start: - Start: + Mulai: Select: - Select: + Pilih: @@ -1058,20 +1101,53 @@ p, li { white-space: pre-wrap; } Circle Mod: - Circle Mod: + Tombol Circle Mod: Motion / Touch... - + Motion/Touch... - Restore Defaults - Kembali ke Default + Clear All + Bersihkan Semua - + + Restore Defaults + Kembalikan ke kondisi Default + + + + + Clear + Bersihkan + + + + + [not set] + [belum di tentukan] + + + + + Restore Default + Kembalikan Ke Kondisi Default + + + + Information + Informasi + + + + After pressing OK, first move your joystick horizontally, and then vertically. + Setelah menekan tombol OK, pindahkan joystick anda secara horizontal kemudian secara vertikal. + + + [press key] [tekan tombol] @@ -1081,165 +1157,165 @@ p, li { white-space: pre-wrap; } Configure Motion / Touch - + Atur Motion/Touch Motion - + Gerakan Motion Provider: - + Penyedian Gerakan: Sensitivity: - + Sensitivitas: Touch - + Sentuhan Touch Provider: - + Penyedia Sentuhan: Calibration: - + Penyesuaian (100, 50) - (1800, 850) - + (100,50)-(1800,850) Configure - + Pengaturan CemuhookUDP Config - + Pengaturan CemuhookUDP You may use any Cemuhook compatible UDP input source to provide motion and touch input. - + Kamu dapat menggunakan Cemuhook apa saja yang cocok dengan sumber input UDP untuk menyediakan input motion dan touch. Server: - + Server Port: - + Port: Pad: - + Pad: Pad 1 - + Pad 1 Pad 2 - + Pad 2 Pad 3 - + Pad 3 Pad 4 - + Pad 4 Learn More - + Pelajari Lebih Banyak Test - + Tes Mouse (Right Click) - + Mouse (Klik Kanan) CemuhookUDP - + CemuhookUDP Emulator Window - + Jendela Window Emulator <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - + <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Pelajari Lebih Banyak</span></a> Testing - + Pengujian Configuring - + Mengatur Test Successful - + Pengujian Berhasil Successfully received data from the server. - + Berhasil Menerima Data Dari Server. Test Failed - + Pengujian Gagal Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. - + Tidak bisa menerima data valid dari server <br>Tolong pastikan bahwa server telah di atur dengan benar dan alamat serta port-nya sudah benar. Citra - + Citra UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. - + Pengaturan pengujian atau penyesuaian UDP sedang dalam proses.<br>Tolong tunggu sampai selesai. @@ -1257,7 +1333,7 @@ p, li { white-space: pre-wrap; } Username - Username + Nama User @@ -1332,7 +1408,7 @@ p, li { white-space: pre-wrap; } Note: this can be overridden when region setting is auto-select - Catatan: ini akan diganti bila setting region adalah otomatis + Catatan: ini bisa di lewati bila pengaturan region-nya otomatis di pilih @@ -1347,7 +1423,7 @@ p, li { white-space: pre-wrap; } French (français) - Perancis (français) + Prancis (français) @@ -1367,7 +1443,7 @@ p, li { white-space: pre-wrap; } Simplified Chinese (简体中文) - Cina Disederhanakan (简体中文) + Cina Yang Di Sederhanakan (简体中文) @@ -1422,37 +1498,47 @@ p, li { white-space: pre-wrap; } Clock - + Jam System Clock - + Jam Sistem Fixed Time - + Waktu Tetap Startup time + Waktu Mulai + + + + yyyy-MM-ddTHH:mm:ss - + + Play Coins: + Koin Permainan: + + + Console ID: ID Konsol: - + Regenerate - Perbarui + Perbaharui - + System settings are available only when game is not running. - Pengaturan sistem hanya tersedia jika game sedang tidak berjalan. + Pengaturan sistem hanya tersedia ketika game sedang tidak berjalan. @@ -1482,7 +1568,7 @@ p, li { white-space: pre-wrap; } Bahamas - Bahamas + Bahama @@ -1492,7 +1578,7 @@ p, li { white-space: pre-wrap; } Belize - Belise + Belize @@ -1502,12 +1588,12 @@ p, li { white-space: pre-wrap; } Brazil - Brasil + Brazil British Virgin Islands - Kepulauan Virgin Britania Raya + Kepulauan Virginia Britania Raya @@ -1522,7 +1608,7 @@ p, li { white-space: pre-wrap; } Chile - Chile + Chili @@ -1562,12 +1648,12 @@ p, li { white-space: pre-wrap; } Grenada - Grenada + Granada Guadeloupe - Guadeloupe + Guadelope @@ -1647,7 +1733,7 @@ p, li { white-space: pre-wrap; } Saint Vincent and the Grenadines - Saint Vincent dan Grenadines + Saint Vincent dan Granadines @@ -1677,7 +1763,7 @@ p, li { white-space: pre-wrap; } US Virgin Islands - Kepulauan Virgin Amerika Serikat + Kepulauan Virginia Amerika Serikat @@ -1807,7 +1893,7 @@ p, li { white-space: pre-wrap; } Luxembourg - Luksembourg + Luksemburg @@ -1842,7 +1928,7 @@ p, li { white-space: pre-wrap; } New Zealand - New Zealand + Selandia Baru @@ -1852,7 +1938,7 @@ p, li { white-space: pre-wrap; } Poland - Poland + Polandia @@ -1862,7 +1948,7 @@ p, li { white-space: pre-wrap; } Romania - Rumania + Romania @@ -1877,7 +1963,7 @@ p, li { white-space: pre-wrap; } Slovakia - Slovakia + Slowakia @@ -1917,7 +2003,7 @@ p, li { white-space: pre-wrap; } United Kingdom - Britania Raya + Inggris @@ -1977,7 +2063,7 @@ p, li { white-space: pre-wrap; } Andorra - Andorra + Andora @@ -2102,7 +2188,7 @@ p, li { white-space: pre-wrap; } Jordan - Jordan + Yordania @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } Bermuda - - + + Console ID: 0x%1 ID Konsol: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? - Ini akan menggantikan 3DS virtual saat ini dengan yang baru. 3DS virtual Anda saat ini tidak dapat dikembalikan. Mungkin akan memberikan efek tak terduga dalam permainan. Kemungkinan ini akan gagal jika Anda menggunakan config savegame lama. Lanjutkan? + Ini akan menggantikan 3DS virtual anda saat ini dengan yang baru. 3DS virtual Anda saat ini tidak dapat dikembalikan. Hal ini mungkin akan memberikan efek tak terduga dalam game. Kemungkinan hal ini akan gagal jika Anda menggunakan pengaturan save game lama. Lanjutkan? - + Warning Peringatan + + ConfigureUi + + + Form + + + + + General + + + + + Interface language: + + + + + Theme: + + + + + Game List + + + + + Icon Size: + + + + + + None + + + + + Small (24x24) + + + + + Large (48x48) + + + + + Row 1 Text: + + + + + + File Name + + + + + + Full Path + + + + + + Title Name + + + + + + Title ID + + + + + Row 2 Text: + + + + + Hide Titles without Icon + + + + + <System> + + + + + English + + + ConfigureWeb @@ -2151,11 +2335,11 @@ p, li { white-space: pre-wrap; } By providing your username and token, you agree to allow Citra to collect additional usage data, which may include user identifying information. - Dengan memberikan username dan token, Anda menyetujui untuk memperbolehkan Citra mengumpulkan data penggunaan tambahan, yang mungkin berisi informasi identifikasi pengguna. + Dengan memberikan nama user dan token, Anda menyetujui Citra untuk mengumpulkan data penggunaan tambahan, mungkin termaksud informasi identifikasi pengguna. - + Verify Verifikasi @@ -2172,7 +2356,7 @@ p, li { white-space: pre-wrap; } Username: - Username: + Nama User: @@ -2192,7 +2376,7 @@ p, li { white-space: pre-wrap; } Learn more - Pelajari lebih lanjut + Pelajari lebih Banyak @@ -2212,53 +2396,53 @@ p, li { white-space: pre-wrap; } Show Current Game in your Discord Status - Tampilkan Permainan Saat Ini ke Status Discord + Tampilkan Game Saat Ini ke Status Discord Anda - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> - <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Pelajari lebih lanjut</span></a> + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Pelajari lebih banyak</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Daftar</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">Apa token saya ?</span></a> - - + + Telemetry ID: 0x%1 ID Telemetri: 0x%1 - - - Username and token not verified - Nama pengguna dan token tidak terverifikasi - - Username and token were not verified. The changes to your username and/or token have not been saved. - Username dan token tidak terverifikasi. Perubahan pada username dan/atau token tidak disimpan. + Username and token not verified + Nama user dan token tidak terverifikasi - + + Username and token were not verified. The changes to your username and/or token have not been saved. + Nama user dan token tidak terverifikasi. Perubahan pada nama user dan/atau token tidak disimpan. + + + Verifying Memverifikasi - + Verification failed Verifikasi gagal - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. - Verifikasi gagal. Pastikan username dan token yang Anda masukkan benar dan koneksi internet Anda bekerja. + Verifikasi gagal. Pastikan nama user dan token yang Anda masukkan benar serta koneksi internet Anda bekerja. @@ -2281,7 +2465,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>IPv4 address of the host</p></body></html> - <html><head/><body><p>Alamat IPv4 yang digunakan oleh host</p></body></html> + <html><head/><body><p>Alamat IPv4 dari host</p></body></html> @@ -2291,7 +2475,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Port number the host is listening on</p></body></html> - <html><head/><body><p>Nomor Port yang digunakan oleh host</p></body></html> + <html><head/><body><p>Nomor Port yang digunakan oleh host sedang di dengarkan</p></body></html> @@ -2301,7 +2485,7 @@ p, li { white-space: pre-wrap; } Nickname - Nickname + Nama Panggilan @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting Menghubungkan - + Connect Hubungkan @@ -2330,413 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? - <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Data anonim dikumpulkan</a>untuk membantu menjadikan Citra lebih baik. <br/><br/>Apakah Anda ingin membagikan penggunaan data Anda dengan kami? + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Data anonim dikumpulkan</a>untuk membantu Citra menjadi lebih baik. <br/><br/>Apakah Anda ingin membagikan penggunaan data Anda dengan kami? - + Telemetry Telemetri - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. - Kecepatan emulasi saat ini. Nilai yang lebih tinggi atau lebih rendah dari 100% menunjukan emulasi yang lebih cepat atau lebih lambat dari 3DS. + Kecepatan emulasi saat ini. Nilai yang lebih tinggi atau lebih rendah dari 100% menunjukan emulasi berjalan lebih cepat atau lebih lambat dari 3DS. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - Seberapa banyak frame per detik yang ditampilkan oleh permainan. Tiap permainan dan adegan akan bervariasi. + Beberapa banyak frame per detik yang ditampilkan oleh permainan saat ini. Hal ini akan bervariasi dari tiap game dan adegan per-adegan. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - Waktu yang dibutuhkan untuk meniru frame 3DS, framelimiting atau v-sync tidak termasuk. setidaknya 16.67 ms untuk emulasi kecepatan penuh. + Waktu yang dibutuhkan untuk mengemulasi frame 3DS, tidak menghitung pembatasan frame atau v-sync. setidaknya emulasi yang tergolong kecepatan penuh harus berada setidaknya pada 16.67 ms. - + Clear Recent Files - Bersihkan Berkas-berkas Terbaru + Bersihkan Berkas File Terbaru - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available Pembaharuan Tersedia - + An update is available. Would you like to install it now? Sebuah pembaharuan tersedia. Apakah Anda ingin memasangnya sekarang? - + No Update Found - Tidak Ada Pembaharuan Tersedia - - - - No update is found. - Tidak Ada Pembaharuan Tersedia. + Tidak Ada Pembaharuan di Temukan - + No update is found. + Tidak Ada Pembaharuan Yang di Temukan. + + + + OpenGL 3.3 Unsupported + + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + + + + + Invalid ROM Format - Format ROM Salah + Format ROM Invalid - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - Format ROM Anda tidak didukung.<br/>Mohon ikuti petunjuk untuk membuat ulang<a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>kartrid permainan</a> atau <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>judul terpasang</a>anda. + Format ROM Anda tidak didukung.<br/>Mohon ikuti petunjuk untuk redump<a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>kartrid permainan</a> atau <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>judul terpasang</a>anda. - + ROM Corrupted - ROM Bermasalah + ROM Mengalami Kerusakan - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - ROM anda bermasalah. <br/>Mohon ikuti petunjuk untuk membuat ulang <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>kartrid permainan</a> atau <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>judul terpasang</a>anda. + ROM anda mengalami kerusakan. <br/>Mohon ikuti petunjuk untuk redump <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>kartrid game</a> atau <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>judul terpasang</a>anda. - + ROM Encrypted ROM Dienkripsi - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. ROM anda dienkripsi. <br/>Mohon ikuti petunjuk untuk membuat ulang <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>kartrid permainan</a> atau <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>judul terpasang</a>anda. - - + + Video Core Error Video Core Bermasalah - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. Sebuah masalah telah terjadi. Mohon<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>lihat catatan</a> untuk informasi lebih lanjut. Pastikan anda telah memiliki driver terbaru untuk perangkat GPU anda. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. Anda menggunakan driver bawaan Windows untuk GPU anda. Anda perlu menginstall driver terbaru dari website produsen GPU anda. - + Error while loading ROM! Error saat memuat ROM! - + An unknown error occured. Please see the log for more details. Terjadi error yang tidak diketahui. Lihat log untuk detail lebih lanjut. - + Start Mulai - + Error Opening %1 Folder Kesalahan Dalam Membuka Folder %1 - - + + Folder does not exist! Folder tidak ada! - + Error Opening %1 Kesalahan Dalam Membuka %1 - + Select Directory Pilih Direktori - - 3DS Executable - 3DS Executable + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + - - - All Files (*.*) - Semua File (*.*) - - - + Load File Muat File - + Load Files Muat berkas - + 3DS Installation File (*.CIA*) 3DS Installation File (*.CIA*) - + + All Files (*.*) + Semua File (*.*) + + + %1 has been installed successfully. %1 telah terinstall. - + Unable to open File Tidak dapat membuka File - + Could not open %1 Tidak dapat membuka %1 - + Installation aborted Instalasi dibatalkan - + The installation of %1 was aborted. Please see the log for more details Instalasi %1 dibatalkan. Silahkan lihat file log untuk info lebih lanjut. - + Invalid File File yang tidak valid - + %1 is not a valid CIA %1 bukan CIA yang valid - + Encrypted File File ter-Encrypt - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 harus di dekripsi sebelum digunakan dengan Citra. 3DS asli dibutuhkan. - + File not found File tidak ditemukan - + File "%1" not found File "%1" tidak ditemukan - - - + + + Continue Lanjut - + Missing Citra Account Akun Citra Tidak Ada - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. Anda harus menautkan akun Citra anda untuk mengajukan skenario pengetesan.<br/>Pergi Ke Emulasi &gt; Konfigurasi... &gt; Alamat Website untuk melakukannya. - - - - Record Movie + + Amiibo File (%1);; All Files (*.*) - - - Citra TAS Movie (*.ctm) - - - - - Recording will start once you boot a game. - - - - - The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? - - - - - The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? - - - - - - The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. - - - - - Revision Dismatch - - - - - Game Dismatch - - - - - - Invalid Movie File - - - - - Play Movie - - - - - Game Not Found - - - - - The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. - - - - - Movie recording cancelled. + + Load Amiibo + + - Movie Saved - + + Record Movie + Rekam Video + + + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + Untuk menjaga kekonsistenan dengan RNG,di sarankan untuk merekam video dari permulaan game.<br>Apa anda yakin masih ingin merekam video-nya sekarang? + + + + + Citra TAS Movie (*.ctm) + Citra TAS Video (*.ctm) - The movie is successfully saved. - + Recording will start once you boot a game. + Proses perekaman akan segera di mulai begitu kamu memulai game. + + + + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? + File video yang anda coba untuk muat telah di buat dalam perubahan berbeda dari Citra.<br/>Citra telah punya beberapa perubahan selama waktu tersebut dan proses pemutaran kembali mungin tidak sinkron atau tidak bekerja seperti yang di harapkan.<br/><br/>Pa anda masih yakin untuk memuat file video-nya? + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? + File video yang anda coba muat telah di rekam dengan game berbeda.<br/>Proses pemutaran kembali mungkin tidak akan bekerja seperti yang di harapkan dan mungkin menyebabkan hasil yang tidak dapat di duga.<br/><br/>Apa anda masih yakin ingin memuat file video-nya? + + + + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. + File video yang anda coba untuk muat tidak valid.<br/>Bisa jadi di karenakan file-nya rusak atau Citra telah membuat beberapa perubahan besar kepada Modul Video.<br/>Tolong pilih file video yang berbeda dan silahkan coba kembali. + + + + Revision Dismatch + Perubahan Tidak Pas + + + + Game Dismatch + Game Tidak Pas + + + + + Invalid Movie File + File Video Tidak Valid + + + + + Play Movie + Putar Video + + + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + Untuk menjaga kekonsistenan dengan RNG,di sarankan untuk memutar video dari awal game.<br>Apa anda masih yakin untuk memainkan video-nya sekarang? + + + + Game Not Found + Game Tidak Di Temukan + + + + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. + Video yang anda coba untuk putar dari game yang tidak ada dalam daftar list game.Jika anda memiliki game-nya,tolong tambahkan game folder-,nya ke daftar list game dan coba mainkan video-nya lagi, + + + + Movie recording cancelled. + Perekaman Video Di Batalkan. + + + + Movie Saved + Video Di Simpan + + + + The movie is successfully saved. + Video telah berhasil di simpan. + + + Speed: %1% / %2% Kelajuan: %1% / %2% - + Speed: %1% Kecepatan: %1% - + Game: %1 FPS Game: %1 FPS - + Frame: %1 ms Frame: %1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. %1 tidak tersedia. Mohon <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>buat arsip sistem anda</a>.<br/>Melanjutkan emulasi dapat menyebabkan kegagalan dan masalah-masalah lainnya. - + System Archive Not Found Arsip Sistem Tidak Ditemukan - + Fatal Error Fatal Error - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. Sebuah masalah serius telah terjadi. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Periksa log</a> untuk informasi lebih lanjut.<br/>Melanjutkan emulasi dapat menyebabkan kegagalan dan masalah-masalah lainnya. - + Abort Batalkan - - + + Citra Citra - + Would you like to exit now? Apakah anda ingin keluar sekarang? - + The game is still running. Would you like to stop emulation? Permainan sedang berjalan. Apakah anda ingin menghentikan emulasi? - + Playback Completed - + Pemutaran Kembali Telah Selesai - + Movie playback completed. - + Pemutaran kembali video telah selesai. - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2799,37 +3015,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + + + + + Compatibility + + + + + Region + + + + + File type + + + + + Size + + + + Open Save Data Location Buka Lokasi Save Data - + + Open Extra Data Location + Buka Lokasi Data Tambahan + + + Open Application Location Buka Lokasi Aplikasi - + Open Update Data Location Buka Lokasi Data Pembaruan - + Navigate to GameDB entry Arahkan ke entri GameDB - + Scan Subfolders Pindai Subfolder - + Remove Game Directory Hapus Lokasi Permainan - + Open Directory Location Buka Lokasi Penyimpanan @@ -2837,85 +3083,90 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect - + Sempurna - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Fungsi Game-nya akan sempurna tanpa kerusakan audio atau gambar,Semua fungsionalitas yang telah di uji bekerja sebagaimana yang telah di tujukan tanpa +ada lagi perbaikan yang di butuhkan. - + Great - + Hebat - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Fungsi Game dengan kerusakan gambar atau audio yang kecil dan dapat di mainkan dari awal sampai selesai.Mungkin membutuhkan beberapa +perbaikan. - + Okay - + Setuju - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. - + Fungsi Game dengan kerusakan gambar atau audio yang besar,tetapi game-nya dapat di mainkan dari awal sampai akhir dengan berbagai macam +perbaikan. - + Bad - + Buruk - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Fungsi Game,tetapi dengan kerusakan gambar atau audio yang besar.Tidak bisa berlanjut memasuki ke dalam area tertentu do karenakan kerusakannya tersebut +bahkan dengan berbagai macam perbaikan - + Intro/Menu - + Intro/Menu - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Game secara total tidak dapat di mainkan di karenakan kerusakan gambar atau audio yang besar.Tidak bisa berlanjut hingga melewati Layar +Mulai. - + Won't Boot - + Tidak Mau Memulai - + The game crashes when attempting to startup. - + Game ini mengalami kegagalan ketika ingin memulai. - + Not Tested - + Belum Di Uji - + The game has not yet been tested. - + Game ini masih belum di uji. GameListPlaceholder - + Double-click to add a new folder to the game list Klik 2 kali untuk menambahkan folder baru pada daftar permainan @@ -2923,27 +3174,27 @@ Screen. GameListSearchField - + of dari - + result hasil - + results hasil - + Filter: Saringan: - + Enter pattern to filter Masukkan pola untuk menyaring @@ -2951,23 +3202,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Pica Breakpoints - - + + Emulation running Emulasi berjalan - + Resume Jalankan - + Emulation halted at breakpoint Emulasi berhenti di breakpoint @@ -3384,42 +3635,42 @@ Screen. Segarkan Lobi - + Password Required to Join Kata Sandi Dibutuhkan untuk Bergabung - + Password: Kata Sandi: - + Room Name Nama Ruangan - + Preferred Game Preferensi Permainan - + Host Host - + Players Pemain - + Refreshing Menyegarkan - + Refresh List Segarkan Daftar @@ -3442,220 +3693,245 @@ Screen. File Terkini - + + Amiibo + + + + &Emulation &Emulasi - + &View &Tampilan - + Debugging Debugging - + Screen Layout Tata Letak Layar - + Movie - + Video - + Multiplayer Multiplayer - + &Help Ba&ntuan - + Load File... Muat File... - + Install CIA... Pasang CIA... - + Load Symbol Map... Muat Symbol Map... - + E&xit &Keluar - + &Start &Mulai - + &Pause &Jeda - + &Stop &Berhenti - + FAQ FAQ - + About Citra Tentang Citra - + Single Window Mode Mode Satu Jendela - + Configure... Konfigurasi... - + Display Dock Widget Headers Tampilkan Dock Widget Headers - + Show Filter Bar Tampilkan Filter Bar - + Show Status Bar Tampilkan Status Bar - + Select Game Directory... Pilih Direktori Permainan... - + Selects a folder to display in the game list Pilih folder untuk ditampilkan pada daftar permainan - + Create Pica Surface Viewer Buat Penampil Permukaan Pica - + Record Movie - + Rekam Video - + Play Movie - + Putar Video - + Stop Recording / Playback - + Berhenti Merekam/Putar Kembali - + + Enable Frame Advancing + Aktifkan Pemercepat Frame + + + + Advance Frame + Pemercepat Frame + + + Browse Public Game Lobby Jelajahi Lobi Permainan Publik - + Create Room Buat Ruangan - + Leave Room Tinggalkan Ruangan - + Direct Connect to Room Koneksi Langsung ke Ruangan - + Show Current Room Tunjukkan Ruangan Saat Ini - + Fullscreen Layar penuh - + Modify Citra Install Modifikasi Pemasangan Citra - + Opens the maintenance tool to modify your Citra installation Buka alat perbaikan untuk memodifikasi pemasangan Citra Anda - + Default Default - + Single Screen Layar Tunggal - + Large Screen Layar Besar - + Side by Side Bersebelahan - + Swap Screens Layar Swap - + Check for Updates Periksa Pembaruan - + Report Compatibility Laporkan Kompatibilitas - + Restart Mulai ulang + + + Load... + + + + + Remove + + MicroProfileDialog @@ -3681,23 +3957,23 @@ Screen. - + Connected Terhubung - + Not Connected Tidak Terhubung - + Error Error - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: Gagal menyiarkan ruangan ke lobi publik. Untuk menghost sebuah ruangan secara publik,, anda harus memiliki akun Citra yang valid dan terkonfigurasi di Emulasi-> Konfigurasi -> Web. Jika Anda tidak ingin menyiarkan ruangan ke lobi publik silahkan pilih Tidak Terdaftar. @@ -3816,108 +4092,108 @@ Pesan Debug: %1 Sedang Memainkan %2 - - + + Invalid region Region Tidak Valid - + Japan Jepang - + North America Amerika Utara - + Europe Eropa - + Australia Australia - + China China - + Korea Korea - + Taiwan Taiwan - + Region free Bebas Region - + Invalid Region Region Tidak Valid - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [tidak diatur] - + Hat %1 %2 - + Hat %1%2 - + Axis %1%2 - + Axis %1%2 - + Button %1 - + Tombol %1 - - + + [unknown] [tidak diketahui] - + [unused] [tidak terpakai] - - + + Axis %1 - + Axis %1 diff --git a/dist/languages/it.ts b/dist/languages/it.ts index 7ad040793..b1a2d2adb 100644 --- a/dist/languages/it.ts +++ b/dist/languages/it.ts @@ -70,67 +70,72 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Comando Pica caricato - + Pica command processed Comando Pica eseguito - + Incoming primitive batch Batch primitivo in arrivo - + Finished primitive batch Batch primitivo terminato - + Vertex shader invocation Invocazione vertex shader - + Incoming display transfer Trasferimento display in arrivo - + GSP command processed Comando GSP eseguito - + Buffers swapped Buffer scambiati + + + Unknown debug context event + + CalibrationConfigurationDialog Communicating with the server... - + Comunicando con il server... Cancel - + Annulla Touch the top left corner <br>of your touchpad. - + Tocca l'angolo in alto a sinistra del tuo touchpad. Now touch the bottom right corner <br>of your touchpad. - + Adesso tocca l'angolo in basso a destra del tuo touchpad. @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } Gioco - - + + Block Player Blocca Giocatore - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? Quando blocchi un giocatore, non riceverai più messaggi da quel giocatore.<br><br>Sei sicuro di voler bloccare %1? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected Connesso - + Disconnected Disconnesso - + %1 (%2/%3 members) - connected %1 (%2/%3 membri) - connesso @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! Grazie per la segnalazione! + + + Submitting + + + + + Communication error + + + + + An error occured while sending the Testcase + + + + + Next + + ConfigureAudio @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + %1% @@ -483,17 +508,17 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Select the image flip to apply - + Seleziona il capovolgimento dell'immagine da applicare Flip: - + Rotazione: None - + Nessuna @@ -508,7 +533,7 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Reverse - + Inversa @@ -607,50 +632,78 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere ConfigureDialog - + Citra Configuration Configurazione di Citra - + + + General Generale - + + + System Sistema - + + + Input Input - + + + Graphics Grafica - + + + Audio Audio - + + + Camera Camera - + + + Debug Debug - + + + Web Web + + + + + UI + + + + + Controls + Controlli + ConfigureGeneral @@ -670,64 +723,54 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Conferma uscita con emulazione in corso - - Interface language - Lingua dell'Interfaccia - - - + Updates Aggiornamenti - + Check for updates on start Controlla aggiornamenti all'avvio - + Silently auto update after closing Aggiorna automaticamente dopo la chiusura - + Emulation Emulazione - + Region: Regione: - + Auto-select Selezione automatica - - Theme - Tema - - - - Theme: - Tema: - - - + Hotkeys Hotkey: - - <System> - <System> + + Reset All Settings + - - English - English + + Citra + + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + @@ -766,7 +809,7 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere <html><head/><body><p>Use OpenGL to accelerate rendering.</p><p>Disable to debug graphics-related problem.</p></body></html> - <html><head/><body><p>Usa OpenGL per accellerare il rendering </p><p>Disabilitalo per debuggare problemi grafici + <html><head/><body><p>Usa OpenGL per accellerare il rendering. </p><p>Disabilitalo per il debug di problemi grafici @@ -836,7 +879,7 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere <html><head/><body><p>Use OpenGL to accelerate shader emulation.</p><p>Requires a relatively powerful GPU for better performance.</p></body></html> - + <html><head/><body><p>Attiva OpenGL per accelerare l'emulazione degli shader.</p><p>Necessita di una GPU relativamente potente per prestazioni migliori.</p></body></html> @@ -846,7 +889,7 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere <html><head/><body><p>Correctly handle all edge cases in multiplication operation in shaders. </p><p>Some games requires this to be enabled for the hardware shader to render properly.</p><p>However this would reduce performance in most games.</p></body></html> - + <html><head/><body><p>Gestisce tutti i casi limite nelle operazioni di moltiplicazione degli shaders.</p><p> Alcuni giochi ne necessitano l'attivazione per gli shader hardware così da essere visualizzati nel modo corretto.</p><p>Tuttavia riduce le prestazioni in gran parte dei giochi.</p></body></html> @@ -856,7 +899,7 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere <html><head/><body><p>Force to fall back to software shader emulation when geometry shaders are used. </p><p>Some games require this to be enabled for the hardware shader to render properly.</p><p>However this might reduce performance in some games</p></body></html> - + <html><head/><body><p>Forza l'utilizzo dell'emulazione degli shader via software quando vengono utilizzati dei geometry shaders. </p><p>Alcuni giochi ne necessitano l'attivazione per gli shader hardware così da essere visualizzati nel modo corretto.</p><p>Tuttavia riduce le prestazioni in gran parte dei giochi.</p></body></html> @@ -866,7 +909,7 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere <html><head/><body><p>Use the JIT engine instead of the interpreter for software shader emulation. </p><p>Enable this for better performance.</p></body></html> - + <html><head/><body><p>Utilizza il JIT engine invece dell'interprete per l'emulazione degli shader via software. </p><p>Abilita questa opzione per prestazioni migliori.</p></body></html> @@ -926,7 +969,7 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Hardware Shader support is broken on macOS, and will cause graphical issues like showing a black screen.<br><br>The option is only there for test/development purposes. If you experience graphical issues with Hardware Shader, please turn it off. - + Il supporto degli Shader Hardware non funziona su macOS, e provoca problemi grafici come mostrare una schermata nera.<br><br>L'opzione è presente solo per finalità di test/sviluppo. Se si verifica un problema grafico con lo Shader Hardware, si prega di disattivarlo. @@ -1027,7 +1070,7 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere - + Set Analog Stick Imposta Stick Analogico @@ -1064,15 +1107,48 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Motion / Touch... - + Movimenti / Touch... + Clear All + Rimuovi Tutto + + + Restore Defaults Reimposta Default - + + + Clear + Rimuovi + + + + + [not set] + [non impostato] + + + + + Restore Default + Reimposta valori predefiniti + + + + Information + Informazioni + + + + After pressing OK, first move your joystick horizontally, and then vertically. + Dopo aver premuto OK, muovi il tuo joystick orizzontalmente, e poi verticalmente. + + + [press key] [premi pulsante] @@ -1082,32 +1158,32 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Configure Motion / Touch - + Configura Movimenti / Schermo Touch Motion - + Movimenti Motion Provider: - + Provider dei Movimenti: Sensitivity: - + Sensibilità: Touch - + Touch Touch Provider: - + Provider del Touch: @@ -1117,110 +1193,110 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere (100, 50) - (1800, 850) - + (100, 50) - (1800, 850) Configure - + Configura CemuhookUDP Config - + Configurazione CemuhookUDP You may use any Cemuhook compatible UDP input source to provide motion and touch input. - + Puoi utilizzare qualsiasi input UDP compatibile con Cemuhook per fornire input di movimento e di tocco. Server: - + Server: Port: - + Porta: Pad: - + Pad: Pad 1 - + Pad 1 Pad 2 - + Pad 2 Pad 3 - + Pad 3 Pad 4 - + Pad 4 Learn More - + Per Saperne di Più Test - + Test Mouse (Right Click) - + Mouse (Tasto Destro) CemuhookUDP - + CemuhookUDP Emulator Window - + Finestra di Emulazione <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - + <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Per saperne di più</span></a> Testing - + Prova Configuring - + Configurazione Test Successful - + Prova Riuscita Successfully received data from the server. - + Dati ricevuti con successo dal server. @@ -1230,7 +1306,7 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. - + Impossibile ricevere informazioni valide dal server.<br>Si prega di verificare la corretta configurazione del server insieme alla porta e all'indirizzo forniti. @@ -1240,7 +1316,7 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. - + Test UDP o configurazione della calibrazione in corso.<br>Si prega di attendere fino al loro termine. @@ -1423,35 +1499,45 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Clock - + Orario System Clock - + Orario di Sistema Fixed Time - + Orario Fisso Startup time + Tempo di Avvio + + + + yyyy-MM-ddTHH:mm:ss - + + Play Coins: + Monete di gioco: + + + Console ID: ID Console: - + Regenerate Rigenera - + System settings are available only when game is not running. Le impostazioni del sistema sono disponibili solo quando non è in esecuzione nessun gioco. @@ -1463,42 +1549,42 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Anguilla - + Anguilla Antigua and Barbuda - + Antigua e Barbuda Argentina - + Argentina Aruba - + Aruba Bahamas - + Bahamas Barbados - + Barbados Belize - + Belize Bolivia - + Bolivia @@ -1508,7 +1594,7 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere British Virgin Islands - + Isole Vergini britanniche @@ -1518,87 +1604,87 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Cayman Islands - + Isole Cayman Chile - + Cile Colombia - + Colombia Costa Rica - + Costa Rica Dominica - + Dominica Dominican Republic - + Repubblica Dominicana Ecuador - + Ecuador El Salvador - + El Salvador French Guiana - + Guyana francese Grenada - + Grenada Guadeloupe - + Guadalupa Guatemala - + Guatemala Guyana - + Guyana Haiti - + Haiti Honduras - + Honduras Jamaica - + Giamaica Martinique - + Martinica @@ -1608,62 +1694,62 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Montserrat - + Montserrat Netherlands Antilles - + Antille Olandesi Nicaragua - + Nicaragua Panama - + Panama Paraguay - + Paraguay Peru - + Perù Saint Kitts and Nevis - + Saint Kitts and Nevis Saint Lucia - + Saint Lucia Saint Vincent and the Grenadines - + Saint Vincent e Grenadines Suriname - + Suriname Trinidad and Tobago - + Trinidad e Tobago Turks and Caicos Islands - + Turks e Caicos @@ -1673,17 +1759,17 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Uruguay - + Uruguay US Virgin Islands - + Isole Vergini Americane Venezuela - + Venezuela @@ -2018,92 +2104,92 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Hong Kong - + Hong Kong Macau - + Macao Indonesia - + Indonesia Singapore - + Singapore Thailand - + Tailandia Philippines - + Filippine Malaysia - + Malesia China - + Cina United Arab Emirates - + Emirati Arabi Uniti India - + India Egypt - + Egitto Oman - + Oman Qatar - + Qatar Kuwait - + Kuwait Saudi Arabia - + Arabia Saudita Syria - + Siria Bahrain - + Bahrein Jordan - + Jordan @@ -2121,22 +2207,120 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Bermuda - - + + Console ID: 0x%1 ID Console: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? Questo rimpiazzerà il tuo 3DS virtuale corrente con uno nuovo. Il tuo 3DS virtuale corrente non sarà ripristinabile. Questo potrebbe causare degli effetti inaspettati sui giochi. Potrebbe inoltre fallire, se usi una configurazione di salvataggio datata. Desideri continuare? - + Warning Attenzione + + ConfigureUi + + + Form + + + + + General + + + + + Interface language: + + + + + Theme: + + + + + Game List + + + + + Icon Size: + + + + + + None + + + + + Small (24x24) + + + + + Large (48x48) + + + + + Row 1 Text: + + + + + + File Name + + + + + + Full Path + + + + + + Title Name + + + + + + Title ID + + + + + Row 2 Text: + + + + + Hide Titles without Icon + + + + + <System> + + + + + English + + + ConfigureWeb @@ -2156,7 +2340,7 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere - + Verify Verifica @@ -2213,51 +2397,51 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere Show Current Game in your Discord Status - + Mostra il Gioco Attuale nel tuo Stato di Discord - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Per saperne di più</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Registrati</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">Qual è il mio token?</span></a> - - + + Telemetry ID: 0x%1 ID Telemetria: 0x%1 - + Username and token not verified Nome utente e token non verificati - + Username and token were not verified. The changes to your username and/or token have not been saved. Nome utente e token non verificati. I cambiamenti al tuo nome utente e/o token non sono stati salvati. - + Verifying Verifica in corso - + Verification failed Verifica fallita - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. Verifica fallita. Controlla di aver inserito correttamente il tuo username e token, e che la tua connessione ad internet sia funzionante. @@ -2318,12 +2502,12 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere DirectConnectWindow - + Connecting Connessione in corso - + Connect Connetti @@ -2331,413 +2515,445 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Vengono raccolti dati anonimi </a> per aiutare lo sviluppo di Citra. <br/><br/>Vuoi condividere i tuoi dati di utilizzo con noi? - + Telemetry Telemetria - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Velocità di emulazione corrente. Valori più alti o più bassi di 100% indicano che l'emulazione sta funzionando più velocemente o lentamente di un 3DS. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Quanti frame al secondo il gioco visualizza attualmente. Questo varia da gioco a gioco e da situazione a situazione. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tempo necessario per emulare un frame del 3DS, senza contare il limite al framerate o il v-sync. Per un'emulazione a pieno regime questa dovrebbe essere al più 16.67 ms. - + Clear Recent Files Elimina File Recenti - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available Aggiornamento Disponibile - + An update is available. Would you like to install it now? È disponibile un aggiornamento. Desideri installarlo ora? - + No Update Found Nessun Aggiornamento Disponibile - + No update is found. Non ci sono aggiornamenti. - - + + OpenGL 3.3 Unsupported + + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + + + + + Invalid ROM Format Formato ROM non valido - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + Il formato della ROM non è supportato.<br/>Si prega di seguire le guide per eseguire il redump delle<a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>cartuccie di gioco</a> o dei <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>titoli installati</a>. - + ROM Corrupted ROM Corrotta - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. La tua ROM è corrotta. <br/>Per favore segui le linee guida per riestrarre i tuoi <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>giochi su cartuccia</a> o <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>titoli installati</a>. - + ROM Encrypted ROM Criptata - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + La ROM è criptata.<br/>Si prega di seguire le guide per eseguire il redump delle <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>cartuccie di gioco</a> o dei <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>titoli instalati</a>. - - + + Video Core Error Errore Core Video - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. - + Si è verificato un errore. Per favore <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>guarda il log</a> per maggiori dettagli. Assicurati di avere i più recenti driver grafici per la tua GPU. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. Stai usando i driver di default di Windows per la tua GPU. Devi installare i driver appositi per la tua scheda grafica dal sito del produttore. - + Error while loading ROM! Errore nel caricamento della ROM! - + An unknown error occured. Please see the log for more details. Errore sconosciuto. Visualizza il log per maggiori dettagli. - + Start Avvia - + Error Opening %1 Folder Errore nell'Apertura della Cartella %1 - - + + Folder does not exist! La cartella non esiste! - + Error Opening %1 Errore nell'Apertura di %1 - + Select Directory Seleziona cartella - - 3DS Executable - Eseguibile 3DS + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + - - - All Files (*.*) - Tutti i file (*.*) - - - + Load File Carica file - + Load Files Carica File - + 3DS Installation File (*.CIA*) File di installazione 3DS (*.CIA*) - + + All Files (*.*) + Tutti i file (*.*) + + + %1 has been installed successfully. %1 è stato installato con successo. - + Unable to open File Impossibile aprire il File - + Could not open %1 Impossibile aprire %1 - + Installation aborted Installazione annullata - + The installation of %1 was aborted. Please see the log for more details L'installazione di %1 è stata annullata. Visualizza il log per maggiori dettagli. - + Invalid File File non valido - + %1 is not a valid CIA %1 non è un CIA valido - + Encrypted File File Criptato - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 deve essere decriptato prima di poter essere usato con Citra. E' necessario un 3DS fisico. - + File not found File non trovato - + File "%1" not found File "%1" non trovato - - - + + + Continue Continua - + Missing Citra Account Account di Citra Mancante - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. + Devi collegare il tuo account Citra per inviare dei casi d'esempio. Vai su Emulazione &gt; Configura... &gt; Web per farlo. + + + + Amiibo File (%1);; All Files (*.*) - - - + + Load Amiibo + + + + + + + Record Movie + Registra Filmato + + + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? - - + + Citra TAS Movie (*.ctm) - + Citra TAS Movie (*.ctm) - + Recording will start once you boot a game. - + La registrazione comincerà quando avvierai un gioco. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. - + Revision Dismatch - + Game Dismatch - - + + Invalid Movie File - + File del Filmato Non Valido - + + Play Movie + Riproduci Filmato + + + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? - + Game Not Found - + Gioco Non Trovato - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. - + Movie recording cancelled. - + Registrazione del filmato cancellata. - + Movie Saved - + Filmato Salvato - + The movie is successfully saved. - + Il filmato è stato salvato con successo. - + Speed: %1% / %2% Velocità: %1% / %2% - + Speed: %1% Velocità: %1% - + Game: %1 FPS Gioco: %1 FPS - + Frame: %1 ms Frame: %1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + System Archive Not Found Archivio di Sistema Non Trovato - + Fatal Error Errore fatale - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Abort - - + + Citra Citra - + Would you like to exit now? - + Desideri uscire ora? - + The game is still running. Would you like to stop emulation? - + Playback Completed - + Riproduzione Completata - + Movie playback completed. - + Riproduzione del filmato completata - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2800,37 +3016,67 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere GameList - + + Name + + + + + Compatibility + + + + + Region + + + + + File type + + + + + Size + + + + Open Save Data Location Apri Cartella dei Dati di Salvataggio - + + Open Extra Data Location + + + + Open Application Location Apri Percorso Applicazione - + Open Update Data Location Apri Percorso Dati degli Aggiornamenti - + Navigate to GameDB entry Vai alla voce di GameDB - + Scan Subfolders Controlla le sottocartelle - + Remove Game Directory Rimuovi Cartella - + Open Directory Location Apri Cartella @@ -2838,77 +3084,77 @@ Seleziona da dove l'immagine della fotocamera emulata viene.Potrebbe essere GameListItemCompat - + Perfect - + Perfetto - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great - + Ottimo - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay - + Buono - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. - + Bad - + Scadente - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu - + Intro/Menu - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot - + Non Avviabile - + The game crashes when attempting to startup. - + Not Tested - + Non Testato - + The game has not yet been tested. @@ -2916,35 +3162,35 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the game list - + Fai doppio-click per aggiungere una nuova cartella alla lista giochi GameListSearchField - + of di - + result risultato - + results risultati - + Filter: Filtro: - + Enter pattern to filter @@ -2952,23 +3198,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Breakpoint Pica - - + + Emulation running Emulazione in corso - + Resume Riprendi - + Emulation halted at breakpoint Emulazione arrestata al breakpoint @@ -3351,7 +3597,7 @@ Screen. Public Room Browser - + Navigatore Stanze Pubbliche @@ -3385,42 +3631,42 @@ Screen. Aggiorna Lobby - + Password Required to Join Password Richiesta per Entrare - + Password: Password: - + Room Name Nome Stanza - + Preferred Game Gioco Preferito - + Host Host - + Players Giocatori - + Refreshing Aggiornamento in corso - + Refresh List Aggiorna Lista @@ -3443,220 +3689,245 @@ Screen. File recenti - + + Amiibo + + + + &Emulation &Emulazione - + &View &Visualizza - + Debugging Debugging - + Screen Layout Disposizione schermi - + Movie - + Filmato - + Multiplayer Multigiocatore - + &Help &Aiuto - + Load File... Carica file... - + Install CIA... Installa CIA... - + Load Symbol Map... Carica mappa simboli... - + E&xit &Esci - + &Start &Avvia - + &Pause &Pausa - + &Stop &Stop - + FAQ FAQ - + About Citra Riguardo Citra - + Single Window Mode Modalità finestra singola - + Configure... Configura - + Display Dock Widget Headers Visualizza le intestazioni del dock dei widget - + Show Filter Bar Mosta barra filtri - + Show Status Bar Mostra barra stato - + Select Game Directory... Seleziona cartella dei giochi... - + Selects a folder to display in the game list Seleziona cartella da mostrare nella lista dei giochi - + Create Pica Surface Viewer Crea visualizzatore superficie Pica - + Record Movie - + Registra Filmato - + Play Movie - + Riproduci Filmato - + Stop Recording / Playback + Ferma Registrazione / Riproduzione + + + + Enable Frame Advancing - + + Advance Frame + + + + Browse Public Game Lobby Sfoglia Lobby di Gioco Pubbliche - + Create Room Crea Stanza - + Leave Room Esci dalla Stanza - + Direct Connect to Room Collegamento Diretto alla Stanza - + Show Current Room Mostra Stanza Attuale - + Fullscreen Schermo intero - + Modify Citra Install Modifica Installazione di Citra - + Opens the maintenance tool to modify your Citra installation Accedi allo strumento di manutenzione per modificare la tua Installazione di Citra - + Default Default - + Single Screen Schermo Singolo - + Large Screen Schermo Grande - + Side by Side Affiancati - + Swap Screens Scambia Schermi - + Check for Updates Controlla Aggiornamenti - + Report Compatibility Segnala Compatibilità - + Restart Riavvia + + + Load... + + + + + Remove + + MicroProfileDialog @@ -3682,23 +3953,23 @@ Screen. - + Connected Connesso - + Not Connected Non Connesso - + Error Errore - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: @@ -3816,108 +4087,108 @@ Debug Message: %1 sta giocando a %2 - - + + Invalid region Regione non valida - + Japan Giappone - + North America Nord America - + Europe Europa - + Australia Australia - + China Cina - + Korea Corea - + Taiwan Taiwan - + Region free Region free - + Invalid Region Regione non valida - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [non impostato] - + Hat %1 %2 - + Hat %1 %2 - + Axis %1%2 - + Asse %1%2 - + Button %1 - + Pulsante %1 - - + + [unknown] [sconosciuto] - + [unused] [inutilizzato] - - + + Axis %1 - + Asse %1 diff --git a/dist/languages/ja_JP.ts b/dist/languages/ja_JP.ts index ed372cba1..3f3c974a8 100644 --- a/dist/languages/ja_JP.ts +++ b/dist/languages/ja_JP.ts @@ -70,45 +70,50 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Pica command loaded - + Pica command processed Pica command processed - + Incoming primitive batch Incoming primitive batch - + Finished primitive batch Finished primitive batch - + Vertex shader invocation Vertex shader invocation - + Incoming display transfer Incoming display transfer - + GSP command processed GSP command processed - + Buffers swapped Buffers swapped + + + Unknown debug context event + + CalibrationConfigurationDialog @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } ゲーム - - + + Block Player - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected 接続 - + Disconnected 切断 - + %1 (%2/%3 members) - connected %1 (%2/%3 人) - 接続中 @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! ご報告いただき、ありがとうございました! + + + Submitting + + + + + Communication error + + + + + An error occured while sending the Testcase + + + + + Next + + ConfigureAudio @@ -340,9 +365,9 @@ p, li { white-space: pre-wrap; } - - - %1 % + + %1% + Volume percentage (e.g. 50%) @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration 設定 - + + + General 全般 - + + + System システム - + + + Input 入力 - + + + Graphics グラフィック - + + + Audio サウンド - + + + Camera カメラ - + + + Debug デバッグ - + + + Web Web + + + + + UI + + + + + Controls + + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } エミュレーション停止時に確認 - - Interface language - UIの言語 - - - + Updates 自動更新の設定 - + Check for updates on start Citra起動時に確認 - + Silently auto update after closing Citra終了後に自動更新する - + Emulation エミュレーションに関する設定 - + Region: リージョン(地域)の選択 - + Auto-select 自動 - - Theme - テーマの設定 - - - - Theme: - テーマ選択 - - - + Hotkeys ホットキー - - <System> - <System> + + Reset All Settings + - - English - 英語 + + Citra + + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick アナログスティックを設定する @@ -1067,11 +1110,44 @@ p, li { white-space: pre-wrap; } + Clear All + + + + Restore Defaults ボタン設定の初期化 - + + + Clear + + + + + + [not set] + + + + + + Restore Default + + + + + Information + + + + + After pressing OK, first move your joystick horizontally, and then vertically. + + + + [press key] [キーを入力...] @@ -1440,17 +1516,27 @@ p, li { white-space: pre-wrap; } - + + yyyy-MM-ddTHH:mm:ss + + + + + Play Coins: + + + + Console ID: コンソールID: - + Regenerate コンソールの再作成 - + System settings are available only when game is not running. ゲーム実行中にシステム設定を変更することはできません @@ -2120,13 +2206,13 @@ p, li { white-space: pre-wrap; } - - + + Console ID: 0x%1 コンソール ID: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? 仮想3DSコンソールを新しく作り直します。現在使用中の仮想3DSコンソールを復元することはできず、ゲームに予期しない影響を与えることもあります。 この処理は古い設定のセーブデータが残っていると失敗する可能性があります @@ -2134,11 +2220,109 @@ p, li { white-space: pre-wrap; } それでも続行しますか? - + Warning 警告 + + ConfigureUi + + + Form + + + + + General + + + + + Interface language: + + + + + Theme: + + + + + Game List + + + + + Icon Size: + + + + + + None + + + + + Small (24x24) + + + + + Large (48x48) + + + + + Row 1 Text: + + + + + + File Name + + + + + + Full Path + + + + + + Title Name + + + + + + Title ID + + + + + Row 2 Text: + + + + + Hide Titles without Icon + + + + + <System> + + + + + English + + + ConfigureWeb @@ -2158,7 +2342,7 @@ p, li { white-space: pre-wrap; } - + Verify ユーザー名とトークンの確認 @@ -2218,49 +2402,49 @@ p, li { white-space: pre-wrap; } - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">もっと詳しく</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">ユーザー登録</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">トークンの取得</span></a> - - + + Telemetry ID: 0x%1 テレメトリー ID: 0x%1 - + Username and token not verified ユーザー名とトークンが確認できませんでした - + Username and token were not verified. The changes to your username and/or token have not been saved. ユーザー名とトークンが確認できませんでした 変更は保存されません。 - + Verifying 確認中 - + Verification failed 確認に失敗 - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. 確認に失敗。ユーザー名とトークンが正しく入力されているか、ネット接続が正常に機能しているかの確認をしてください @@ -2321,12 +2505,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting 接続中... - + Connect 接続 @@ -2334,413 +2518,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? - + Telemetry - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. 現在のエミュレーション速度です。100%以外の値は、エミュレーションが3DS実機より高速または低速で行われていることを表します - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. 1秒当たりの表示フレーム数です。ゲームタイトルや場面によって変化することがあります - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. 3DSフレームをエミュレートするのにかかった時間です。フレームリミットや垂直同期の有効時にはカウントしません。フルスピードで動作させるには16.67ms以下に保つ必要があります - + Clear Recent Files - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available - + An update is available. Would you like to install it now? - + No Update Found - + No update is found. - - + + OpenGL 3.3 Unsupported + + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + + + + + Invalid ROM Format - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + ROM Corrupted - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + ROM Encrypted - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - - + + Video Core Error - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. - + Error while loading ROM! ROM読み込みエラー - + An unknown error occured. Please see the log for more details. 不明なエラーが発生しました。詳細はログを確認してください - + Start 開始 - + Error Opening %1 Folder %1 を開く際のエラー - - + + Folder does not exist! フォルダが見つかりません! - + Error Opening %1 - + Select Directory 3DSのROMがあるフォルダを選択 - - 3DS Executable - 3DS 実行可能ファイル + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + - - - All Files (*.*) - すべてのファイル (*.*) - - - + Load File ゲームファイルの読み込み - + Load Files ファイルの読み込み - + 3DS Installation File (*.CIA*) 3DS インストールファイル(.CIA *) - + + All Files (*.*) + すべてのファイル (*.*) + + + %1 has been installed successfully. %1 が正常にインストールされました - + Unable to open File ファイルを開けません - + Could not open %1 %1 を開くことができませんでした - + Installation aborted インストール中止 - + The installation of %1 was aborted. Please see the log for more details %1 のインストールは中断されました。詳細はログを確認してください - + Invalid File 無効なファイル - + %1 is not a valid CIA %1 は有効なCIAではありません - + Encrypted File 暗号化されたファイル - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 は、Citraで使用する前に復号化する必要があります。3DS実機が必要です - + File not found ファイルが見つかりません - + File "%1" not found ファイル "%1" が見つかりませんでした - - - + + + Continue 続行 - + Missing Citra Account Citraアカウントがありません - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. - - - + + Amiibo File (%1);; All Files (*.*) + + + + + Load Amiibo + + + + + + + Record Movie - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + + + + + Citra TAS Movie (*.ctm) - + Recording will start once you boot a game. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. - + Revision Dismatch - + Game Dismatch - - + + Invalid Movie File - + + Play Movie - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + + + + Game Not Found - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. - + Movie recording cancelled. - + Movie Saved - + The movie is successfully saved. - + Speed: %1% / %2% スピード:%1% / %2% - + Speed: %1% スピード:%1% - + Game: %1 FPS ゲーム:%1 FPS - + Frame: %1 ms フレーム:%1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + System Archive Not Found システムアーカイブが見つかりません - + Fatal Error 致命的エラー - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Abort - - + + Citra Citra - + Would you like to exit now? - + The game is still running. Would you like to stop emulation? - + Playback Completed - + Movie playback completed. - + Citra %1 - + Citra %1| %2 @@ -2803,37 +3019,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + + + + + Compatibility + + + + + Region + + + + + File type + + + + + Size + + + + Open Save Data Location セーブデータの保存先を開く - + + Open Extra Data Location + + + + Open Application Location アプリケーションの保存先を開く - + Open Update Data Location アップデータの保存先を開く - + Navigate to GameDB entry 公式ゲームDBで動作状況を確認 - + Scan Subfolders - + Remove Game Directory - + Open Directory Location @@ -2841,77 +3087,77 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. - + Bad - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot - + The game crashes when attempting to startup. - + Not Tested - + The game has not yet been tested. @@ -2919,7 +3165,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the game list @@ -2927,27 +3173,27 @@ Screen. GameListSearchField - + of - + result - + results - + Filter: - + Enter pattern to filter @@ -2955,23 +3201,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Pica Breakpoints - - + + Emulation running Emulation running - + Resume Resume - + Emulation halted at breakpoint Emulation halted at breakpoint @@ -3388,42 +3634,42 @@ Screen. ロビーを更新 - + Password Required to Join パスワードが必要です - + Password: パスワードを入力 - + Room Name 部屋名 - + Preferred Game プレイ希望ゲーム - + Host ホスト - + Players プレイヤー - + Refreshing 更新 - + Refresh List リスト更新 @@ -3446,220 +3692,245 @@ Screen. 最近使ったファイル - + + Amiibo + + + + &Emulation エミュレーション(&E) - + &View 表示(&V) - + Debugging デバッグ - + Screen Layout 画面レイアウト - + Movie - + Multiplayer マルチプレイヤー - + &Help ヘルプ(&H) - + Load File... ファイルを開く... - + Install CIA... CIAのインストール... - + Load Symbol Map... シンボルマップを開く... - + E&xit 終了(&x) - + &Start 開始(&S) - + &Pause 一時停止(&P) - + &Stop 停止(&S) - + FAQ よくある質問 - + About Citra Citraについて - + Single Window Mode シングルウィンドウモード - + Configure... 設定 - + Display Dock Widget Headers Dock Widget ヘッダを表示 - + Show Filter Bar フィルタバーを表示 - + Show Status Bar ステータスバーを表示 - + Select Game Directory... ゲームフォルダの選択 - + Selects a folder to display in the game list ゲームリストに表示するフォルダを選択します - + Create Pica Surface Viewer Create Pica Surface Viewer - + Record Movie - + Play Movie - + Stop Recording / Playback - + + Enable Frame Advancing + + + + + Advance Frame + + + + Browse Public Game Lobby Publicな部屋一覧をブラウズ - + Create Room 新しく部屋を作成 - + Leave Room 退室 - + Direct Connect to Room 指定ルームへ直接接続 - + Show Current Room 現在のルームを表示 - + Fullscreen フルスクリーンで表示 - + Modify Citra Install Citraのインストール形態を変更 - + Opens the maintenance tool to modify your Citra installation Citraのインストール形態を変更するためのメンテナンスツールを開きます - + Default デフォルト - + Single Screen Single Screen - + Large Screen Large Screen - + Side by Side Side by Side - + Swap Screens 画面取替 - + Check for Updates アップデートの確認 - + Report Compatibility レポートの互換性 - + Restart + + + Load... + + + + + Remove + + MicroProfileDialog @@ -3685,23 +3956,23 @@ Screen. - + Connected 接続済 - + Not Connected 未接続 - + Error エラー - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: このルームをPublicな部屋一覧に登録できませんでした。登録するには エミュレーション -> 設定 -> Web で Citraアカウントを設定してください。 Publicな部屋にしたくない場合は「部屋一覧に表示させない(Unlisted)」を選択してください @@ -3820,106 +4091,106 @@ Debug Message: %1 は %2 をプレイ中 - - + + Invalid region 無効なリージョン - + Japan 日本 - + North America 北米 - + Europe ヨーロッパ - + Australia オーストラリア - + China 中国 - + Korea 韓国 - + Taiwan 台湾 - + Region free リージョンフリー - + Invalid Region 無効なリージョン - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [未設定] - + Hat %1 %2 - + Axis %1%2 - + Button %1 - - + + [unknown] [不明] - + [unused] [未使用] - - + + Axis %1 diff --git a/dist/languages/ko_KR.ts b/dist/languages/ko_KR.ts index 65611786e..6906d4b32 100644 --- a/dist/languages/ko_KR.ts +++ b/dist/languages/ko_KR.ts @@ -70,45 +70,50 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Pica command loaded - + Pica command processed Pica command processed - + Incoming primitive batch Incoming primitive batch - + Finished primitive batch Finished primitive batch - + Vertex shader invocation Vertex shader invocation - + Incoming display transfer Incoming display transfer - + GSP command processed GSP command processed - + Buffers swapped Buffers swapped + + + Unknown debug context event + 알 수없는 디버그 컨텍스트 이벤트 + CalibrationConfigurationDialog @@ -171,15 +176,15 @@ p, li { white-space: pre-wrap; } 게임 - - + + Block Player 플레이어 차단 - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? - 플레이어를 차단하면 더 이상 플레이어로부터 채팅 메시지를 받을수 없습니다. <br><br>%을 차단 하시겠습니까? + 플레이어를 차단하면 더 이상 플레이어로부터 채팅 메시지를 받을수 없습니다. <br><br>%1을 차단 하시겠습니까? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected 연결됨 - + Disconnected 연결되지 않음 - + %1 (%2/%3 members) - connected %1 (%2/%3 멤버) - 연결됨 @@ -229,7 +234,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p><span style=" font-size:10pt;">Should you choose to submit a test case to the </span><a href="https://citra-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Citra Compatibility List</span></a><span style=" font-size:10pt;">, The following information will be collected and displayed on the site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware Information (CPU / GPU / Operating System)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Which version of Citra you are running</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The connected Citra account</li></ul></body></html> - <html><head/><body><p><span style=" font-size:10pt;"><a href="https://citra-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Citra 호환성 리스트에</span></a> 제출할 테스트 케이스를 선택해야 합니다</span><span style=" font-size:10pt;">, 다음 정보가 수집되어 사이트에 표시됩니다:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">하드웨어 정보 (CPU/GPU/운영 체제)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">당신이 실행중인 Citra의 버전</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">연결된 Citra 계정</li></ul></body></html> + <html><head/><body><p><span style=" font-size:10pt;"><a href="https://citra-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Citra 호환성 리스트</span></a>에 제출할 테스트 케이스를 선택해야 합니다</span><span style=" font-size:10pt;">. 다음 정보가 수집되어 사이트에 표시됩니다:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">하드웨어 정보 (CPU / GPU / 운영 체제)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">당신이 실행중인 Citra의 버전</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">연결된 Citra 계정</li></ul></body></html> @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! 제출해주셔서 감사합니다! + + + Submitting + + + + + Communication error + + + + + An error occured while sending the Testcase + + + + + Next + + ConfigureAudio @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + %1% @@ -430,7 +455,7 @@ p, li { white-space: pre-wrap; } Select where the image of the emulated camera comes from. It may be an image or a real camera. - 에뮬레이션 된 카메라의 이미지를 가져올 위치를 선택하십시오. 이미지 또는 실제 카메라 일 수 있습니다. + 에뮬레이션되는 카메라의 이미지를 가져올 위치를 선택하십시오. 이미지 또는 실제 카메라일 수 있습니다. @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration Citra 설정 - + + + General 일반 - + + + System 시스템 - + + + Input 입력 - + + + Graphics 그래픽 - + + + Audio 오디오 - + + + Camera 카메라 - + + + Debug 디버그 - + + + Web + + + + + UI + UI + + + + Controls + 컨트롤 + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } 에뮬레이션이 실행되는 동안 종료확인 - - Interface language - 인터페이스 언어 - - - + Updates 업데이트 - + Check for updates on start 시작시 업데이트 확인 - + Silently auto update after closing 종료후 자동으로 업데이트 - + Emulation 에뮬레이션 - + Region: 지역: - + Auto-select 자동 - - Theme - 테마 - - - - Theme: - 테마: - - - + Hotkeys 단축키 - - <System> - <시스템> + + Reset All Settings + - - English - English + + Citra + + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick 아날로그 스틱 설정 @@ -1067,11 +1110,44 @@ p, li { white-space: pre-wrap; } + Clear All + 모두 지우기 + + + Restore Defaults 기본값으로 재설정 - + + + Clear + 지우기 + + + + + [not set] + [설정 안함] + + + + + Restore Default + 기본값으로 재설정 + + + + Information + 정보 + + + + After pressing OK, first move your joystick horizontally, and then vertically. + OK을 누른 후 먼저 조이스틱을 수평으로 이동한 다음 수직으로 이동하세요. + + + [press key] [키 입력] @@ -1440,17 +1516,27 @@ p, li { white-space: pre-wrap; } 시작 시간 - + + yyyy-MM-ddTHH:mm:ss + yyyy-MM-ddTHH:mm:ss + + + + Play Coins: + 플레이 코인: + + + Console ID: 콘솔 ID: - + Regenerate 재생성 - + System settings are available only when game is not running. 시스템 설정은 게임이 실행되고 있지 않을 때만 사용할 수 있습니다. @@ -2077,7 +2163,7 @@ p, li { white-space: pre-wrap; } Qatar - Qatar + 카타르 @@ -2087,7 +2173,7 @@ p, li { white-space: pre-wrap; } Saudi Arabia - Saudi Arabia + 사우디아라비아 @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } 버뮤다 - - + + Console ID: 0x%1 콘솔 ID: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? - 현재 사용하는 가상 3DS를 새로운 시스템으로 교체합니다. 현재 사용하는 가상 3DS는 복구 할 수 없습니다. 이러한 변경은 게임에 예기치 않은 영향을 미칠 수 있습니다. 이 작업은 오래된 Config Savegame를 사용하는 경우 실패할 수 있습니다. 계속하시겠습니까? + 현재 사용하는 가상 3DS를 새로운 시스템으로 교체합니다. 현재 사용하는 가상 3DS는 복구 할 수 없습니다. 이러한 변경은 게임에 예기치 않은 영향을 미칠 수 있습니다. 이 작업은 오래된 Config Savegame을 사용하는 경우 실패할 수 있습니다. 계속하시겠습니까? - + Warning 경고 + + ConfigureUi + + + Form + Form + + + + General + 일반 + + + + Interface language: + 인터페이스 언어: + + + + Theme: + 테마: + + + + Game List + 게임 리스트 + + + + Icon Size: + 아이콘 사이즈: + + + + + None + 없음 + + + + Small (24x24) + 작은 (24x24) + + + + Large (48x48) + 큰 (48x48) + + + + Row 1 Text: + 첫째행 텍스트: + + + + + File Name + 파일 이름 + + + + + Full Path + 전체 경로 + + + + + Title Name + 타이틀 이름 + + + + + Title ID + 타이틀 ID + + + + Row 2 Text: + 둘째행 텍스트: + + + + Hide Titles without Icon + 아이콘이 없는 타이틀 숨기기 + + + + <System> + <시스템> + + + + English + English + + ConfigureWeb @@ -2155,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify 인증 @@ -2215,48 +2399,48 @@ p, li { white-space: pre-wrap; } 디스코드에 실행중인 게임 보이기 - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">자세히 알아보기</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">가입</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">가입</span></a> - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">나의 토큰이 무엇인가요?</span></a> - - + + Telemetry ID: 0x%1 Telemetry ID: 0x%1 - + Username and token not verified 사용자 이름과 토큰이 확인되지 않았습니다 - + Username and token were not verified. The changes to your username and/or token have not been saved. 사용자 이름 및 토큰을 확인하지 못했습니다. 사용자 이름 및 토큰에 대한 변경 내용이 저장되지 않습니다. - + Verifying 확인중 - + Verification failed 인증 실패 - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. 인증에 실패했습니다. 사용자 이름과 토큰을 올바르게 입력했으며 인터넷 연결이 작동하는지 확인하십시오. @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting 연결중 - + Connect 연결 @@ -2330,413 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? Citra를 개선하기위해 <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>익명데이터가 수집됩니다</a>. <br/><br/>사용 데이터를 공유하시겠습니까? - + Telemetry 텔레메트리 - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. 현재 에뮬레이션 속도. 100%보다 높거나 낮은 값은 에뮬레이션이 3DS보다 빠르거나 느린 것을 나타냅니다. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. 게임이 현재 표시하고있는 초당 프레임 수입니다. 이것은 게임마다 다르며 장면마다 다릅니다. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. 3DS 프레임을 에뮬레이션 하는 데 걸린 시간, 프레임제한 또는 v-동기화를 카운트하지 않음. 최대 속도 에뮬레이션의 경우, 이는 최대 16.67 ms여야 합니다. - + Clear Recent Files 최근 파일 삭제 - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available 업데이트가 사용가능합니다 - + An update is available. Would you like to install it now? 업데이트가 존재합니다. 지금 설치할까요? - + No Update Found 업데이트를 찾을 수 없음 - + No update is found. 업데이트를 찾을 수 없습니다. - - + + OpenGL 3.3 Unsupported + OpenGL 3.3이 지원되지않음 + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + GPU가 OpenGL 3.3을 지원하지 않거나 최신 그래픽 드라이버를 가지고 있지 않을 수 있습니다. + + + + Invalid ROM Format 올바르지 않은 롬 포맷 - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. 지원되지 않는 롬 포맷입니다. <br/><a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>게임 카트리지</a>나 <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>설치된 타이틀</a>을 덤프하기위해 가이드를 따르세요 - + ROM Corrupted 롬이 손상되었습니다 - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. 롬이 손상되었습니다. <br/><a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>게임 카트리지</a>나 <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>설치된 타이틀</a>을 덤프하기위해 가이드를 따르세요 - + ROM Encrypted - 롬이 암호화되어 있습니다 + 롬이 암호화되어 있음 - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. 롬이 암호화 되어있습니다. <br/><a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>게임 카트리지</a>나 <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>설치된 타이틀</a>을 덤프하기위해 가이드를 따르세요 - - + + Video Core Error 비디오 코어 에러 - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. 치명적인 오류가 발생했습니다. 자세한 내용은 <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>로그를 확인하십시오</a>. GPU용 최신 그래픽 드라이버가 있는지 확인하십시오. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. GPU의 기본 Windows 드라이버를 실행하고 있습니다. 제조업체의 웹 사이트에서 그래픽 카드에 맞는 드라이버를 설치해야합니다. - + Error while loading ROM! ROM을 로드하는 중 오류가 발생했습니다! - + An unknown error occured. Please see the log for more details. 알 수 없는 오류가 발생했습니다. 자세한 내용은 로그를 참조하십시오. - + Start 시작 - + Error Opening %1 Folder %1 폴더 열기 오류 - - + + Folder does not exist! 폴더가 존재하지 않습니다! - + Error Opening %1 %1 열기 오류 - + Select Directory 디렉토리 선택 - - 3DS Executable - 3DS 실행파일 + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + 3DS 실행파일 (%1);;모든파일 (*.*) - - - All Files (*.*) - 모든파일 (*.*) - - - + Load File 파일 열기 - + Load Files 파일 열기 - + 3DS Installation File (*.CIA*) 3DS 설치파일 (*.CIA*) - + + All Files (*.*) + 모든파일 (*.*) + + + %1 has been installed successfully. %1가 성공적으로 설치되었습니다. - + Unable to open File 파일을 열 수 없음 - + Could not open %1 %1를 열수 없음 - + Installation aborted 설치가 중단됨 - + The installation of %1 was aborted. Please see the log for more details %1의 설치가 중단되었습니다. 자세한 내용은 로그를 참조하십시오. - + Invalid File 올바르지 않은 파일 - + %1 is not a valid CIA %1은 올바른 CIA가 아닙니다 - + Encrypted File 암호화된 파일 - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 은 Citra에서 사용되기전에 디크립트되어야 합니다. 실제 3DS가 필요합니다. - + File not found 파일을 찾을 수 없음 - + File "%1" not found 파일 "%1"을 찾을 수 없음 - - - + + + Continue 계속 - + Missing Citra Account Citra 계정 없음 - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. 테스트를 제출하기 위해서는 Citra계정을 연결해야합니다.<br/>연결하려면 Emulation &gt; Configure... &gt; Web 으로 가세요. - - - + + Amiibo File (%1);; All Files (*.*) + Amiibo 파일 (%1);; 모든파일 (*.*) + + + + Load Amiibo + Amiibo 불러오기 + + + + + + Record Movie 무비 녹화 - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + RNG와의 일관성을 유지하려면 게임 시작시 동영상을 녹화하는 것이 좋습니다. 지금 무비를 녹화하시겠습니까? + + + + Citra TAS Movie (*.ctm) Citra TAS Movie (*.ctm) - + Recording will start once you boot a game. 게임을 부팅할때 레코딩이 시작됩니다. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? 재생하려는 무비파일은 Citra의 다른 리비전에서 만들어 졌습니다. <br/>그동안 Citra에는 많은 변경이 있었고 재생된 내용은 싱크가 맞지않거나 예상과 다르게 작동할 수 있습니다. <br/><br/>정말 무비파일을 여시겠습니까? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? 재생하려는 무비파일은 다른게임으로 부터 녹화되었습니다. <br/>재생은 원하는 결과를 나타내지않거나, 예기치않은 결과를 만들 수 있습니다.<br/><br/> 정말 무비파일을 여시겠습니까? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. 재생하려고 하는 무비파일은 올바르지않습니다. <br/>파일이 손상되었거나 Citra의 무비 모듈에 메이저한 변경이 있었습니다. <br/>다른 무비파일이 선택해서 다시 시도하십시오. - + Revision Dismatch 리비전 불일치 - + Game Dismatch 게임 불일치 - - + + Invalid Movie File 올바르지 않은 무비 파일 - + + Play Movie 무비 재생 - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + RNG와의 일관성을 유지하려면 게임 시작시 동영상을 재생하는 것이 좋습니다.<br>지금 무비를 재생하시겠습니까? + + + Game Not Found 게임을 찾을 수 없음 - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. 재생하려는 무비의 게임이 게임리스트에 존재하지 않습니다. 만약 게임을 가지고 있으면 게임 폴더를 게임 리스트에 추가하고 다시 무비를 플레이하세요 - + Movie recording cancelled. 무비 레코딩이 취소되었습니다. - + Movie Saved 무비 저장됨 - + The movie is successfully saved. 무비가 성공적으로 저장되었습니다. - + Speed: %1% / %2% 속도: %1% / %2% - + Speed: %1% 속도: %1% - + Game: %1 FPS 게임: %1 FPS - + Frame: %1 ms 프레임: %1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. %1이 없습니다. <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>시스템 아카이브를 덤프하십시오</a>.<br/>에뮬레이션을 계속하면 충돌 및 버그가 발생할 수 있습니다. - + System Archive Not Found System Archive를 찾을수 없음 - + Fatal Error 치명적인 에러 - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. 치명적인 오류가 발생했습니다. 자세한 내용은 <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>로그를 확인하십시오</a>. <br/>에뮬레이션을 계속하면 충돌과 버그가 발생할 수 있습니다. - + Abort 중단 - - + + Citra Citra - + Would you like to exit now? 지금 종료하시겠습니까? - + The game is still running. Would you like to stop emulation? 게임이 아직 작동중입니다. 에뮬레이션을 정지할까요? - + Playback Completed 재생 완료 - + Movie playback completed. 무비 재생 완료 - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2799,37 +3015,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + 이름 + + + + Compatibility + 호환성 + + + + Region + 지역 + + + + File type + 파일 타입 + + + + Size + 크기 + + + Open Save Data Location 세이브 데이터 위치 열기 - + + Open Extra Data Location + Extra Date 위치 열기 + + + Open Application Location 어플리케이션 위치 열기 - + Open Update Data Location 업데이트 데이터 위치 열기 - + Navigate to GameDB entry GameDB 엔트리로 이동 - + Scan Subfolders 서브 디렉토리 스캔 - + Remove Game Directory 게임 디렉토리 삭제 - + Open Directory Location 디렉토리 위치 열기 @@ -2837,81 +3083,81 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect 완벽함 - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. 오디오 또는 그래픽 글리치가 없이 게임이 완벽하게 작동하며, 테스트된 모든 기능이 특별한 해결방안 없이 의도대로 작동합니다. - + Great 좋음 - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. 게임은 사소한 그래픽문제나 오디오 글리치와 함께 처음부터 끝까지 진행가능합니다. 몇가지 해결방안이 필요할 수 있습니다. - + Okay 양호 - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. 게임은 주요 그래픽문제나 오디오 글리치와 함께 처음부터 끝까지 진행가능합니다. 몇가지 해결방안이 필요할 수 있습니다. - + Bad 나쁨 - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. 게임은 작동하지만 주요 그래픽이나 오디오 글리치가 있습니다. 특별한 해결방안에도 불구하고 특정한 지역에서 글리치로 인해 진행이 불가능합니다 - + Intro/Menu 인트로/메뉴 - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. 주요 그래픽 또는 오디오 결함으로 인해 게임을 완전히 재생할 수 없습니다. 시작화면을 지날 수 없습니다 - + Won't Boot 실행불가 - + The game crashes when attempting to startup. 시작할 때 게임이 충돌합니다. - + Not Tested 테스트되지 않음 - + The game has not yet been tested. 이 게임은 아직 테스트되지 않았습니다. @@ -2919,7 +3165,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the game list 더블 클릭하여 게임 목록에 새 폴더 추가 @@ -2927,27 +3173,27 @@ Screen. GameListSearchField - + of - + result 결과 - + results 결과 - + Filter: 필터: - + Enter pattern to filter 검색 필터 입력 @@ -2955,23 +3201,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Pica Breakpoints - - + + Emulation running 에뮬레이션 실행중 - + Resume Resume - + Emulation halted at breakpoint 에뮬레이션이 브레이크포인트에서 정지했습니다 @@ -3388,42 +3634,42 @@ Screen. 로비 새로고침 - + Password Required to Join 참가시 비밀번호 필요 - + Password: 비밀번호: - + Room Name 방 이름 - + Preferred Game 선호되는 게임 - + Host 호스트 - + Players 플레이어 - + Refreshing 새로고침중 - + Refresh List 리스트 새로고침 @@ -3446,220 +3692,245 @@ Screen. 최근 파일 - + + Amiibo + 아미보 + + + &Emulation 에뮬레이션(&E) - + &View 보기(&V) - + Debugging 디버깅 - + Screen Layout 스크린 레이아웃 - + Movie 무비 - + Multiplayer 멀티플레이어 - + &Help 도움말(&H) - + Load File... 파일 열기... - + Install CIA... CIA 설치... - + Load Symbol Map... Symbol Map 열기... - + E&xit 종료(&X) - + &Start 시작(&S) - + &Pause 일시중지(&P) - + &Stop 정지(&S) - + FAQ FAQ - + About Citra Citra에 대하여 - + Single Window Mode 싱글 윈도우 모드 - + Configure... 설정... - + Display Dock Widget Headers Dock 위젯 보이기 - + Show Filter Bar 필터바 보이기 - + Show Status Bar 스테이스바 보이기 - + Select Game Directory... 게임 디렉토리 선택... - + Selects a folder to display in the game list 게임 리스트를 보여줄 디렉토리 선택 - + Create Pica Surface Viewer Pica Surface Viewer 생성 - + Record Movie 무비 녹화 - + Play Movie 무비 재생 - + Stop Recording / Playback 레코딩 / 재생 정지 - + + Enable Frame Advancing + 프레임 전진 사용 + + + + Advance Frame + 프레임 전진 + + + Browse Public Game Lobby 공개 방 찾아보기 - + Create Room 방 만들기 - + Leave Room 방 나가기 - + Direct Connect to Room 방에 직접 연결 - + Show Current Room 현재 방 보이기 - + Fullscreen 전체화면 - + Modify Citra Install Citra 설치 변경 - + Opens the maintenance tool to modify your Citra installation Citra 설치 변경을 위한 유지보수 도구 열기 - + Default 기본 - + Single Screen 단일화면 - + Large Screen 큰 화면 - + Side by Side 좌우화면 (Side by Side) - + Swap Screens 스크린 바꾸기 - + Check for Updates 업데이트 체크 - + Report Compatibility 호환성 보고하기 - + Restart 재시작 + + + Load... + 열기... + + + + Remove + 제거 + MicroProfileDialog @@ -3685,23 +3956,23 @@ Screen. - + Connected 연결됨 - + Not Connected 연결되지 않음 - + Error 오류 - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: 공개로비에 방을 알리는데 실패했습니다. 방을 공개적으로 호스트하기 위해서는 에뮬레이션 -> 설정 -> 웹 에서 유효한 Citra 계정을 설정해야합니다. @@ -3820,108 +4091,108 @@ Debug Message: %1은 %2를 플레이중입니다 - - + + Invalid region 올바르지 않은 지역 - + Japan 일본 - + North America 북미 - + Europe 유럽 - + Australia 호주 - + China 중국 - + Korea 한국 - + Taiwan 대만 - + Region free 지역해제 - + Invalid Region 올바르지 않은 지역 - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [설정 안함] - + Hat %1 %2 - + 방향키 %1 %2 - + Axis %1%2 - + Axis %1%2 - + Button %1 - + 버튼 %1 - - + + [unknown] [알수없는] - + [unused] [사용되지않음] - - + + Axis %1 - + Axis %1 diff --git a/dist/languages/lt_LT.ts b/dist/languages/lt_LT.ts index ef6ee7491..5ce48fd00 100644 --- a/dist/languages/lt_LT.ts +++ b/dist/languages/lt_LT.ts @@ -70,45 +70,50 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded „Pica“ komanda įkrauta - + Pica command processed „Pica“ komanda apdorota - + Incoming primitive batch Įeinanti primityvi partija - + Finished primitive batch Primityvi partija užbaigta - + Vertex shader invocation Vertekso šešėliuoklės iškvietimas - + Incoming display transfer Įeinantis vaizdo perdavimas - + GSP command processed GSP komanda apdorota - + Buffers swapped Buferiai apkeisti + + + Unknown debug context event + Nežinomas derinimo konteksto įvykis + CalibrationConfigurationDialog @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } Žaidimas - - + + Block Player Užblokuoti žaidėją - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? Kai jūs užblokuosite žaidėją, jūs nebegausite naujų pranešimų nuo jo. <br><br>Ar tikrai norite užblokuoti %1? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected Prisijungta - + Disconnected Atsijungta - + %1 (%2/%3 members) - connected %1 (%2/%3 vartotojai) - prisijungta @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! Ačiū už jūsų pateikimą! + + + Submitting + Pateikiama + + + + Communication error + Komunikacijos klaida + + + + An error occured while sending the Testcase + Klaida siunčiant suderinamumo pateiktį + + + + Next + Kitas + ConfigureAudio @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + %1% @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration „Citra“ konfigūracija - + + + General Pagrindinis - + + + System Sistema - + + + Input Įvestis - + + + Graphics Grafika - + + + Audio Garsas - + + + Camera Kamera - + + + Debug Derinimas - + + + Web Tinklo tarnyba + + + + + UI + NS (naudotojo sąsaja) + + + + Controls + Valdymas + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } Patvirtinti išėjimą veikiant emuliacijai - - Interface language - Sąsajos kalba - - - + Updates Atnaujinimai - + Check for updates on start Paieškoti atnaujinimų paleidžiant programą - + Silently auto update after closing Tyliai atsinaujinti išjungus programą - + Emulation Emuliacija - + Region: Regionas: - + Auto-select Automatiškai pasirinkti - - Theme - Tema - - - - Theme: - Tema: - - - + Hotkeys Spartieji klavišai - - <System> - <System> + + Reset All Settings + Atstatyti visus nustatymus - - English - Anglų + + Citra + „Citra“ + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + Ar tikrai norite <b>atstatyti jūsų nustatymus</b>ir uždaryti „Citra“? @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick Nustatyti analoginį valdiklį @@ -1067,11 +1110,44 @@ p, li { white-space: pre-wrap; } + Clear All + Išvalyti viską + + + Restore Defaults Atkurti numatytuosius - + + + Clear + Išvalyti + + + + + [not set] + [nenustatyta] + + + + + Restore Default + Atkurti numatytuosius + + + + Information + Informacija + + + + After pressing OK, first move your joystick horizontally, and then vertically. + Kai paspausite OK, pajudinkite savo valdiklio lazdelę horizontaliai, ir paskui vertikaliai. + + + [press key] [paspauskite klavišą] @@ -1440,17 +1516,27 @@ p, li { white-space: pre-wrap; } Užkrovimo laikas - + + yyyy-MM-ddTHH:mm:ss + metai-MĖNESIAI-dienaTVALANDA:minutė:sekundė + + + + Play Coins: + Žaidimų pinigų kiekis: + + + Console ID: Konsolės ID: - + Regenerate Regeneruoti - + System settings are available only when game is not running. Sistemos nustatymai yra prieinami, tik kai žaidimai nepaleisti. @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } Bermudai - - + + Console ID: 0x%1 Konsolės ID: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? Tai pakeis jūsų dabartinį virtualų 3DS nauju. Jūsų dabartinis virtualus 3DS bus nebeatkuriamas. Tai gali padaryti netikėtų pokyčių žaidimuose. Tęsti? - + Warning Įspėjimas + + ConfigureUi + + + Form + Forma + + + + General + Pagrindinis + + + + Interface language: + Sąsajos kalba: + + + + Theme: + Tema: + + + + Game List + Žaidimų sąrašo nustatymai + + + + Icon Size: + Žaidimo paveikslėlio dydis: + + + + + None + Nėra + + + + Small (24x24) + Mažas (24x24) + + + + Large (48x48) + Didelis (48x48) + + + + Row 1 Text: + 1 eilutės tekstas: + + + + + File Name + Failo pavadinimas + + + + + Full Path + Pilnas adresas + + + + + Title Name + Programos pavadinimas + + + + + Title ID + Programos ID + + + + Row 2 Text: + 2 eilutės tekstas: + + + + Hide Titles without Icon + Paslėpti programas be paveikslėlio + + + + <System> + <System> + + + + English + Anglų k. + + ConfigureWeb @@ -2155,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify Patikrinti @@ -2215,48 +2399,48 @@ p, li { white-space: pre-wrap; } Rodyti jūsų žaidžiamą žaidimą Discord'e - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Sužinoti daugiau</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Užsiregistruoti</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Užsiregistruoti</span></a> - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">Koks yra mano simbolinis ID?</span></a> - - + + Telemetry ID: 0x%1 Telemetrijos ID: 0x%1 - + Username and token not verified Vartotojo vardas ir simbolinis ID nėra patikrinti - + Username and token were not verified. The changes to your username and/or token have not been saved. Vartotojo vardas ir simbolinis ID nebuvo patikrinti. Pakeitimai nebuvo išsaugoti. - + Verifying Tikrinama - + Verification failed Tikrinimas nepavyko - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. Tikrinimas nepavyko. Įsitikinkite, ar įvedėte duomenis teisingai ir kad jūsų interneto ryšys veikia. @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting Jungiamasi - + Connect Prisijungti @@ -2330,413 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anoniminiai duomenys yra renkami </a> kad padėtumėte Citra komandai. <br/><br/>Ar norite pasidalinti savo duomenimis su mumis? - + Telemetry Telemetrija - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Dabartinės emuliacijos greitis. Reikšmės žemiau ar aukščiau 100% parodo, kad emuliacija veikia greičiau ar lėčiau negu 3DS. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Kiek FPS žaidimas šiuo metu atvaizduoja. Tai gali keistis nuo žaidimo ir scenos. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Laikas, kuris buvo sunaudotas atvaizduoti 1 3DS kadrą, neskaičiuojant FPS ribojimo ar V-Sync. Pilno greičio emuliacijai reikalinga daugiausia 16.67 ms reikšmė. - + Clear Recent Files Pravalyti neseniai įkrautus failus - + F9 F9 - + F10 F10 - + CTRL+F Ctrl+F - + Update Available Pasiekiamas atnaujinimas - + An update is available. Would you like to install it now? Atnaujinimas yra pasiekiamas. Ar dabar norite jį įdiegti? - + No Update Found Atnaujinimų nerasta - + No update is found. Atnaujinimų nerasta - - + + OpenGL 3.3 Unsupported + OpenGL 3.3 nepalaikomas + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + Jūsų vaizdo plokštė nepalaiko OpenGL 3.3, arba neturite naujausių vaizdo tvarkyklių. + + + + Invalid ROM Format Klaidingas ROM formatas - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Jūsų ROM formatas yra nepalaikomas.<br/>Prašome pasižiūrėti į mūsų gidus kaip iškopijuoti jūsų <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>žaidimų plokšteles</a>arba <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>suinstaliuotus žaidimus</a>. - + ROM Corrupted Pažeistas ROM failas - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Jūsų ROM failas yra pažeistas.<br/>Prašome pasižiūrėti į mūsų gidus kaip iškopijuoti jūsų<a href='https://citra-emu.org/wiki/dumping-game-cartridges/'> žaidimų plokšteles</a>arba<a href='https://citra-emu.org/wiki/dumping-installed-titles/'> suinstaliuotus žaidimus</a>. - + ROM Encrypted Užšifruotas ROM failas - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Jūsų ROM failas yra užšifruotas. <br/>Prašome pasižiūrėti į mūsų gidus kaip iškopijuoti jūsų <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>žaidimų plokšteles</a>arba <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>suinstaliuotus žaidimus</a>. - - + + Video Core Error Vaizdo atkūrimo klaida - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. Įvyko klaida. Prašome <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>pasižiūrėti į žurnalą</a>dėl daugiau informacijos. Įsitinkite, ar turite naujausias vaizdo tvarkykles jūsų vaizdo plokštei. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. Jūs turite numatytasias Windows tvarkykles jūsų vaizdo plokštei. Jums reikia įdiegti tikrasias tvarkykles jūsų vaizdo plokštei iš gamintojo internetinio puslapio. - + Error while loading ROM! Klaida įkraunant atvaizdą! - + An unknown error occured. Please see the log for more details. Įvyko nežinoma klaida. Pasižiūrėkite į žurnalą dėl daugiau informacijos. - + Start Pradėti - + Error Opening %1 Folder Klaida atidarant %1 aplanką - - + + Folder does not exist! Aplankas neegzistuoja! - + Error Opening %1 Klaida atidarant %1 - + Select Directory Pasirinkti katalogą - - 3DS Executable - 3DS taik. programa + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + 3DS programa (%1);;Visi failai (*.*) - - - All Files (*.*) - Visi failai (*.*) - - - + Load File Įkrauti failą - + Load Files Įkrauti failus - + 3DS Installation File (*.CIA*) 3DS instaliacijos failas (*.cia*) - + + All Files (*.*) + Visi failai (*.*) + + + %1 has been installed successfully. %1 buvo įdiegtas sėkmingai. - + Unable to open File Negalima atverti failo - + Could not open %1 Nepavyko atverti %1 - + Installation aborted Instaliacija nutraukta - + The installation of %1 was aborted. Please see the log for more details Failo %1 instaliacija buvo nutraukta. Pasižiūrėkite į žurnalą dėl daugiau informacijos - + Invalid File Klaidingas failas - + %1 is not a valid CIA %1 nėra tinkamas CIA - + Encrypted File Šifruotas failas - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 turi būti iššifruotas prieš naudojant jį su „Citra“. Tikra 3DS konsolė yra būtina. - + File not found Failas nerastas - + File "%1" not found Failas "%1" nerastas - - - + + + Continue Tęsti - + Missing Citra Account Nėra „Citra“ paskyros - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. Jūs turite prijungti jūsų Citra vartotoją prieš pateikiant suderinamumą. <br/>Eikite į Emuliacija &gt; Konfigūruoti... &gt; Tinklo tarnyba. - - - + + Amiibo File (%1);; All Files (*.*) + „Amiibo“ failas (%1);; Visi failai (*.*) + + + + Load Amiibo + Įkrauti „Amiibo“ + + + + + + Record Movie Įrašyti įvesčių vaizdo įrašą - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + Laikantis įvairių numerių generatoriaus taisyklių, rekomenduojama pradėti įrašinėti įvestis nuo žaidimo paleisties.<br>Ar tikrai norite pradėti įrašinėti įvestis dabar? + + + + Citra TAS Movie (*.ctm) Citra TAS vaizdo įrašas (*.ctm) - + Recording will start once you boot a game. Įrašymas prasidės kai įkrausite žaidimą. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? - + Šis įvesčių įrašas buvo sukurtas senesnėje „Citra“ versijoje.<br/>„Citra“ turėjo pakeitimų, ir įrašas gali atitrūkinėti arba neveikti.<br/><br/>Ar tikrai norite įkrauti šį įrašą? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? - + Šis įvesčių įrašas buvo sukurtas kitame žaidime.<br/>Įrašas gali veikti netikėtai.<br/><br/>Ar tikrai norite įkrauti šį įrašą? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. - + Šis įvesčių įrašas yra klaidingas.<br/>Failas yra pažeistas arba „Citra“ turėjo didelių pakitimų įrašų modulyje. <br/>Prašome pasirinkti kitą įrašo failą ir pabandyti iš naujo. - + Revision Dismatch Revizijų nesutapimas - + Game Dismatch - + Žaidimų nesutapimas - - + + Invalid Movie File Klaidingas filmo failas - + + Play Movie Paleisti filmą - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + Laikantis įvairių numerių generatoriaus taisyklių, rekomenduojama paleisti įrašą nuo žaidimo paleisties.<br>Ar tikrai norite paleisti įvestį dabar? + + + Game Not Found Žaidimas nerastas - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. - + Įrašas, kurį bandote paleisti, nėra iš žaidimų, kuriuos turite savo žaidimų sąraše. Prašome įtraukti savo žaidimų aplanką į sąrašą ir pabandyti iš naujo. - + Movie recording cancelled. - + Įrašo įrašymas nutrauktas. - + Movie Saved - + Įrašas išsaugotas - + The movie is successfully saved. Filmas sėkmingai išsaugotas. - + Speed: %1% / %2% Greitis: %1% / %2% - + Speed: %1% Greitis: %1% - + Game: %1 FPS Žaidimas: %1 FPS - + Frame: %1 ms Kadras: %1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + Trūksta %1. Prašome <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>iškopijuoti sisteminius archyvus</a>. <br/>Jeigu tęsite emuliaciją, gali įvykti netikėtų išsijungimų ir klaidų. - + System Archive Not Found Sisteminis archyvas nerastas - + Fatal Error Nepataisoma klaida - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. Įvyko nepataisoma klaida. Prašome <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>pasižiūrėti į žurnalą</a>dėl daugiau informacijos. Jeigu tęsite emuliaciją, gali įvykti netikėtų išsijungimų ir riktų. - + Abort - + Nutraukti - - + + Citra „Citra“ - + Would you like to exit now? - + Ar norite išeiti? - + The game is still running. Would you like to stop emulation? - + Žaidimas vis dar veikia. Ar norite sustabdyti emuliaciją? - + Playback Completed - + Atkūrimas užbaigtas - + Movie playback completed. - + Įrašo atkūrimas užbaigtas. - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2799,37 +3015,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + Pavadinimas + + + + Compatibility + Suderinamumas + + + + Region + Regionas + + + + File type + Failo tipas + + + + Size + Dydis + + + Open Save Data Location Atidaryti išsaugojimo duomenų vietą - + + Open Extra Data Location + Atidaryti papildomų duomenų vietą + + + Open Application Location Atidaryti programos vietą - + Open Update Data Location Atidaryti atnaujinimo duomenų vietą - + Navigate to GameDB entry Eiti į suderinamumo puslapį - + Scan Subfolders Ieškoti poaplankius - + Remove Game Directory Pašalinti žaidimo katalogą - + Open Directory Location Atidaryti katalogo vietą @@ -2837,85 +3083,85 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect - + Tobulas - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Žaidimas veikia nuostabiai be jokių garso ar vaizdo trikdžių, visos išbandytos funkcijos veikia kaip numatyta be problemų apėjimų. - + Great - + Puikus - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Žaidimas veikia su smulkiais garso arba vaizdo trikdžiais ir gali būti pereitas nuo pradžios iki galo. Gali reikalauti keleto problemų apėjimų. - + Okay - + Geras - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. - + Žaidimas veikia su dideliais garso arba vaizdo trikdžiais, bet žaidimas gali būti pereitas nuo pradžios iki galo su problemų apėjimais. - + Bad - + Blogas - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Žaidimas veikia, bet su dideliais garso arba vaizdo trikdžiais. Neįmanoma pereiti keleto vietų net su problemų apėjimais. - + Intro/Menu - + Rodo tik pradžios ekraną - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Žaidimas yra visiškai negalimas žaisti dėl didelių garso ar vaizdo trikdžių. Neįmanoma pratęsti žaidimo toliau negu pradžios ekranas. - + Won't Boot - + Nepasileidžia - + The game crashes when attempting to startup. - + Žaidimas netikėtai išsijungia pasileidžiant. - + Not Tested - + Netestuota - + The game has not yet been tested. - + Žaidimas dar nebuvo išbandytas. GameListPlaceholder - + Double-click to add a new folder to the game list Paspauskite dukart kad pridėtumėte naują katalogą žaidimų sąraše @@ -2923,27 +3169,27 @@ Screen. GameListSearchField - + of - + result rezultatų - + results rezultatai - + Filter: Filtras: - + Enter pattern to filter Įveskite raktinius žodžius filtravimui @@ -2951,23 +3197,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints „Pica“ nutrūkimo taškai - - + + Emulation running Emuliacija veikia - + Resume Pratęsti - + Emulation halted at breakpoint Emuliacija sustabdyta nutrūkimo taške @@ -3342,7 +3588,7 @@ Screen. Toggle LLE Service Modules - + Įjungti žemo lygio emuliacijos sisteminius modulius @@ -3384,42 +3630,42 @@ Screen. Atnaujinti sąrašą - + Password Required to Join Reikalingas slaptažodis - + Password: Slaptažodis: - + Room Name Serverio pavadinimas - + Preferred Game Pageidautinas žaidimas - + Host Vartotojas - + Players Žaidėjų skaičius - + Refreshing Atnaujinama - + Refresh List Atnaujinti sąrašą @@ -3442,219 +3688,244 @@ Screen. Neseniai įkrauti failai - + + Amiibo + „Amiibo“ + + + &Emulation &Emuliacija - + &View &Žiūrėti - + Debugging Derinimas - + Screen Layout Ekranų išdėstymas - + Movie Įvesčių įrašai - + Multiplayer Kelių žaidėjų režimas - + &Help &Pagalba - + Load File... Įkrauti failą... - + Install CIA... Diegti CIA... - + Load Symbol Map... Įkrauti simbolių žemėlapį... - + E&xit Į&šeiti - + &Start &Pradėti - + &Pause &Pauzė - + &Stop &Sustabdyti - + FAQ DUK - + About Citra Apie „Citra“ - + Single Window Mode Vieno lango režimas - + Configure... Konfigūruoti... - + Display Dock Widget Headers Rodyti ikonėles apačioje - + Show Filter Bar Rodyti paieškos juostą - + Show Status Bar Rodyti būsenos juostą - + Select Game Directory... Pasirinkti žaidimo katalogą... - + Selects a folder to display in the game list Pasirenka aplanką, kuris rodomas žaidimų saraše - + Create Pica Surface Viewer Sukurti „Pica“ pagrindo žiūryklę - + Record Movie Įrašyti įvesčių vaizdo įrašą - + Play Movie Paleisti įvesčių vaizdo įrašą - + Stop Recording / Playback - + Sustabdyti įrašymą / atkūrimą - + + Enable Frame Advancing + Įjungti kadro perėjimą + + + + Advance Frame + Pereiti į kitą kadrą + + + Browse Public Game Lobby Peržiūrėti viešus žaidimų serverius - + Create Room Sukurti serverį - + Leave Room Palikti serverį - + Direct Connect to Room Tiesioginis prisijungimas prie serverio - + Show Current Room Rodyti dabartinį serverį - + Fullscreen Per visą ekraną - + Modify Citra Install Modifikuoti „Citra“ instaliaciją - + Opens the maintenance tool to modify your Citra installation Atidaro priežiūros įrankį modifikuoti jūsų „Citra“ instaliaciją - + Default Numatytasis - + Single Screen Vienas ekranas - + Large Screen Didelis ekranas - + Side by Side Vienas prie kito šonu - + Swap Screens Apkeisti ekranus - + Check for Updates Tikrinti, ar yra naujinimų - + Report Compatibility Pranešti suderinamumą - + Restart - + Persirauti + + + + Load... + Įkrauti... + + + + Remove + Pašalinti @@ -3681,23 +3952,23 @@ Screen. - + Connected Prisijungta - + Not Connected Neprisijungta - + Error Klaida - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: Nepavyko paskelbti serverio viešai. Norint paskelbti viešai jus privalote turėti tinkamą „Citra“ paskyrą, sukonfigūruotą Emuliacija -> Konfigūruoti -> Tinklo tarnyba. Jeigu nenorite kurti serverio viešai, pasirinkite Nematomas. @@ -3816,108 +4087,108 @@ Derinimo pranešimas: %1 žaidžia %2 - - + + Invalid region Klaidingas regionas - + Japan Japonija - + North America Šiaurės Amerika - + Europe Europa - + Australia Australija - + China Kinija - + Korea Korėja - + Taiwan Taivanas - + Region free Be regiono - + Invalid Region Klaidingas regionas - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [nenustatytas] - + Hat %1 %2 - + Pusė %1 %2 - + Axis %1%2 - + Ašis %1%2 - + Button %1 - + Mygtukas %1 - - + + [unknown] [nežinomas] - + [unused] [nenaudojamas] - - + + Axis %1 - + Ašis %1 diff --git a/dist/languages/nb.ts b/dist/languages/nb.ts index 4091a8785..2a48ef264 100644 --- a/dist/languages/nb.ts +++ b/dist/languages/nb.ts @@ -70,77 +70,82 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Pica kommando lastet - + Pica command processed Pica kommandoen behandlet - + Incoming primitive batch Innkommende primitiv batch - + Finished primitive batch Ferdigstilt primitiv batch - + Vertex shader invocation Vertex shader påkalling - + Incoming display transfer Innkommende skjermoverføring - + GSP command processed GSP kommando behandlet - + Buffers swapped Buffere byttet + + + Unknown debug context event + + CalibrationConfigurationDialog Communicating with the server... - + Kommuniserer med serveren... Cancel - + Avbryt Touch the top left corner <br>of your touchpad. - + Trykk på øverste venstre hjørne<br>på styreflaten din. Now touch the bottom right corner <br>of your touchpad. - + Nå berør nederste høyre hjørne <br>på styreflaten. Configuration completed! - + Konfigurasjon fullført! OK - + OK @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } Spill - - + + Block Player Blokker Spiller - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? Når du blokkerer en spiller, vil du ikke lenger motta chatmeldinger fra dem.<br><br>Er du sikker på at du vil blokkere %1? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected Tilkoblet - + Disconnected Frakoblet - + %1 (%2/%3 members) - connected %1 (%2/%3 medlemmer) - tilkoblet @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! Takk for ditt bidrag! + + + Submitting + + + + + Communication error + + + + + An error occured while sending the Testcase + + + + + Next + + ConfigureAudio @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration Citra Konfigurasjon - + + + General Generelt - + + + System System - + + + Input Inngang - + + + Graphics Grafikk - + + + Audio Lyd - + + + Camera Kamera - + + + Debug Debug - + + + Web Web + + + + + UI + + + + + Controls + + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } Bekreft avslutting mens emuleringen kjører - - Interface language - Grensesnittspråk - - - + Updates Oppdateringer - + Check for updates on start Se etter oppdateringer ved start - + Silently auto update after closing Stille automatisk oppdatering etter avslutning - + Emulation Emulering - + Region: Region - + Auto-select Auto-Velg - - Theme - Tema - - - - Theme: - Tema - - - + Hotkeys Hurtigtaster - - <System> - <System> + + Reset All Settings + - - English - Engelsk + + Citra + + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick Still Analog Stick @@ -1063,15 +1106,48 @@ p, li { white-space: pre-wrap; } Motion / Touch... - + Bevegelse / Berøring... + Clear All + + + + Restore Defaults Gjenopprett Standardinnstillinger - + + + Clear + + + + + + [not set] + + + + + + Restore Default + + + + + Information + + + + + After pressing OK, first move your joystick horizontally, and then vertically. + + + + [press key] [trykk på tast] @@ -1081,165 +1157,165 @@ p, li { white-space: pre-wrap; } Configure Motion / Touch - + Konfigurer Bevegelse / Berøring Motion - + Bevegelse Motion Provider: - + Bevegelses leverandør: Sensitivity: - + Sensitivitet: Touch - + Berøring Touch Provider: - + Berørings Leverandør: Calibration: - + Kalibrering: (100, 50) - (1800, 850) - + (100, 50) - (1800, 850) Configure - + Konfigurer CemuhookUDP Config - + CemuhookUDP Konfigurasjon You may use any Cemuhook compatible UDP input source to provide motion and touch input. - + Du kan bruke en hvilken som helst Cemuhook kompatibel UDP inngangskilde for å gi bevegelse og berørings inngang. Server: - + Server: Port: - + Port: Pad: - + Pad: Pad 1 - + Pad 1 Pad 2 - + Pad 2 Pad 3 - + Pad 3 Pad 4 - + Pad 4 Learn More - + Lær Mer Test - + Test Mouse (Right Click) - + Mus (Høyre Klikk) CemuhookUDP - + CemuhookUDP Emulator Window - + Emulator Vindu <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - + <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Lær Mer</span></a> Testing - + Testing Configuring - + Konfigurerer Test Successful - + Test Vellykket Successfully received data from the server. - + Mottatt data fra serveren vellykket. Test Failed - + Test Mislyktes Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. - + Kunne ikke motta gyldige data fra serveren.<br>Kontroller at serveren er riktig konfigurert, og adressen og porten er riktige. Citra - + Citra UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. - + UDP Test eller kalibreringskonfigurasjon pågår.<br>Vennligst vent på at de skal fullføre. @@ -1422,35 +1498,45 @@ p, li { white-space: pre-wrap; } Clock - + Klokke System Clock - + System Klokke Fixed Time - + Bestemt Tid Startup time + Oppstartstid + + + + yyyy-MM-ddTHH:mm:ss - + + Play Coins: + + + + Console ID: Konsoll ID: - + Regenerate Regenerere - + System settings are available only when game is not running. System innstillingene er ikke tilgjengelig når spillet kjører. @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } Bermuda - - + + Console ID: 0x%1 Konsoll ID: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? Dette erstatter din nåværende virtuelle 3DS med en ny. Din nåværende virtuelle 3DS kan ikke gjenopprettes. Dette kan ha uventede effekter i spill. Dette kan misslykkes, hvis du bruker et utdatert konfigurasjon lagret spill. Fortsette? - + Warning Advarsel + + ConfigureUi + + + Form + + + + + General + + + + + Interface language: + + + + + Theme: + + + + + Game List + + + + + Icon Size: + + + + + + None + + + + + Small (24x24) + + + + + Large (48x48) + + + + + Row 1 Text: + + + + + + File Name + + + + + + Full Path + + + + + + Title Name + + + + + + Title ID + + + + + Row 2 Text: + + + + + Hide Titles without Icon + + + + + <System> + + + + + English + + + ConfigureWeb @@ -2155,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify Verifisere @@ -2207,56 +2391,56 @@ p, li { white-space: pre-wrap; } Discord Presence - + Discord tilstedeværelse Show Current Game in your Discord Status - + Vis Gjeldende Spill i Discord Statusen din. - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Lær mer</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Registrer deg</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">Hva er min nøkkel?</span></a> - - + + Telemetry ID: 0x%1 Telemetri ID: 0x%1 - + Username and token not verified Brukernavn og nøkkel ikke bekreftet - + Username and token were not verified. The changes to your username and/or token have not been saved. Brukernavn og nøkkel ble ikke bekreftet. Endringene i brukernavnet ditt og/eller nøkkel ble ikke lagret. - + Verifying Verifiserer - + Verification failed Verifikasjon misslyktes - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. Verifikasjon mislyktes. Kontroller at du har angitt brukernavnet ditt og nøkkelen riktig, og at Internettilkoblingen din fungerer. @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting Kobler til - + Connect Koble til @@ -2330,413 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonym data samles inn</a> for å forbedre Citra. <br/><br/>Vil du dele dine brukerdata med oss? - + Telemetry - + Telemetri - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Nåværende emuleringhastighet. Verdier høyere eller lavere enn 100% indikerer at emuleringen kjører raskere eller langsommere enn en 3DS. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Hvor mange bilder per sekund spillet vises for øyeblikket. Dette vil variere fra spill til spill og scene til scene. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tid tatt for å emulere et 3DS bilde, gjelder ikke bildebegrensning eller V-Sync. For raskest emulering bør dette være høyst 16,67 ms. - + Clear Recent Files Tøm nylige filer - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available - + Oppdatering Tilgjengelig - + An update is available. Would you like to install it now? - - - - - No Update Found - - - - - No update is found. - + En oppdatering er tilgjengelig. Ønsker du å installere den nå? - + No Update Found + Ingen Oppdatering Funnet + + + + No update is found. + Ingen oppdatering ble funnet. + + + + OpenGL 3.3 Unsupported + + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + + + + + Invalid ROM Format - + Ugyldig ROM Format - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + ROM-formatet støttes ikke.<br/>Følg veiledningene for å redumpe dine<a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>spillpatroner</a> eller <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installerte titler</a>. - + ROM Corrupted - + ROM Korrupt - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + ROM er ødelagt.<br/>Vennligst følg veiledningene for å dumpe din<a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>Spillpatronen</a> eller <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installerte titler</a>. - + ROM Encrypted - + ROM Kryptert - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + Din ROM er kryptert. <br/>Vennligst følg veiledningene får å dumpe <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>spillpatroner</a> eller <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installerte titler</a>. - - + + Video Core Error - + Video Kjerne Feil - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. - + En feil har oppstått. Vennligst <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>se loggen</a> for flere detaljer. Kontroller at du har de nyeste grafikkdriverne for GPU. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. - + Du kjører standard Windows-drivere for din GPU. Du må installere de riktige driverne for grafikkortet ditt fra produsentens nettsted. - + Error while loading ROM! Feil ved lasting av ROM! - + An unknown error occured. Please see the log for more details. En ukjent feil oppstod. Vennligst se loggen for mer informasjon. - + Start Start - + Error Opening %1 Folder Feil ved Åpning av %1 Mappe - - + + Folder does not exist! Mappen eksistere ikke! - + Error Opening %1 Feil ved åpning av %1 - + Select Directory Velg Plassering - - 3DS Executable - 3DS Kjørbar + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + - - - All Files (*.*) - Alle Filer (*.*) - - - + Load File Last Fil - + Load Files Last Filer - + 3DS Installation File (*.CIA*) 3DS Installasjons Fil (*.CIA*) - + + All Files (*.*) + Alle Filer (*.*) + + + %1 has been installed successfully. %1 Ble installert vellykket. - + Unable to open File Kan ikke åpne Fil - + Could not open %1 Kunne ikke åpne %1 - + Installation aborted Installasjon avbrutt - + The installation of %1 was aborted. Please see the log for more details Installeringen av %1 ble avbrutt. Vennligst se logg for detaljer - + Invalid File Ugyldig Fil - + %1 is not a valid CIA %1 er ikke en gyldig CIA - + Encrypted File Kryptert Fil - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 må bli dekryptert før den kan bli brukt av Citra. En ekte 3DS er nødvendig. - + File not found Fil ikke funnet - + File "%1" not found Fil "%1" ble ikke funnet - - - + + + Continue Fortsett - + Missing Citra Account Mangler Citra Bruker - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. + Du må koble din Citra-konto til å sende inn testtilfeller.<br/>Gå til Emulering &gt; Konfigurasjon... &gt; Web får å gjøre det. + + + + Amiibo File (%1);; All Files (*.*) - - - - Record Movie - - - - - - Citra TAS Movie (*.ctm) - - - - - Recording will start once you boot a game. - - - - - The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? - - - - - The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? - - - - - - The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. - - - - - Revision Dismatch - - - - - Game Dismatch - - - - - - Invalid Movie File - - - - - Play Movie - - - - - Game Not Found - - - - - The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. - - - - - Movie recording cancelled. + + Load Amiibo + + - Movie Saved + + Record Movie + Ta Opp Video + + + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + + + + Citra TAS Movie (*.ctm) + Citra TAS Film (*.ctm) + - The movie is successfully saved. - + Recording will start once you boot a game. + Opptak starter når du starter et spill. + + + + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? + Filmen filen du prøver å laste ble opprettet på en annen revisjon av Citra.<br/>Citra har hatt noen endringer i løpet av tiden, og avspillingen kan de-synkroniseres eller ikke fungere som forventet.<br/><br/>Er du sikker på at du fortsatt vil laste video filen? + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? + video filen du prøver å laste ble tatt opp med et annet spill.<br/>Avspillingen fungerer kanskje ikke som forventet, og det kan føre til uventede resultater.<br/><br/>Er du sikker på at du fortsatt vil laste filmfilen? + + + + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. + Filmfilen du prøver å laste er ugyldig.<br/>Enten er filen skadet, eller så har Citra har gjort noen store endringer i filmmodulen.<br/>Vennligst velg en annen filmfil og prøv igjen. + + + + Revision Dismatch + Revisjon Avvik + + + + Game Dismatch + Spill Avvik + + + + + Invalid Movie File + Ugyldig Video Fil + + + + + Play Movie + Spill Film + + + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + + + + + Game Not Found + Spill Ikke Funnet + + + + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. + Filmen du prøver å spille er fra et spill som ikke er i spillelisten. Hvis du eier spillet, må du legge til spillemappen til spillelisten og prøve å spille av filmen igjen. + + + + Movie recording cancelled. + Filmopptak avbrutt. + + + + Movie Saved + Film Lagret + + + + The movie is successfully saved. + Filmen ble lagret vellykket. + + + Speed: %1% / %2% Fart: %1% / %2% - + Speed: %1% Fart: %1% - + Game: %1 FPS Spill: %1 FPS - + Frame: %1 ms Bilde: %1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + %1 mangler. Vennligst <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump systemarkivene dine</a>.<br/>Fortsatt emulering kan føre til krasjer og feil. - + System Archive Not Found System Arkiv ikke funnet - + Fatal Error Fatal Feil - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + En fatal feil har oppstått. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Se loggen</a> for detaljer.<br/>Fortsatt emulering kan føre til krasjer og feil. - + Abort - + Avbryt - - + + Citra Citra - + Would you like to exit now? - + Vil du avslutte nå? - + The game is still running. Would you like to stop emulation? - + Spillet kjører fortsatt. Vil du stoppe emulering? - + Playback Completed - + Avspilling Fullført - + Movie playback completed. - + Filmavspilling fullført. - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2799,37 +3015,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + + + + + Compatibility + + + + + Region + + + + + File type + + + + + Size + + + + Open Save Data Location Åpne Lagringsdata Plassering - + + Open Extra Data Location + + + + Open Application Location Åpne applikasjons plassering - + Open Update Data Location Åpne Oppdateringdata Plassering - + Navigate to GameDB entry Naviger til GameDB oppføring - + Scan Subfolders Skann Undermapper - + Remove Game Directory Slett Spill Mappe - + Open Directory Location Fjern Mappe Plassering @@ -2837,85 +3083,90 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect - + Perfekt - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Spillet fungerer feilfritt uten lyd- eller grafiske feil, alle testet funksjonalitet fungerer som tiltenkt uten +behov for midlertidige løsninger. - + Great - + Bra - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Spillet Fungerer med minimale grafiske- eller lyd feil og kan spilles fra start til slutt. Kan kreve noe +midlertidige løsninger. - + Okay - + Ok - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. - + Spillet fungerer med omfattende grafiske- eller lyd feil, men er spillbart fra start til slutt med +midlertidige løsninger. - + Bad - + Dårlig - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Spillet fungerer, men med omfattende grafiske- eller lyd feil. Umulig med fremgang i spesifikke områder på grunn av feil +selv med midlertidige løsninger. - + Intro/Menu - + Intro/Meny - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Spillet er helt uspillbart på grunn av store grafiske- eller lyd feil. Kan ikke gå videre forbi Start +Skjermen. - + Won't Boot - + Vil ikke starte opp - + The game crashes when attempting to startup. - + Spillet krasjer når du prøver å starte opp. - + Not Tested - + Ikke Testet - + The game has not yet been tested. - + Spillet har ikke blitt testet ennå. GameListPlaceholder - + Double-click to add a new folder to the game list Dobbelttrykk for å legge til en ny mappe til spilllisten @@ -2923,27 +3174,27 @@ Screen. GameListSearchField - + of av - + result Resultat - + results Resultater - + Filter: Filter: - + Enter pattern to filter Skriv inn mønster for å filtrere @@ -2951,23 +3202,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Pica Bruddpunkt - - + + Emulation running Emulering kjører - + Resume Fortsett - + Emulation halted at breakpoint Emuleringen stoppet ved bruddpunktet @@ -3384,42 +3635,42 @@ Screen. Oppdater Lobby - + Password Required to Join Passord kreves for å bli med - + Password: Passord: - + Room Name Rom Navn - + Preferred Game Foretrukket Spill - + Host Vert - + Players Spillere - + Refreshing Oppdaterer - + Refresh List Oppdaterer Liste @@ -3442,220 +3693,245 @@ Screen. Nylige Filer - + + Amiibo + + + + &Emulation &Emulering - + &View &Vis - + Debugging Feilsøking - + Screen Layout Skjerm Oppsett - + Movie - + Video - + Multiplayer Flerspiller - + &Help &Hjelp - + Load File... Last inn fil... - + Install CIA... Installer CIA... - + Load Symbol Map... Last inn symbolkart... - + E&xit Avslutt - + &Start &Start - + &Pause &Pause - + &Stop &Stopp - + FAQ FAQ - + About Citra Om Citra - + Single Window Mode Enkelt vindu modus - + Configure... Konfigurer... - + Display Dock Widget Headers Vis Dock Widget Headere - + Show Filter Bar Vis filter linje - + Show Status Bar Vis status linje - + Select Game Directory... Velg spill plassering... - + Selects a folder to display in the game list Velg en mappe til å vise spilllisten - + Create Pica Surface Viewer Lag Pica overflate visning - + Record Movie - + Ta Opp Video - + Play Movie - + Spill Video - + Stop Recording / Playback + Stopp Innspilling / Avspilling + + + + Enable Frame Advancing - + + Advance Frame + + + + Browse Public Game Lobby Bla gjennom Offentlig Spill Lobby - + Create Room Opprett Rom - + Leave Room Forlat Rom - + Direct Connect to Room Koble Direkte til Rom - + Show Current Room Vis Nåværende Rom - + Fullscreen Fullskjerm - + Modify Citra Install Modifiser Citra Installasjon - + Opens the maintenance tool to modify your Citra installation Åpner vedlikeholdvertøyet for din Citra Installasjon - + Default Standard - + Single Screen Enkel Skjerm - + Large Screen Stor Skjerm - + Side by Side Side ved Side - + Swap Screens Bytt Skjerm - + Check for Updates Sjekk for oppdateringer - + Report Compatibility Rapporter Kompatibilitet - + Restart Omstart + + + Load... + + + + + Remove + + MicroProfileDialog @@ -3681,23 +3957,23 @@ Screen. - + Connected Tilkoblet - + Not Connected Ikke Tilkoblet - + Error Feil - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: Kunne ikke kunngjøre rommet til den offentlige lobbyen. For å være vert for et rom offentlig, må du ha en gyldig Citra-konto konfigurert i Emulering -> Konfigurering -> Web. Hvis du ikke vil publisere et rom i den offentlige lobbyen, velger du Unotert i stedet. @@ -3816,108 +4092,108 @@ Feilsøkingsmelding: %1 spiller %2 - - + + Invalid region Ugyldig region - + Japan Japan - + North America Nord Amerika - + Europe Europa - + Australia Australia - + China Kina - + Korea Korea - + Taiwan Taiwan - + Region free Sonefri - + Invalid Region Ugyldig Region - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [ikke bestemt] - + Hat %1 %2 - + Hat %1 %2 - + Axis %1%2 - + Akse %1%2 - + Button %1 - + Knapp %1 - - + + [unknown] [ukjent] - + [unused] [ubrukt] - - + + Axis %1 - + Akse %1 diff --git a/dist/languages/nl.ts b/dist/languages/nl.ts index a6e2b5660..289792550 100644 --- a/dist/languages/nl.ts +++ b/dist/languages/nl.ts @@ -70,45 +70,83 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Pica opdracht geladen - + Pica command processed Pica opdracht verwerkt - + Incoming primitive batch Inkomende primitieve batch - + Finished primitive batch Klaar met primitieve batch - + Vertex shader invocation Vertex shader-aanroep - + Incoming display transfer Inkomende schermoverdracht - + GSP command processed GSP opdracht verwerkt - + Buffers swapped Buffers verwisseld + + + Unknown debug context event + + + + + CalibrationConfigurationDialog + + + Communicating with the server... + + + + + Cancel + + + + + Touch the top left corner <br>of your touchpad. + + + + + Now touch the bottom right corner <br>of your touchpad. + + + + + Configuration completed! + + + + + OK + + ChatRoom @@ -128,15 +166,26 @@ p, li { white-space: pre-wrap; } Stuur Bericht - + Name - + Game + + + + Block Player + + + + + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? + + ClientRoom @@ -154,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected - + Disconnected - + %1 (%2/%3 members) - connected @@ -257,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! + + + Submitting + + + + + Communication error + + + + + An error occured while sending the Testcase + + + + + Next + + ConfigureAudio @@ -296,9 +365,9 @@ p, li { white-space: pre-wrap; } - - - %1 % + + %1% + Volume percentage (e.g. 50%) @@ -519,88 +588,121 @@ p, li { white-space: pre-wrap; } GDB - - The GDB Stub only works correctly when the CPU JIT is off. - De GDB Stub werkt alleen correct als de CPU JIT is uitgeschakeld. - - - + Enable GDB Stub GBD Stub inschakelen - + Port: Poort: - + Logging - + Global Log Filter - + Show Log Console (Windows Only) - + Open Log Location + + + Miscellaneous + + + + + Enable CPU JIT + + ConfigureDialog - + Citra Configuration Citra configuratie - + + + General Algemeen - + + + System Systeem - + + + Input Invoer - + + + Graphics Beeldkwaliteit - + + + Audio Geluid - + + + Camera - + + + Debug Fouten opsporen - + + + Web Website + + + + + UI + + + + + Controls + + ConfigureGeneral @@ -620,74 +722,54 @@ p, li { white-space: pre-wrap; } Bevestig afsluiten terwijl emulatie bezig is - - Interface language - Interfacetaal - - - + Updates Updates - + Check for updates on start Zoeken naar updates bij opstarten - + Silently auto update after closing Auto update na sluiten in de achtergrond - - Performance - Prestaties - - - - Enable CPU JIT - CPU JIT inschakelen - - - + Emulation Emulatie - + Region: Regio: - + Auto-select Automatisch selecteren - - Theme - Thema - - - - Theme: - Thema: - - - + Hotkeys Sneltoetsen - - <System> - <System> + + Reset All Settings + - - English - Engels + + Citra + + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + @@ -874,12 +956,17 @@ p, li { white-space: pre-wrap; } Scherm Verwisselen - - Hardware Shader Warning + + Background Color: + Hardware Shader Warning + + + + Hardware Shader support is broken on macOS, and will cause graphical issues like showing a black screen.<br><br>The option is only there for test/development purposes. If you experience graphical issues with Hardware Shader, please turn it off. @@ -982,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick Analog Stick instellen @@ -1017,16 +1104,220 @@ p, li { white-space: pre-wrap; } Circle Mod: - + + Motion / Touch... + + + + + Clear All + + + + Restore Defaults Standaardwaarde herstellen - + + + Clear + + + + + + [not set] + + + + + + Restore Default + + + + + Information + + + + + After pressing OK, first move your joystick horizontally, and then vertically. + + + + [press key] [Druk op een toets] + + ConfigureMotionTouch + + + Configure Motion / Touch + + + + + Motion + + + + + Motion Provider: + + + + + Sensitivity: + + + + + Touch + + + + + Touch Provider: + + + + + Calibration: + + + + + (100, 50) - (1800, 850) + + + + + + Configure + + + + + CemuhookUDP Config + + + + + You may use any Cemuhook compatible UDP input source to provide motion and touch input. + + + + + Server: + + + + + Port: + + + + + Pad: + + + + + Pad 1 + + + + + Pad 2 + + + + + Pad 3 + + + + + Pad 4 + + + + + Learn More + + + + + + Test + + + + + Mouse (Right Click) + + + + + + CemuhookUDP + + + + + Emulator Window + + + + + <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> + + + + + Testing + + + + + Configuring + + + + + Test Successful + + + + + Successfully received data from the server. + + + + + Test Failed + + + + + Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. + + + + + Citra + + + + + UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. + + + ConfigureSystem @@ -1201,36 +1492,834 @@ p, li { white-space: pre-wrap; } + Country + + + + + Clock + + + + + System Clock + + + + + Fixed Time + + + + + Startup time + + + + + yyyy-MM-ddTHH:mm:ss + + + + + Play Coins: + + + + Console ID: Console ID: - + Regenerate Herstellen - + System settings are available only when game is not running. Systeeminstellingen zijn alleen beschikbaar wanneer er geen spel actief is. - + + Japan + + + + + Anguilla + + + + + Antigua and Barbuda + + + + + Argentina + + + + + Aruba + + + + + Bahamas + + + + + Barbados + + + + + Belize + + + + + Bolivia + + + + + Brazil + + + + + British Virgin Islands + + + + + Canada + + + + + Cayman Islands + + + + + Chile + + + + + Colombia + + + + + Costa Rica + + + + + Dominica + + + + + Dominican Republic + + + + + Ecuador + + + + + El Salvador + + + + + French Guiana + + + + + Grenada + + + + + Guadeloupe + + + + + Guatemala + + + + + Guyana + + + + + Haiti + + + + + Honduras + + + + + Jamaica + + + + + Martinique + + + + + Mexico + + + + + Montserrat + + + + + Netherlands Antilles + + + + + Nicaragua + + + + + Panama + + + + + Paraguay + + + + + Peru + + + + + Saint Kitts and Nevis + + + + + Saint Lucia + + + + + Saint Vincent and the Grenadines + + + + + Suriname + + + + + Trinidad and Tobago + + + + + Turks and Caicos Islands + + + + + United States + + + + + Uruguay + + + + + US Virgin Islands + + + + + Venezuela + + + + + Albania + + + + + Australia + + + + + Austria + + + + + Belgium + + + + + Bosnia and Herzegovina + + + + + Botswana + + + + + Bulgaria + + + + + Croatia + + + + + Cyprus + + + + + Czech Republic + + + + + Denmark + + + + + Estonia + + + + + Finland + + + + + France + + + + + Germany + + + + + Greece + + + + + Hungary + + + + + Iceland + + + + + Ireland + + + + + Italy + + + + + Latvia + + + + + Lesotho + + + + + Liechtenstein + + + + + Lithuania + + + + + Luxembourg + + + + + Macedonia + + + + + Malta + + + + + Montenegro + + + + + Mozambique + + + + + Namibia + + + + + Netherlands + + + + + New Zealand + + + + + Norway + + + + + Poland + + + + + Portugal + + + + + Romania + + + + + Russia + + + + + Serbia + + + + + Slovakia + + + + + Slovenia + + + + + South Africa + + + + + Spain + + + + + Swaziland + + + + + Sweden + + + + + Switzerland + + + + + Turkey + + + + + United Kingdom + + + + + Zambia + + + + + Zimbabwe + + + + + Azerbaijan + + + + + Mauritania + + + + + Mali + + + + + Niger + + + + + Chad + + + + + Sudan + + + + + Eritrea + + + + + Djibouti + + + + + Somalia + + + + + Andorra + + + + + Gibraltar + + + + + Guernsey + + + + + Isle of Man + + + + + Jersey + + + + + Monaco + + + + + Taiwan + + + + + South Korea + + + + Hong Kong + + + + + Macau + + + + + Indonesia + + + + + Singapore + + + + + Thailand + + + + + Philippines + + + + + Malaysia + + + + + China + + + + + United Arab Emirates + + + + + India + + + + + Egypt + + + + + Oman + + + + + Qatar + + + + + Kuwait + + + + + Saudi Arabia + + + + + Syria + + + + + Bahrain + + + + + Jordan + + + + + San Marino + + + + + Vatican City + + + + + Bermuda + + + + + Console ID: 0x%1 Console ID: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? Dit zal je huidige virtuele 3DS vervangen met een nieuwe. Je huidige virtuele 3DS is niet herstelbaar. Dit kan onverwachte effecten hebben in spellen. Dit kan mislukken, als je een verouderd configuratie opslagbestand gebruikt. Doorgaan? - + Warning Waarschuwing + + ConfigureUi + + + Form + + + + + General + + + + + Interface language: + + + + + Theme: + + + + + Game List + + + + + Icon Size: + + + + + + None + + + + + Small (24x24) + + + + + Large (48x48) + + + + + Row 1 Text: + + + + + + File Name + + + + + + Full Path + + + + + + Title Name + + + + + + Title ID + + + + + Row 2 Text: + + + + + Hide Titles without Icon + + + + + <System> + + + + + English + + + ConfigureWeb @@ -1250,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify Verifiëren @@ -1300,48 +2389,58 @@ p, li { white-space: pre-wrap; } Herstellen - + + Discord Presence + + + + + Show Current Game in your Discord Status + + + + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> - - + + Telemetry ID: 0x%1 Telemetrie ID: 0x%1 - + Username and token not verified - + Username and token were not verified. The changes to your username and/or token have not been saved. Gebruikersnaam en token zijn niet geverifieerd. De veranderingen aan je gebruikersnaam en/of token zijn niet opgeslagen. - + Verifying Verifiëren - + Verification failed Verificatie mislukt - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. Verificatie mislukt. Kijk of je je gebruikersnaam en token goed hebt ingevuld, en dat je internetverbinding werkt. @@ -1402,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting - + Connect @@ -1415,310 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - - To help improve Citra, the Citra Team collects anonymous usage data. No private or personally identifying information is collected. This data helps us to understand how people use Citra and prioritize our efforts. Furthermore, it helps us to more easily identify emulation bugs and performance issues. This data includes:<ul><li>Information about the version of Citra you are using</li><li>Performance data about the games you play</li><li>Your configuration settings</li><li>Information about your computer hardware</li><li>Emulation errors and crash information</li></ul>By default, this feature is enabled. To disable this feature, click 'Emulation' from the menu and then select 'Configure...'. Then, on the 'Web' tab, uncheck 'Share anonymous usage data with the Citra team'. <br/><br/>By using this software, you agree to the above terms.<br/><br/><a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Learn more</a> - Om Citra te verbeteren, zal het Citra team anonieme gebruiksdata verzamelen. Geen privé of persoonlijk identificerende informatie zal worden verzameld. Deze data zal ons helpen begrijpen hoe de mensen Citra gebruiken en onze inspanningen te prioriteren. Daarnaast zal het ons helpen makkelijker emulatiebugs en prestatieproblemen te identificeren. Onder deze data valt:<ul><li>Informatie over de versie van Citra die je gebruikt</li><li>Prestatiedata over de spellen die je speelt</li><li>Je configuratieinstellingen</li><li>Informatie over je computerhardware</li><li>Emulatie errors en crashinformatie</li></ul>Standaard is deze optie ingeschakeld. Om deze optie uit te schakelen, klik op 'Emulatie' vanuit het menu en kies 'Configuratie...'. Dan in de 'Web' tab, deselecteer 'Deel anonieme gebruiksdata met het Citra team'. <br/><br/>Door deze software te gebruiker, ga je akkoord met de bovenstaande voorwaardes.<br/><br/><a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Leer meer</a> + + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? + - + + Telemetry + + + + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Huidige emulatiesnelheid. Waardes hoger of lager dan 100% geven aan dat de emulatie sneller of langzamer gaat dan een 3DS. - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Hoeveel frames per seconde het spel nu momenteel laat zien. Dit kan variëren van spel tot spel en scene tot scene. - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tijd verstrekt om één 3DS frame te emuleren, zonder framelimitatie of V-Sync te tellen. Voor volledige snelheid emulatie zal dit maximaal 16.67 ms moeten zijn. - + + Clear Recent Files + + + + F9 - + F10 - + CTRL+F CTRL+F - - Update available! - Update beschikbaar! + + Update Available + - - An update for Citra is available. Do you wish to install it now?<br /><br />This <b>will</b> terminate emulation, if it is running. - Een update voor Citra is beschikbaar. Wil je die nu installeren?<br /><br />Dit <b>zal</b> de huidige emulatie stoppen, als deze bezig is. + + An update is available. Would you like to install it now? + - - No update found - Geen update gevonden + + No Update Found + - - No update has been found for Citra. - Geen update voor Citra is gevonden. + + No update is found. + - - Error while initializing OpenGL 3.3 Core! - Fout bij het initialiseren van OpenGL 3.3 Core! + + OpenGL 3.3 Unsupported + - + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. - Je GPU ondersteunt OpenGL 3.3 misschien niet, of je hebt niet de laatste grafische stuurprogramma's. + - - - - - + + + Invalid ROM Format + + + + + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. + + + + + ROM Corrupted + + + + + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. + + + + + ROM Encrypted + + + + + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. + + + + + + Video Core Error + + + + + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. + + + + + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. + + + + Error while loading ROM! Fout tijdens het laden van de ROM! - - - The ROM format is not supported. - De ROM-formaat is niet ondersteund. - - - - Could not determine the system mode. - Kon de systeemmodus niet vaststellen. - - - - The game that you are trying to load must be decrypted before being used with Citra. A real 3DS is required.<br/><br/>For more information on dumping and decrypting games, please see the following wiki pages: <ul><li><a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>Dumping Game Cartridges</a></li><li><a href='https://citra-emu.org/wiki/dumping-installed-titles/'>Dumping Installed Titles</a></li></ul> - Het spel dat je probeert te laden moet eerst gedecodeerd worden voordat je het kan gebruiken met Citra. Een echte 3DS is vereist.<br/><br/>Voor meer informatie over dumping en decoderen van spellen, zie de volgende wiki-pagina's: <ul><li><a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>Dumping Game Cartridges</a></li><li><a href='https://citra-emu.org/wiki/dumping-installed-titles/'>Dumping Installed Titles</a></li></ul> - - - - An error occured in the video core. - Een fout in de video core is opgetreden. - - - - Citra has encountered an error while running the video core, please see the log for more details.For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.Ensure that you have the latest graphics drivers for your GPU. - Citra heeft een fout aangetroffen tijdens het uitvoeren van de video core, raadpleeg het logboek voor meer informatie. Raadpleeg de volgende pagina voor meer informatie over het openen van het logboek: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>. Zorg dat je beschikt over de nieuwste grafische stuurprogramma's voor uw GPU. - - - + An unknown error occured. Please see the log for more details. Er is een onbekende fout opgetreden. Zie het logboek voor meer details. - + Start Start - + Error Opening %1 Folder - - + + Folder does not exist! Map bestaat niet! - + Error Opening %1 - + Select Directory Selecteer Folder - - 3DS Executable - 3DS Executable + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + - - - All Files (*.*) - Alle bestanden (*.*) - - - + Load File Laad bestand - + Load Files - + 3DS Installation File (*.CIA*) 3DS Installatie bestand (*.CIA*) - + + All Files (*.*) + Alle bestanden (*.*) + + + %1 has been installed successfully. - + Unable to open File Kan bestand niet openen - + Could not open %1 - + Installation aborted Installatie onderbroken - + The installation of %1 was aborted. Please see the log for more details - + Invalid File Ongeldig bestand - + %1 is not a valid CIA - + Encrypted File Versleuterd bestand - + %1 must be decrypted before being used with Citra. A real 3DS is required. - + File not found Bestand niet gevonden - + File "%1" not found Bestand "%1" niet gevonden - + + + Continue Doorgaan - + Missing Citra Account - - In order to submit a game compatibility test case, you must link your Citra account.<br><br/>To link your Citra account, go to Emulation &gt; Configuration &gt; Web. + + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. - + + Amiibo File (%1);; All Files (*.*) + + + + + Load Amiibo + + + + + + + + Record Movie + + + + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + + + + + + Citra TAS Movie (*.ctm) + + + + + Recording will start once you boot a game. + + + + + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? + + + + + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? + + + + + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. + + + + + Revision Dismatch + + + + + Game Dismatch + + + + + + Invalid Movie File + + + + + + Play Movie + + + + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + + + + + Game Not Found + + + + + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. + + + + + Movie recording cancelled. + + + + + Movie Saved + + + + + The movie is successfully saved. + + + + Speed: %1% / %2% - + Speed: %1% Snelheid: %1% - + Game: %1 FPS Spel: %1 FPS - + Frame: %1 ms Frame: %1 ms - - The game you are trying to load requires additional files from your 3DS to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>Dumping System Archives and the Shared Fonts from a 3DS Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. - Het spel dat je probeert te laden vereist dat er extra bestanden van uw 3DS worden gedumpt voordat je kan spelen.<br/><br/>Voor meer informatie over dumping van deze bestanden, kijk dan naar de volgende wiki pagina: <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>Dumping System Archives and the Shared Fonts from a 3DS Console</a>.<br/><br/>Wil je afsluiten en terug gaan naar de lijst met spellen? Doorgaan met de emulatie kan crashes, beschadigde save data of andere bugs veroorzaken. + + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. + - - : %1. - : %1. - - - + System Archive Not Found Systeem archief niet gevonden - - Citra was unable to locate the 3DS shared fonts. - Citra was kon de locatie van de 3DS gedeelde fonts niet vinden. - - - - Shared Fonts Not Found - Gedeelde Fonts Niet Gevonden - - - + Fatal Error Fatale Fout - - Citra has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs. - Citra heeft een fatale fout aangetroffen, raadpleeg het logboek voor meer informatie. Raadpleeg de volgende pagina voor meer informatie over het openen van het logboek: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Wil je afsluiten en terug gaan naar de lijst met spellen? Doorgaan met de emulatie kan crashes, beschadigde save data of andere bugs veroorzaken. + + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. + - - + + Abort + + + + + Citra Citra - - Are you sure you want to close Citra? - Weet je zeker dat je Citra wilt afsluiten? + + Would you like to exit now? + - - Are you sure you want to stop the emulation? Any unsaved progress will be lost. - Weet je zeker dat je de emulatie wilt stoppen? Alle niet opgeslagen voortgang zal verloren gaan. + + The game is still running. Would you like to stop emulation? + - + + Playback Completed + + + + + Movie playback completed. + + + + Citra %1 - + Citra %1| %2 @@ -1781,146 +3015,205 @@ p, li { white-space: pre-wrap; } GameList - + + Name + + + + + Compatibility + + + + + Region + + + + + File type + + + + + Size + + + + + Open Save Data Location + Open opslag data locatie + + + + Open Extra Data Location + + + + + Open Application Location + + + + + Open Update Data Location + + + + + Navigate to GameDB entry + + + + + Scan Subfolders + + + + + Remove Game Directory + + + + + Open Directory Location + + + + + GameListItemCompat + + Perfect - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. - + Bad - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot - + The game crashes when attempting to startup. - + Not Tested - + The game has not yet been tested. + + + GameListPlaceholder - - of - van de + + Double-click to add a new folder to the game list + + + + GameListSearchField - - result - Resultaat + + of + - results - Resultaten + result + - + + results + + + + Filter: - + Enter pattern to filter - - - Open Save Data Location - Open opslag data locatie - - - - Open Application Location - - - - - Open Update Data Location - - - - - Navigate to GameDB entry - - GraphicsBreakPointsWidget - + Pica Breakpoints Pica breekpunten - - + + Emulation running Emulatie loopt - + Resume Hervatten - + Emulation halted at breakpoint Emulatie gestopt op breekpunt @@ -1928,122 +3221,122 @@ Screen. GraphicsSurfaceWidget - + Pica Surface Viewer Pica Surface Viewer - + Color Buffer Kleur Buffer - + Depth Buffer Diepte Buffer - + Stencil Buffer Stencil Buffer - + Texture 0 Structuur 0 - + Texture 1 Structuur 1 - + Texture 2 Structuur 2 - + Custom Aangepast - + Unknown Onbekend - + Save Opslaan - + Source: Bron: - + Physical Address: Fysiek Adres: - + Width: Breedte: - + Height: Hoogte: - + Format: Formaat: - + X: X: - + Y: Y: - + Pixel out of bounds Pixel buiten bereik - + (unable to access pixel data) (geen toegang tot pixel data) - + (invalid surface address) (ongeldig surface adres) - + (unknown surface format) (onbekend surface formaat) - + Portable Network Graphic (*.png) Portable Network Graphic (*.png) - + Binary data (*.bin) Binary data (*.bin) - + Save Surface Surface opslaan @@ -2290,6 +3583,14 @@ Screen. + + LLEServiceModulesWidget + + + Toggle LLE Service Modules + + + Lobby @@ -2329,42 +3630,42 @@ Screen. - + Password Required to Join - + Password: - + Room Name - + Preferred Game - + Host - + Players - + Refreshing - + Refresh List @@ -2387,195 +3688,245 @@ Screen. Recente Bestanden - + + Amiibo + + + + &Emulation &Emulatie - + &View &Beeld - + Debugging Foutopsporing - + Screen Layout - + + Movie + + + + Multiplayer - + &Help &Help - + Load File... Laad Bestand... - + Install CIA... CIA Installeren... - + Load Symbol Map... Symbool Map Laden... - + E&xit &Afsluiten - + &Start &Start - + &Pause &Pauzeren - + &Stop &Stop - + FAQ FAQ - + About Citra Over Citra - + Single Window Mode Enkel Scherm Modus - + Configure... Configureren... - + Display Dock Widget Headers Dock Widget Headers Tonen - + Show Filter Bar Filter Bar Tonen - + Show Status Bar Status Bar Tonen - + Select Game Directory... Selecteer Spel Folder... - + Selects a folder to display in the game list Selecteert een folder om te tonen in de spellen lijst - + Create Pica Surface Viewer Pica Surface Viewer Maken - + + Record Movie + + + + + Play Movie + + + + + Stop Recording / Playback + + + + + Enable Frame Advancing + + + + + Advance Frame + + + + Browse Public Game Lobby - + Create Room - + Leave Room - + Direct Connect to Room - + Show Current Room - + Fullscreen Volledig Scherm - + Modify Citra Install Citra Installatie Aanpassen - + Opens the maintenance tool to modify your Citra installation Opent de onderhouds-tool om de Citra installatie aan te passen - + Default - + Single Screen - + Large Screen - + Side by Side - + Swap Screens - + Check for Updates Zoeken naar Updates - + Report Compatibility + + + Restart + + + + + Load... + + + + + Remove + + MicroProfileDialog @@ -2589,31 +3940,35 @@ Screen. MultiplayerState + Current connection status + Not Connected. Click here to find a room! - + + Connected - + + Not Connected - + Error - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: @@ -2731,114 +4086,108 @@ Debug Message: - - + + Invalid region - + Japan - + North America - + Europe - + Australia - + China - + Korea - + Taiwan - + Region free - + Invalid Region - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [niet ingesteld] - - - Joystick %1 - Joystick %1 + + Hat %1 %2 + - - Hat %1 %2 - Hat %1 %2 + + Axis %1%2 + - - Axis %1%2 - Axis %1%2 + + Button %1 + - - Button %1 - Knop %1 - - - + [unknown] [onbekend] - + [unused] [ongebruikt] - Axis %1 - Axis %1 + Axis %1 + @@ -2930,7 +4279,7 @@ Debug Message: WaitTreeEvent - + reset type = %1 reset type = %1 @@ -2938,12 +4287,12 @@ Debug Message: WaitTreeMutex - + locked %1 times by thread: %1 keer gesloten door thread: - + free vrij @@ -2951,7 +4300,7 @@ Debug Message: WaitTreeMutexList - + holding mutexes mutexes worden vasthouden @@ -2959,12 +4308,12 @@ Debug Message: WaitTreeObjectList - + waiting for all objects wachten op alle objecten - + waiting for one of the following objects wachten op een van de volgende objecten @@ -2972,12 +4321,12 @@ Debug Message: WaitTreeSemaphore - + available count = %1 beschikbare aantal = %1 - + max count = %1 maximale aantal = %1 @@ -2985,102 +4334,102 @@ Debug Message: WaitTreeThread - + running lopend - + ready Gereed - + waiting for address 0x%1 Wachten op adres 0x%1 - + sleeping sluimeren - + waiting for IPC response wachten op IPC antwoord - + waiting for objects wachten op objecten - + waiting for HLE return wachten op HLE teruggave - + dormant slapend - + dead dood - + PC = 0x%1 LR = 0x%2 PC = 0x%1 LR = 0x%2 - + default standaard - + all alle - + AppCore AppCore - + SysCore SysCore - + Unknown processor %1 Onbekende processor %1 - + processor = %1 processor = %1 - + thread id = %1 thread id = %1 - + priority = %1(current) / %2(normal) prioriteit = %1(huidige) / %2(normaal) - + last running ticks = %1 laatste lopende tikken = %1 - + not holding mutex geen mutex wordt vastgehouden @@ -3088,7 +4437,7 @@ Debug Message: WaitTreeThreadList - + waited by thread gepauzeerd door thread @@ -3096,17 +4445,17 @@ Debug Message: WaitTreeTimer - + reset type = %1 reset type = %1 - + initial delay = %1 Initiële vertraging = %1 - + interval delay = %1 interval vertraging = %1 @@ -3114,27 +4463,27 @@ Debug Message: WaitTreeWaitObject - + [%1]%2 %3 [%1]%2 %3 - + waited by no thread gepauzeerd door geen thread - + one shot one shot - + sticky sticky - + pulse pulse @@ -3142,7 +4491,7 @@ Debug Message: WaitTreeWidget - + Wait Tree Wait Tree diff --git a/dist/languages/pl_PL.ts b/dist/languages/pl_PL.ts index 1c8a4ae33..337dff20e 100644 --- a/dist/languages/pl_PL.ts +++ b/dist/languages/pl_PL.ts @@ -70,45 +70,50 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Polecenie Pica załadowane - + Pica command processed Polecenie Pica wykonane - + Incoming primitive batch Przychodząca prymitywna partia - + Finished primitive batch Zakończona prymitywna partia - + Vertex shader invocation Wywołanie cienieniowania Vertex - + Incoming display transfer Przychodzący transfer ekranu - + GSP command processed Polecenie GSP wykonane - + Buffers swapped Bufory zamienione + + + Unknown debug context event + + CalibrationConfigurationDialog @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } Gra - - + + Block Player Zablokuj Gracza - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? Jeżeli zablokujesz gracza, nie będziesz więcej otrzymywał wiadomości od niego.<br><br>Jesteś pewien, że chcesz zablokować %1? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected Połączono - + Disconnected Rozłączono - + %1 (%2/%3 members) - connected %1 (%2/%3 członków) - połączonych @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! Dziękujemy za zgłoszenie! + + + Submitting + + + + + Communication error + + + + + An error occured while sending the Testcase + + + + + Next + + ConfigureAudio @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + %1% @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration Konfiguracja Citry - + + + General Ogólne - + + + System System - + + + Input Sterowanie - + + + Graphics Obraz - + + + Audio Dźwięk - + + + Camera Kamera - + + + Debug Debug - + + + Web Sieć + + + + + UI + + + + + Controls + Sterowanie + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } Potwierdź wyjście, gdy emulator jest uruchomiony - - Interface language - Język Interfejsu - - - + Updates Aktualizacje - + Check for updates on start Sprawdź dostępność aktualizacji przy uruchomieniu - + Silently auto update after closing Automatycznie aktualizuj w tle po zamknięciu - + Emulation Emulacja - + Region: Region: - + Auto-select Wybór automatyczny - - Theme - Motyw - - - - Theme: - Motyw: - - - + Hotkeys Skróty klawiszowe - - <System> - <System> + + Reset All Settings + - - English - Angielski + + Citra + + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick Ustaw Analog @@ -1067,11 +1110,44 @@ p, li { white-space: pre-wrap; } + Clear All + Wyczyść Wszystko + + + Restore Defaults Przywróć Domyślne - + + + Clear + Wyczyść + + + + + [not set] + [nieustawione] + + + + + Restore Default + Przywróć Domyślne + + + + Information + Informacja + + + + After pressing OK, first move your joystick horizontally, and then vertically. + Po naciśnięciu OK, wykonaj ruch analogiem horyzontalnie, a następnie wertykalnie. + + + [press key] [naciśnij przycisk] @@ -1440,17 +1516,27 @@ p, li { white-space: pre-wrap; } Czas Uruchomienia - + + yyyy-MM-ddTHH:mm:ss + + + + + Play Coins: + Monety Gry: + + + Console ID: ID konsoli: - + Regenerate Regeneruj - + System settings are available only when game is not running. Ustawienia systemowe są dostępne tylko wtedy, gdy gra nie jest uruchomiona @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } Bermudy - - + + Console ID: 0x%1 ID konsoli: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? To zastąpi twojego obecnego wirtualnego 3DS. Odzyskanie twojego obecnego 3DS będzie niemożliwe. To może spowodować niespodziewane efekty w grach. Operacja może się nie powieść jeżeli korzystasz z przestarzałej konfiguracji zapisów gier. Kontynuować? - + Warning Ostrzeżenie + + ConfigureUi + + + Form + + + + + General + + + + + Interface language: + + + + + Theme: + + + + + Game List + + + + + Icon Size: + + + + + + None + + + + + Small (24x24) + + + + + Large (48x48) + + + + + Row 1 Text: + + + + + + File Name + + + + + + Full Path + + + + + + Title Name + + + + + + Title ID + + + + + Row 2 Text: + + + + + Hide Titles without Icon + + + + + <System> + + + + + English + + + ConfigureWeb @@ -2155,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify Zweryfikuj @@ -2215,48 +2399,48 @@ p, li { white-space: pre-wrap; } Pokaż obecnie włączoną grę w statusie na Discrodzie - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Dowiedz się więcej</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Zarejestruj się</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">Czym jest mój token?</span></a> - - + + Telemetry ID: 0x%1 ID Telemetrii: 0x%1 - + Username and token not verified Nazwa Użytkownika i Token nie są zweryfikowane - + Username and token were not verified. The changes to your username and/or token have not been saved. Nazwa Użytkownika i Token nie zostały zweryfikowane. Zmiana Nazwy Użytkownika i/lub Tokenu nie została zapisana - + Verifying Weryfikowanie - + Verification failed Weryfikacja nieudana - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. Weryfikacja nieudana. Sprawdź czy wprowadziłeś swoją nazwę użytkownika i swój token prawidłowo, a także czy twoje połączenie internetowe jest sprawne. @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting Łączenie - + Connect Połączono @@ -2330,413 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonimowe dane są zbierane</a> w celu wsparcia rozwoju Citry. <br/><br/>Czy chciałbyś się z nami podzielić danymi użytkowania? - + Telemetry Telemetria - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Obecna szybkość emulacji. Wartości większe lub mniejsze niż 100 % oznaczają, że emulacja jest szybsza lub wolniejsza niż 3DS - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Jak wiele klatek na sekundę gra wyświetla w tej chwili. Ta wartość będzie się różniła między grami, jak również między scenami w grze. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Czas potrzebny do emulacji klatki 3DS, nie zawiera limitowania klatek oraz v-sync. Dla pełnej prędkości emulacji, wartość nie powinna przekraczać 16.67 ms. - + Clear Recent Files Wyczyść Ostatnio Używane - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available Aktualizacja dostępna - + An update is available. Would you like to install it now? Aktualizacja jest dostępna. Chciałbyś ją teraz zainstalować? - + No Update Found Nie znaleziono aktualizacji - + No update is found. Nie znaleziono aktualizacji - - + + OpenGL 3.3 Unsupported + + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + + + + + Invalid ROM Format Nieprawidłowy format ROMu - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Format Twojego ROMu nie jest wspierany.<br/>Wykonaj ROM ponownie korzystając z naszych poradników <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>gry na kartridżach</a> lub <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>tytuły zainstalowane</a>. - + ROM Corrupted ROM jest uszkodzony - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Twój ROM jest uszkodzony.<br/>Wykonaj ROM ponownie korzystając z naszych poradników <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>gry na kartridżach</a> lub <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>tytuły zainstalowane</a>. - + ROM Encrypted ROM jest zaszyfrowany - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Twój ROM jest zaszyfrowany.<br/>Wykonaj ROM ponownie korzystając z naszych poradników <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>gry na kartridżach</a> lub <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>tytuły zainstalowane</a>. - - + + Video Core Error Błąd Rdzenia Wideo - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. Wystąpił błąd. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Spójrz w log</a>, aby dowiedzieć się więcej. Upewnij się, że posiadasz najnowsze sterowniki dla swojej kraty graficznej. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. Korzystasz z domyślnych sterowników systemu Windows dla swojej karty graficznej. Zainstaluj sterowniki dostarczane przez producenta twojej karty graficznej. - + Error while loading ROM! Błąd podczas ładowania ROM'u! - + An unknown error occured. Please see the log for more details. Wystąpił nieznany błąd. Sprawdź logi, aby dowiedzieć się więcej. - + Start Start - + Error Opening %1 Folder Błąd podczas otwierania folderu %1 - - + + Folder does not exist! Folder nie istnieje! - + Error Opening %1 Błąd podczas otwierania %1 - + Select Directory Wybierz Folder - - 3DS Executable - Plik wykonywalny 3DS'a + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + - - - All Files (*.*) - Wszystkie Pliki (*.*) - - - + Load File Załaduj Plik - + Load Files Załaduj Pliki - + 3DS Installation File (*.CIA*) Plik Instalacyjny 3DS'a (*.CIA*) - + + All Files (*.*) + Wszystkie Pliki (*.*) + + + %1 has been installed successfully. %1 został poprawnie zainstalowany. - + Unable to open File Nie można otworzyć Pliku - + Could not open %1 Nie można otworzyć %1 - + Installation aborted Instalacja przerwana - + The installation of %1 was aborted. Please see the log for more details Instalacja %1 została przerwana. Sprawdź logi, aby uzyskać więcej informacji. - + Invalid File Niepoprawny Plik - + %1 is not a valid CIA %1 nie jest prawidłowym plikiem CIA - + Encrypted File Plik Zaszyfrowany - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 musi zostać zdeszyfrowany przed użyciem w Citra. Prawdziwy 3DS jest wymagany. - + File not found Nie znaleziono pliku - + File "%1" not found Nie znaleziono pliku "%1" - - - + + + Continue Kontynuuj - + Missing Citra Account Brakuje konta Citra - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. Musisz podłączyć Citrę do swojego konta, aby móc zgłosić przypadek testowy.<br/>Przejdź do Emulacja &gt; Skonfiguruj... &gt; Sieć, aby tego dokonać. - - - + + Amiibo File (%1);; All Files (*.*) + + + + + Load Amiibo + + + + + + + Record Movie Nagraj Film - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + + + + + Citra TAS Movie (*.ctm) Citra TAS Movie (*.ctm) - + Recording will start once you boot a game. Nagrywanie rozpocznie się wraz ze startem gry. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? Nagranie, które próbujesz odtworzyć pochodzi z innej wersji Citry. <br/> Citra wprowadziła pewne zmiany w tym czasie, odtwarzanie może być niezsynchronizowane lub może nie działać zgodnie z założeniami. <br/><br/> Jesteś pewien, że chcesz załadować ten plik? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? Nagranie, które próbujesz załadować pochodzi z innej gry. <br/> Odtwarzanie może nie działać zgodnie poprawnie i może wiązać się z nieoczekiwanym rezultatem. <br/><br/> Jesteś pewien, że chcesz załadować ten plik? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. Nagranie, które próbujesz odtworzyć jest nieprawidłowe. <br/> Może być uszkodzone, lub Citra wprowadziła spore zmiany w module Filmów. <br/>Spróbuj ponownie z innym plikiem nagrania. - + Revision Dismatch Niepasująca Rewizja - + Game Dismatch Niepasująca Gra - - + + Invalid Movie File Nieprawidłowy Plik Filmu - + + Play Movie Odtwórz Film - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + + + + Game Not Found Nie Znaleziono Gry - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. Nagranie, które próbujesz odtworzyć pochodzi z gry, której nie masz na swojej liście. Jeżeli posiadasz tę grę, dodaj ją do swojej listy i spróbuj odtworzyć nagranie ponownie. - + Movie recording cancelled. Nagrywanie zostało przerwane. - + Movie Saved Zapisano Film - + The movie is successfully saved. Film został poprawnie zapisany. - + Speed: %1% / %2% Prędkość: %1% / %2% - + Speed: %1% Prędkość: %1% - + Game: %1 FPS Gra: %1 FPS - + Frame: %1 ms Klatka: %1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. Brakuje %1. <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>Zgraj swoje archiva systemowe</a>.<br/>Kontynuowanie emulacji może wiązać się z błędami oraz awariami gry. - + System Archive Not Found Archiwum Systemowe nie zostało odnalezione - + Fatal Error Błąd Krytyczny - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. Wystąpił błąd krytyczny. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Spójrz w log</a>, aby dowiedzieć się więcej.<br/>Kontynuowanie emulacji może wiązać się z błędami oraz awariami gry. - + Abort Przerwij - - + + Citra Citra - + Would you like to exit now? Czy chcesz teraz wyjść? - + The game is still running. Would you like to stop emulation? Gra jest nadal uruchomiona. Czy chcesz przerwać emulację? - + Playback Completed Odtwarzanie Zakończone - + Movie playback completed. Odtwarzanie filmu zostało zakończone. - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2799,37 +3015,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + + + + + Compatibility + + + + + Region + + + + + File type + + + + + Size + + + + Open Save Data Location Otwórz Lokalizację Zapisów Gry - + + Open Extra Data Location + Otwórz Dodatkową Lokalizację Aplikacji + + + Open Application Location Otwórz Lokalizację Aplikacji - + Open Update Data Location Otwórz Lokalizację Aktualizacji - + Navigate to GameDB entry Przejdź do wpisu w bazie gier - + Scan Subfolders Przeszukaj Podkatalogi - + Remove Game Directory Usuń Katalog Gier - + Open Directory Location Otwórz lokalizację katalogu @@ -2837,78 +3083,78 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect Idealna - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. Gra działa bez zarzutu, bez błędów graficznych lub dźwiękowych. Nie potrzebuje żadnych obejść ani poprawek. - + Great Świetna - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. Gra działa z pomniejszymi błędami dźwiękowymi lub graficznymi, jest grywalna od początku do końca. Może wymagać kilku obejść/poprawek. - + Okay W porządku - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. Gra działa z większymi błędami dźwiękowymi lub graficznymi, ale jest grywalna od początku do końca. Może wymagać kilku obejść/poprawek. - + Bad Zła - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. Gra działa z większymi błędami dźwiękowymi lub graficznymi. Niemożliwe jest przejście konkretnych miejsc nawet z obejściami. - + Intro/Menu Intro/Menu - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. Gra jest całkowicie niegrywalna z uwagi na poważne błędy graficzne lub dźwiękowe. Działa jedynie ekran startowy. - + Won't Boot Nie uruchamia się - + The game crashes when attempting to startup. Gra wysypuje się przy próbie uruchomienia - + Not Tested Nieprzetestowana - + The game has not yet been tested. Gra nie została jeszcze przetestowana. @@ -2916,7 +3162,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the game list Dwuklik, aby dodać nowy folder do listy gier @@ -2924,27 +3170,27 @@ Screen. GameListSearchField - + of z - + result wynik - + results wyniki - + Filter: Filtr: - + Enter pattern to filter Wprowadź wzór filtra @@ -2952,23 +3198,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Punkty przerwania Pica - - + + Emulation running Emulacja uruchomiona - + Resume Wznów - + Emulation halted at breakpoint Emulacja zatrzymana w punkcie przerwania @@ -3385,42 +3631,42 @@ Screen. Odśwież Lobby - + Password Required to Join Wymagane Hasło, aby Dołączyć - + Password: Hasło: - + Room Name Nazwa Pokoju - + Preferred Game Preferowana Gra - + Host Gospodarz - + Players Graczy - + Refreshing Odświeżanie - + Refresh List Odśwież Listę @@ -3443,220 +3689,245 @@ Screen. Ostatnio Używane - + + Amiibo + + + + &Emulation &Emulacja - + &View &Widok - + Debugging Debugowanie - + Screen Layout Układ Ekranów: - + Movie Film - + Multiplayer Multiplayer - + &Help &Pomoc - + Load File... Załaduj Plik... - + Install CIA... Instaluj CIA... - + Load Symbol Map... Ładowanie Mapy Symboli... - + E&xit &Wyjście - + &Start &Uruchom - + &Pause &Pauza - + &Stop &Zatrzymaj - + FAQ FAQ - + About Citra O Citra - + Single Window Mode Tryb Pojedynczego Okna - + Configure... Skonfiguruj... - + Display Dock Widget Headers Wyświetl Nagłówki Widgetów. - + Show Filter Bar Pokaż Pasek Filtrowania - + Show Status Bar Pokaż Pasek Statusu - + Select Game Directory... Wybierz Katalog Gier... - + Selects a folder to display in the game list Wybiera katalog, z którego ma załadować listę gier - + Create Pica Surface Viewer Stwórz Podgląd Powierzchni Pica - + Record Movie Nagraj Film - + Play Movie Odtwórz Film - + Stop Recording / Playback Przerwij Nagrywanie / Odtwarzanie - + + Enable Frame Advancing + + + + + Advance Frame + + + + Browse Public Game Lobby Przeglądaj Publiczne Pokoje - + Create Room Stwórz Pokój - + Leave Room Opóść Pokój - + Direct Connect to Room Bezpośrednie Połączenie z Pokojem - + Show Current Room Pokaż Aktualny Pokój - + Fullscreen Pełny Ekran - + Modify Citra Install Zmodyfikuj instalację Citry - + Opens the maintenance tool to modify your Citra installation Otwiera narzędzie do modyfikacji twojej instalacji Citry - + Default Domyślny - + Single Screen Pojedynczy Ekran - + Large Screen Duży Ekran - + Side by Side Obok Siebie - + Swap Screens Zamień Ekrany - + Check for Updates Sprawdź dostępność Aktualizacji - + Report Compatibility Zgłoś Kompatybilność - + Restart Zrestartuj + + + Load... + + + + + Remove + + MicroProfileDialog @@ -3682,23 +3953,23 @@ Screen. - + Connected Połączono - + Not Connected Nie Połączono - + Error Błąd - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: Nie udało się rozgłosić pokoju na publicznej liście. W celu hostowania publicznego pokoju, niezbędne jest skonfigurowanie konta Citra w Emulacja - > Skonfiguruj...-> Sieć. Jeżeli nie chcesz upubliczniać pokoju, wybierz Niewidoczny podczas jego tworzenia. @@ -3817,106 +4088,106 @@ Debug: %1 gra w %2 - - + + Invalid region Nieprawidłowy region - + Japan Japonia - + North America Ameryka Północna - + Europe Europa - + Australia Australia - + China Chiny - + Korea Korea - + Taiwan Tajwan - + Region free Bez ograniczenia regionalnego - + Invalid Region Nieprawidłowy Region - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [nie ustawiono] - + Hat %1 %2 Kapelusz %1 %2 - + Axis %1%2 Osie %1%2 - + Button %1 Przycisk %1 - - + + [unknown] [nieznany] - + [unused] [nieużywany] - - + + Axis %1 Oś %1 diff --git a/dist/languages/pt_BR.ts b/dist/languages/pt_BR.ts index 64664cfaf..248fc029e 100644 --- a/dist/languages/pt_BR.ts +++ b/dist/languages/pt_BR.ts @@ -64,58 +64,63 @@ p, li { white-space: pre-wrap; } <html><head/><body><p><span style=" font-size:7pt;">&quot;3DS&quot; is a trademark of Nintendo. Citra is not affiliated with Nintendo in any way.</span></p></body></html> - <html><head/><body><p><span style=" font-size:7pt;">&quot;3DS&quot; é uma marca da Nintendo. Citra não é afiliado com a Nintendo de nenhuma forma.</span></p></body></html> + <html><head/><body><p><span style=" font-size:7pt;">&quot;3DS&quot; é uma marca da Nintendo. O Citra não é afiliado com a Nintendo de nenhuma forma.</span></p></body></html> BreakPointModel - + Pica command loaded Comando Pica carregado - + Pica command processed Comando Pica processado - + Incoming primitive batch - Recebendo Primitive batch + Recebendo primitive batch - + Finished primitive batch Primitive batch finalizado - + Vertex shader invocation - Invocação de Vertex Shader + Invocação de vertex shader - + Incoming display transfer - Transferência de display iminente + Recebendo transferência de display - + GSP command processed Comando GSP processado - + Buffers swapped Buffers trocados + + + Unknown debug context event + Evento de contexto de depuração desconhecido + CalibrationConfigurationDialog Communicating with the server... - Conectando ao servidor... + Conectando-se ao servidor... @@ -171,15 +176,15 @@ p, li { white-space: pre-wrap; } Jogo - - + + Block Player Bloquear jogador - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? - Ao bloquear um jogador, você não irá mais receber mensagens dele no chat.<br><br>Deseja mesmo bloquear %1? + Ao bloquear um jogador, você não receberá mais mensagens dele no chat.<br><br>Deseja mesmo bloquear %1? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected Conectado - + Disconnected Desconectado - + %1 (%2/%3 members) - connected %1 (%2/%3 membros) - conectado @@ -218,18 +223,18 @@ p, li { white-space: pre-wrap; } Report Compatibility - Informar compatibilidade + Relatar compatibilidade Report Game Compatibility - Informar compatibilidade de jogo + Relatar compatibilidade de jogo <html><head/><body><p><span style=" font-size:10pt;">Should you choose to submit a test case to the </span><a href="https://citra-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Citra Compatibility List</span></a><span style=" font-size:10pt;">, The following information will be collected and displayed on the site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware Information (CPU / GPU / Operating System)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Which version of Citra you are running</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The connected Citra account</li></ul></body></html> - <html><head/><body><p><span style=" font-size:10pt;">Ao enviar um caso de teste à </span><a href="https://citra-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Lista de compatibilidade do Citra</span></a><span style=" font-size:10pt;">, as seguintes informações serão coletadas e exibidas no site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Informações de hardware (CPU / GPU / sistema operacional)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qual versão do Citra você está usando</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A conta do Citra conectada</li></ul></body></html> + <html><head/><body><p><span style=" font-size:10pt;">Ao enviar um caso de teste à </span><a href="https://citra-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">lista de compatibilidade do Citra</span></a><span style=" font-size:10pt;">, as seguintes informações serão recolhidas e exibidas no site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Informações de hardware (CPU / GPU / sistema operacional)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qual versão do Citra você está usando</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A conta do Citra conectada</li></ul></body></html> @@ -239,7 +244,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Game functions flawlessly with no audio or graphical glitches.</p></body></html> - <html><head/><body><p>O jogo funciona perfeitamente sem falhas no áudio ou nos gráficos.</p></body></html> + <html><head/><body><p>O jogo funciona impecavelmente, sem falhas no áudio ou nos gráficos.</p></body></html> @@ -259,7 +264,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.</p></body></html> - <html><head/><body><p>O jogo funciona com grandes falhas gráficas ou de áudio, mas o jogo é jogável do início ao fim com soluções alternativas.</p></body></html> + <html><head/><body><p>O jogo funciona com grandes falhas gráficas ou de áudio, mas é jogável do início ao fim com o uso de soluções alternativas.</p></body></html> @@ -274,7 +279,7 @@ p, li { white-space: pre-wrap; } Intro/Menu - Intro/Menu + Intro/menu @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! Agradecemos pelo seu relatório! + + + Submitting + Enviando + + + + Communication error + Erro de comunicação + + + + An error occured while sending the Testcase + Ocorreu um erro ao enviar o caso de testes + + + + Next + Próximo + ConfigureAudio @@ -312,22 +337,22 @@ p, li { white-space: pre-wrap; } Output Engine: - Engine de Saída: + Engine de saída: This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency. - Este efeito de pós-processamento ajusta a velocidade do áudio para acompanhar a velocidade de emulação e ajuda prevenir cortes no áudio. Isso entretanto aumenta a latência do áudio. + Este efeito de pós-processamento ajusta a velocidade do áudio para acompanhar a velocidade de emulação e ajuda a evitar cortes no áudio. No entanto, isto aumenta a latência do áudio. Enable audio stretching - Habilitar alongamento de áudio + Ativar alongamento de áudio Audio Device: - Dispositivo de Áudio: + Dispositivo de áudio: @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + %1% @@ -367,7 +392,7 @@ p, li { white-space: pre-wrap; } Camera to configure: - Câmera para configurar: + Câmera a configurar: @@ -435,7 +460,7 @@ p, li { white-space: pre-wrap; } Camera Image Source: - Caminho da imagem da câmera: + Fonte da imagem da câmera: @@ -527,7 +552,7 @@ p, li { white-space: pre-wrap; } Resolution: 512*384 - Resolução: 512*384 + Resolução: 512x384 @@ -542,12 +567,12 @@ p, li { white-space: pre-wrap; } Supported image files (%1) - Arquivos de imagem suportados (%1) + Arquivos de imagem compatíveis (%1) Open File - Abrir Arquivo + Abrir arquivo @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration Configurações do Citra - + + + General Geral - + + + System Sistema - + + + Input Controle - + + + Graphics Gráficos - + + + Audio Áudio - + + + Camera Câmera - + + + Debug - Debug + Depuração - + + + Web Rede + + + + + UI + Interface + + + + Controls + Controles + ConfigureGeneral @@ -666,67 +719,57 @@ p, li { white-space: pre-wrap; } Confirm exit while emulation is running - Confirmar saída quando a emulação estiver rodando + Confirmar saída quando a emulação estiver em execução - - Interface language - Idioma da interface - - - + Updates Atualizações - + Check for updates on start Verificar atualizações ao iniciar - + Silently auto update after closing Atualizar silenciosamente ao fechar - + Emulation Emulação - + Region: Região: - + Auto-select Seleção automática - - Theme - Tema - - - - Theme: - Tema: - - - + Hotkeys Teclas de atalho - - <System> - <Sistema> + + Reset All Settings + Redefinir todos os ajustes - - English - Inglês + + Citra + Citra + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + Deseja mesmo <b>restaurar as suas configurações ao padrão</b> e fechar o Citra? @@ -744,12 +787,12 @@ p, li { white-space: pre-wrap; } Enable V-Sync - Habilitar V-Sync + Ativar V-Sync Limit Speed Percent - Limitar Porcentagem de Velocidade + Limitar porcentagem de velocidade @@ -780,7 +823,7 @@ p, li { white-space: pre-wrap; } Auto (Window Size) - Automática (Tamanho da Janela) + Automática (tamanho da janela) @@ -790,52 +833,52 @@ p, li { white-space: pre-wrap; } 2x Native (800x480) - 2x Nativa (800x480) + 2x nativa (800x480) 3x Native (1200x720) - 3x Nativa (1200x720) + 3x nativa (1200x720) 4x Native (1600x960) - 4x Nativa (1600x960) + 4x nativa (1600x960) 5x Native (2000x1200) - 5x Nativa (2000x1200) + 5x nativa (2000x1200) 6x Native (2400x1440) - 6x Nativa (2400x1440) + 6x nativa (2400x1440) 7x Native (2800x1680) - 7x Nativa (2800x1680) + 7x nativa (2800x1680) 8x Native (3200x1920) - 8x Nativa (3200x1920) + 8x nativa (3200x1920) 9x Native (3600x2160) - 9x Nativa (3600x2160) + 9x nativa (3600x2160) 10x Native (4000x2400) - 10x Nativa (4000x2400) + 10x nativa (4000x2400) <html><head/><body><p>Use OpenGL to accelerate shader emulation.</p><p>Requires a relatively powerful GPU for better performance.</p></body></html> - <html><head/><body><p>Usa o OpenGL para acelerar a emulação de shaders.</p><p>Requer uma GPU relativamente poderosa para um melhor desempenho.</p></body></html> + <html><head/><body><p>Usa o OpenGL para acelerar a emulação de shaders.</p><p>Requer uma GPU relativamente potente para um melhor desempenho.</p></body></html> @@ -855,7 +898,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Force to fall back to software shader emulation when geometry shaders are used. </p><p>Some games require this to be enabled for the hardware shader to render properly.</p><p>However this might reduce performance in some games</p></body></html> - <html><head/><body><p>Força a emulação de shaders voltar a ser processada via software quando shaders de geometria forem usados. </p><p>Alguns jogos precisam que isto esteja ativado para que os shaders sejam adequadamente renderizados via hardware.</p><p>No entanto, isso pode reduzir o desempenho na maioria dos jogos.</p></body></html> + <html><head/><body><p>Força a emulação de shaders voltar a ser processada via software quando shaders de geometria forem usados. </p><p>Alguns jogos precisam que isto esteja ativado para que os shaders sejam adequadamente renderizados via hardware.</p><p>No entanto, isso pode reduzir o desempenho em alguns jogos.</p></body></html> @@ -865,7 +908,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p>Use the JIT engine instead of the interpreter for software shader emulation. </p><p>Enable this for better performance.</p></body></html> - <html><head/><body><p>Usa o mecanismo JIT (ao invés do interpretador) para emular shaders via software. </p><p>Ative isso para um melhor desempenho.</p></body></html> + <html><head/><body><p>Usa o mecanismo JIT (ao invés do interpretador) para emular shaders via software. </p><p>Ative isto para um melhor desempenho.</p></body></html> @@ -875,7 +918,7 @@ p, li { white-space: pre-wrap; } Layout - Layout + Estilo @@ -885,7 +928,7 @@ p, li { white-space: pre-wrap; } Screen Layout: - Layout de tela: + Estilo de tela: @@ -910,7 +953,7 @@ p, li { white-space: pre-wrap; } Swap Screens - Trocar Telas + Trocar telas @@ -1026,9 +1069,9 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick - Definir Analog Stick + Definir direcional analógico @@ -1067,11 +1110,44 @@ p, li { white-space: pre-wrap; } + Clear All + Limpar tudo + + + Restore Defaults Restaurar padrões - + + + Clear + Limpar + + + + + [not set] + [não definido] + + + + + Restore Default + Restaurar padrão + + + + Information + Informação + + + + After pressing OK, first move your joystick horizontally, and then vertically. + Após pressionar OK, mova seu direcional analógico primeiro horizontalmente e depois verticalmente. + + + [press key] [pressione uma tecla] @@ -1239,7 +1315,7 @@ p, li { white-space: pre-wrap; } UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. - Teste UDP ou configuração de calibração está em progresso no momento.<br>Por favor, aguarde até a conclusão deles. + O teste UDP ou configuração de calibração está em progresso no momento.<br>Aguarde até a conclusão deles. @@ -1252,12 +1328,12 @@ p, li { white-space: pre-wrap; } System Settings - Configurações de Sistema + Configurações de sistema Username - Usuário + Nome de usuário @@ -1367,7 +1443,7 @@ p, li { white-space: pre-wrap; } Simplified Chinese (简体中文) - Chinês Simplificado (简体中文) + Chinês simplificado (简体中文) @@ -1392,7 +1468,7 @@ p, li { white-space: pre-wrap; } Traditional Chinese (正體中文) - Chinês Tradicional (正體中文) + Chinês tradicional (正體中文) @@ -1440,19 +1516,29 @@ p, li { white-space: pre-wrap; } Horário na inicialização - + + yyyy-MM-ddTHH:mm:ss + aaaa-MM-ddTHH:mm:ss + + + + Play Coins: + Moedas de jogo: + + + Console ID: ID do console: - + Regenerate Regerar - + System settings are available only when game is not running. - Configurações de sistema estão disponíveis apenas quando o game não estiver rodando. + As configurações de sistema estão disponíveis apenas quando não houver nenhum jogo em execução. @@ -1612,7 +1698,7 @@ p, li { white-space: pre-wrap; } Netherlands Antilles - Antilhas holandesas + Antilhas Holandesas @@ -1657,7 +1743,7 @@ p, li { white-space: pre-wrap; } Trinidad and Tobago - Trinidad e Tobago + Trindade e Tobago @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } Bermuda - - + + Console ID: 0x%1 ID do console: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? - Isso vai substituir seu 3DS virtual atual por um novo. Seu 3DS virtual atual não será recuperável. Isso pode causar efeitos inesperados em jogos. Isso pode falhar se você utilizar uma configuração de jogo salvo desatualizada. Continuar? + Isso vai substituir seu 3DS virtual atual por um novo. Seu 3DS virtual atual não será recuperável. Isto pode causar efeitos inesperados em jogos. Isto pode falhar se você utilizar uma configuração de jogo salvo desatualizada. Continuar? - + Warning Alerta + + ConfigureUi + + + Form + Formulário + + + + General + Geral + + + + Interface language: + Idioma da interface: + + + + Theme: + Tema: + + + + Game List + Lista de jogos + + + + Icon Size: + Tamanho do ícone: + + + + + None + Não mostrar + + + + Small (24x24) + Pequeno (24x24) + + + + Large (48x48) + Grande (48x48) + + + + Row 1 Text: + Texto da 1ª linha: + + + + + File Name + Nome do arquivo + + + + + Full Path + Caminho completo + + + + + Title Name + Nome do título + + + + + Title ID + ID do título + + + + Row 2 Text: + Texto da 2ª linha: + + + + Hide Titles without Icon + Ocultar títulos sem ícone + + + + <System> + <Sistema> + + + + English + Inglês (English) + + ConfigureWeb @@ -2151,18 +2335,18 @@ p, li { white-space: pre-wrap; } By providing your username and token, you agree to allow Citra to collect additional usage data, which may include user identifying information. - Ao preencher seu usuário e token, você concorda em permitir ao Citra coletar dados de uso adicionais, que podem incluir informações de identificação de usuário. + Ao informar seu usuário e token, você concorda em permitir ao Citra recolher dados de uso adicionais, que podem incluir informações de identificação de usuário. - + Verify Verificar Sign up - Cadastrar + Cadastrar-se @@ -2172,7 +2356,7 @@ p, li { white-space: pre-wrap; } Username: - Usuário: + Nome de usuário @@ -2197,7 +2381,7 @@ p, li { white-space: pre-wrap; } Telemetry ID: - ID de Telemetria: + ID de telemetria: @@ -2215,48 +2399,48 @@ p, li { white-space: pre-wrap; } Mostrar o jogo atual no seu status do Discord - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Saiba mais</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Cadastrar-se</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Cadastrar-se</span></a> - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">Qual é o meu token?</span></a> - - + + Telemetry ID: 0x%1 - ID de Telemetria: 0x%1 + ID de telemetria: 0x%1 - + Username and token not verified Nome de usuário e token não verificados - + Username and token were not verified. The changes to your username and/or token have not been saved. - Usuário e token não foram verificados. As mudanças de seu usuário e/ou token não foram salvas. + O nome de usuário e token não foram verificados. As mudanças do seu usuário e/ou token não foram salvas. - + Verifying Verificando - + Verification failed - Verificação falhou + A verificação falhou - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. A verificação falhou. Verifique se você colocou seu usuário e token corretamente, e se sua conexão com a internet está funcionando. @@ -2266,7 +2450,7 @@ p, li { white-space: pre-wrap; } Direct Connect - Conectar-se Diretamente + Conectar-se diretamente @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting Conectando - + Connect Conectar @@ -2330,414 +2514,446 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? - <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Dados anônimos são coletados</a> para ajudar a melhorar o Citra. <br/><br/>Gostaria de compartilhar seus dados de uso conosco? + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Dados anônimos são recolhidos</a> para ajudar a melhorar o Citra. <br/><br/>Gostaria de compartilhar os seus dados de uso conosco? - + Telemetry Telemetria - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. - Atual velocidade de emulação. Valores maiores ou menores que 100% indicam que a emulação está rodando mais rápida ou lentamente que um 3DS. + Atual velocidade de emulação. Valores maiores ou menores que 100% indicam que a emulação está rodando mais rápida ou lentamente que em um 3DS. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. - Quantos quadros por segundo o jogo está atualmente mostrando. Isto vai variar de jogo para jogo e cena para cena. + Quantos quadros por segundo o jogo está exibindo atualmente. Isto vai variar de jogo para jogo e cena para cena. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. - Tempo levado para emular um quadro do 3DS, não contando o limitador de framerate ou o v-sync. Para emulação em velocidade total isso deve ser pelo menos 16.67 ms. + Tempo levado para emular um quadro do 3DS, sem considerar o limitador de taxa de quadros ou o V-sync. Valores menores ou iguais a 16.67 ms indicam que a emulação está em velocidade plena. - + Clear Recent Files Limpar arquivos recentes - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available Atualização disponível - + An update is available. Would you like to install it now? Uma atualização está disponível. Gostaria de instalá-la agora? - + No Update Found Nenhuma atualização encontrada - + No update is found. Nenhuma atualização encontrada - - + + OpenGL 3.3 Unsupported + Sem suporte a OpenGL 3.3 + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + Ou sua GPU não é compatível com o OpenGL 3.3 ou você não possui o driver de gráficos mais recente. + + + + Invalid ROM Format Formato de ROM inválido - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. O formato da sua ROM é incompatível.<br/>Por favor, siga os guias para extrair jogos de seus <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>cartuchos de jogo</a> ou <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>títulos instalados</a>. - + ROM Corrupted ROM corrompida - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Sua ROM está corrompida.<br/>Por favor, siga os guias para extrair jogos de seus <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>cartuchos de jogo</a> ou <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>títulos instalados</a>. - + ROM Encrypted ROM encriptada - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Sua ROM está encriptada.<br/>Por favor, siga os guias para extrair jogos de seus <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>cartuchos de jogo</a> ou <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>títulos instalados</a>. - - + + Video Core Error Erro no núcleo de vídeo - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. - Um erro ocorreu. Para mais detalhes, <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>confira o log</a>. Verifique se os drivers mais recentes da sua GPU estão instalados. + Ocorreu um erro. Para mais detalhes, <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>confira o registro</a>. Verifique se os drivers mais recentes da sua GPU estão instalados. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. Você está usando os drivers padrão do Windows para a sua GPU. Você precisa instalar os drivers adequados para a sua placa de vídeo disponíveis no site da fabricante. - + Error while loading ROM! Erro ao carregar ROM! - + An unknown error occured. Please see the log for more details. - Um erro desconhecido ocorreu. Por favor veja o log para mais detalhes. + Ocorreu um erro desconhecido. Verifique o registro para mais detalhes. - + Start Iniciar - + Error Opening %1 Folder Erro ao abrir a pasta %1 - - + + Folder does not exist! - Pasta não existe! + A pasta não existe! - + Error Opening %1 Erro ao abrir %1 - + Select Directory - Selecionar Diretório + Selecionar pasta - - 3DS Executable - Executável 3DS + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + Executável do 3DS (%1);;Todos os arquivos (*.*) - - + + Load File + Carregar arquivo + + + + Load Files + Carregar arquivos + + + + 3DS Installation File (*.CIA*) + Arquivo de instalação 3DS (*.CIA*) + + + All Files (*.*) Todos os arquivos (*.*) - - Load File - Carregar Arquivo - - - - Load Files - Carregar Arquivos - - - - 3DS Installation File (*.CIA*) - Arquivo de Instalação 3DS (*.CIA*) - - - + %1 has been installed successfully. %1 foi instalado com sucesso. - + Unable to open File Não foi possível abrir o arquivo - + Could not open %1 Não foi possível abrir %1 - + Installation aborted Instalação cancelada - + The installation of %1 was aborted. Please see the log for more details - A instalação de %1 foi abortada. Verifique o log para mais detalhes + A instalação de %1 foi interrompida. Verifique o registro para mais detalhes - + Invalid File Arquivo inválido - + %1 is not a valid CIA %1 não é um CIA válido - + Encrypted File - Arquivo criptografado + Arquivo encriptado - + %1 must be decrypted before being used with Citra. A real 3DS is required. - %1 deve ser decriptado antes de ser usado no Citra. + %1 precisa ser decriptado antes de ser usado no Citra. É necessário um 3DS de verdade. - + File not found Arquivo não encontrado - + File "%1" not found Arquivo "%1" não encontrado - - - + + + Continue Continuar - + Missing Citra Account - Conta do Citra Faltando + Conta do Citra faltando - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. Você precisa entrar com sua conta do Citra para enviar casos de teste.<br/>Para isso, vá para Emulação &gt; Configurar... &gt; Rede. - - - + + Amiibo File (%1);; All Files (*.*) + Arquivo do Amiibo (%1);; Todos os arquivos (*.*) + + + + Load Amiibo + Carregar Amiibo + + + + + + Record Movie Gravar passos - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + Para manter consistência com sistemas de geração de números aleatórios (RNG), recomendamos começar a gravar assim que o jogo iniciar.<br>Você ainda deseja iniciar uma gravação agora? + + + + Citra TAS Movie (*.ctm) Arquivo de gravação TAS do Citra (*.ctm) - + Recording will start once you boot a game. A gravação será iniciada assim que você iniciar um jogo. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? A gravação que você está tentando carregar foi criada em uma revisão diferente do Citra.<br/>O Citra sofreu algumas mudanças com o passar do tempo e, por causa disso, a reprodução pode dessincronizar ou não funcionar como o esperado.<br/><br/>Você ainda deseja carregar esta gravação? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? - A gravação que você está tentando carregar foi criada com um jogo diferente.<br/>A reprodução pode não funcionar como o esperado, podendo causar resultados inesperados.<br/><br/>Você ainda deseja carregar esta gravação? + A gravação que você está tentando carregar foi criada em um jogo diferente.<br/>A reprodução pode não funcionar adequadamente, podendo causar resultados inesperados.<br/><br/>Você ainda deseja carregar esta gravação? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. O arquivo de gravação que você está tentando carregar é inválido.<br/>Ou o arquivo está corrompido ou o Citra passou por grandes mudanças em seu módulo de gravações.<br/>Por favor, escolha um arquivo de gravação diferente e tente novamente. - + Revision Dismatch Discrepância de revisões - + Game Dismatch Discrepância de jogos - - + + Invalid Movie File Arquivo de gravação inválido - + + Play Movie Reproduzir gravação - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + Para manter consistência com sistemas de geração de números aleatórios (RNG), recomendamos começar a reproduzir a gravação assim que o jogo iniciar.<br>Você ainda deseja reproduzir uma gravação agora? + + + Game Not Found Jogo não encontrado - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. A gravação que você está tentando reproduzir é de um jogo que não está presente na sua lista de jogos. Se você tiver esse jogo, adicione a pasta dele à lista de jogos e tente reproduzir a gravação novamente. - + Movie recording cancelled. Gravação cancelada. - + Movie Saved Gravação salva - + The movie is successfully saved. A gravação foi salva com sucesso. - + Speed: %1% / %2% Velocidade: %1% / %2% - + Speed: %1% Velocidade: %1% - + Game: %1 FPS Jogo: %1 FPS - + Frame: %1 ms Quadro: %1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. %1 está faltando. Por favor, <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>faça a extração dos arquivos do seu sistema</a>.<br/>Continuar a emulação pode resultar em travamentos e bugs. - + System Archive Not Found - Arquivo de Sistema não Encontrado + Arquivo de sistema não encontrado - + Fatal Error - Erro Fatal + Erro fatal - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - Um erro fatal ocorreu. Para mais detalhes, <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>confira o log</a>. Continuar a emulação pode resultar em travamentos e bugs. + Ocorreu um erro fatal. Para mais detalhes, <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>confira o registro</a>. Continuar a emulação pode resultar em travamentos e bugs. - + Abort - Abortar + Interromper - - + + Citra Citra - + Would you like to exit now? Deseja sair agora? - + The game is still running. Would you like to stop emulation? - O jogo ainda está rodando. Deseja parar a emulação? + O jogo ainda está em execução. Deseja parar a emulação? - + Playback Completed Reprodução concluída - + Movie playback completed. Reprodução dos passos concluída. - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2747,7 +2963,7 @@ p, li { white-space: pre-wrap; } Command Name - Nome do Comando + Nome do comando @@ -2762,7 +2978,7 @@ p, li { white-space: pre-wrap; } New Value - Novo Valor + Novo valor @@ -2770,23 +2986,23 @@ p, li { white-space: pre-wrap; } Pica Command List - Lista de Comandos Pica + Lista de comandos Pica Start Tracing - Iniciar Tracing + Iniciar rastreamento Copy All - Copiar todos + Copiar tudo Finish Tracing - Finalizar Tracing + Finalizar rastreamento @@ -2794,43 +3010,73 @@ p, li { white-space: pre-wrap; } Graphics Debugger - Debugger Gráfico + Depurador gráfico GameList - + + Name + Nome + + + + Compatibility + Compatibilidade + + + + Region + Região + + + + File type + Tipo de arquivo + + + + Size + Tamanho + + + Open Save Data Location - Abrir Local dos Dados Salvos + Abrir local dos dados salvos - + + Open Extra Data Location + Abrir local dos dados extras + + + Open Application Location - Abrir Local do Aplicativo + Abrir local do aplicativo - + Open Update Data Location - Abrir Local dos Dados de Atualizações + Abrir local dos dados de atualizações - + Navigate to GameDB entry Abrir artigo do jogo no GameDB - + Scan Subfolders Escanear subpastas - + Remove Game Directory Remover pasta de jogos - + Open Directory Location Abrir local da pasta @@ -2838,82 +3084,82 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect Perfeito - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - O jogo roda impecavelmente, sem nenhum problema no áudio ou nos gráficos. Todos os recursos testados + O jogo funciona impecavelmente, sem nenhum problema no áudio ou nos gráficos. Todos os recursos testados do jogo funcionam como deveriam, sem nenhuma solução alternativa necessária. - + Great Ótimo - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - O jogo roda com pequenos problemas nos gráficos ou no áudio e é jogável do início ao fim. Pode exigir + O jogo funciona com pequenos problemas nos gráficos ou no áudio e é jogável do início ao fim. Pode exigir algumas soluções alternativas. - + Okay Razoável - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. - O jogo roda com grandes problemas nos gráficos ou no áudio, mas é jogável do início ao fim + O jogo funciona com grandes problemas nos gráficos ou no áudio, mas é jogável do início ao fim com o uso de soluções alternativas. - + Bad Ruim - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - O jogo roda, só que com problemas significativos nos gráficos ou no áudio. Não é possível progredir em áreas + O jogo funciona, só que com problemas significativos nos gráficos ou no áudio. Não é possível progredir em áreas específicas por conta de tais problemas, mesmo com soluções alternativas. - + Intro/Menu Intro/menu - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. É impossível jogar o jogo devido a grandes problemas nos gráficos ou no áudio. Não é possível passar da tela inicial do jogo. - + Won't Boot Não inicia - + The game crashes when attempting to startup. O jogo trava ou se encerra abruptamente ao se tentar iniciá-lo. - + Not Tested Não testado - + The game has not yet been tested. O jogo ainda não foi testado. @@ -2921,7 +3167,7 @@ tela inicial do jogo. GameListPlaceholder - + Double-click to add a new folder to the game list Clique duas vezes para adicionar uma nova pasta à lista de jogos @@ -2929,27 +3175,27 @@ tela inicial do jogo. GameListSearchField - + of de - + result resultado - + results resultados - + Filter: Filtro: - + Enter pattern to filter Digite o padrão para filtrar @@ -2957,25 +3203,25 @@ tela inicial do jogo. GraphicsBreakPointsWidget - + Pica Breakpoints - Pica Breakpoints + Pontos de interrupção Pica - - + + Emulation running - Emulação rodando + Emulação em execução - + Resume Retomar - + Emulation halted at breakpoint - Emulação interrompida no breakpoint + Emulação interrompida no ponto de interrupção @@ -2983,17 +3229,17 @@ tela inicial do jogo. Pica Surface Viewer - Visualizador de Superfície Pica + Visualizador de superfícies Pica Color Buffer - Buffer de Cor + Buffer de cor Depth Buffer - Buffer de Profundidade + Buffer de profundidade @@ -3073,7 +3319,7 @@ tela inicial do jogo. (unable to access pixel data) - (incapaz de acessar dado de pixel) + (não é possível acessar o dado do pixel) @@ -3098,7 +3344,7 @@ tela inicial do jogo. Save Surface - Salvar Superfície + Salvar superfície @@ -3111,17 +3357,17 @@ tela inicial do jogo. Start Recording - Iniciar Gravação + Iniciar gravação Stop and Save - Parar e Salvar + Parar e salvar Abort Recording - Interromper Gravação + Interromper gravação @@ -3141,7 +3387,7 @@ tela inicial do jogo. A CiTrace is still being recorded. Do you want to save it? If not, all recorded data will be discarded. - Um CiTrace ainda está sendo gravado. Deseja salva-lo ? Se não, todos os dados gravados serão descartados. + Um CiTrace ainda está sendo gravado. Deseja salvá-lo? Caso contrário, todos os dados gravados serão descartados. @@ -3167,17 +3413,17 @@ tela inicial do jogo. Save Shader Dump - Salvar Extração de Shader + Salvar extração de shader Shader Binary (*.shbin) - Shader Binary (*.shbin) + Shader binário (*.shbin) (data only available at vertex shader invocation breakpoints) - (dados apenas disponíveis nos breakpoints de invocação do vertex shader) + (dados apenas disponíveis nos pontos de interrupção de invocação de vertex shaders) @@ -3187,7 +3433,7 @@ tela inicial do jogo. Input Data - Dado de Entrada + Dado de entrada @@ -3197,7 +3443,7 @@ tela inicial do jogo. Cycle Index: - Índice Cíclico: + Índice cíclico: @@ -3238,35 +3484,35 @@ tela inicial do jogo. Address Registers: %1, %2 - Registradores de Endereço: %1, %2 + Registradores de endereço: %1, %2 Compare Result: %1, %2 - Comparar Resultado: %1, %2 + Comparar resultado: %1, %2 Static Condition: %1 - Condição Estática: %1 + Condição estática: %1 Dynamic Conditions: %1, %2 - Condições Dinâmicas: %1, %2 + Condições dinâmicas: %1, %2 Loop Parameters: %1 (repeats), %2 (initializer), %3 (increment), %4 - Parametros de loop: %1 (repetições), %2 (inicializador), %3 (incremento), %4 + Parâmetros de loop: %1 (repetições), %2 (inicializador), %3 (incremento), %4 @@ -3290,27 +3536,27 @@ tela inicial do jogo. Create Room - Criar Sala + Criar sala Room Name - Nome da Sala + Nome da sala Preferred Game - Jogo Preferido + Jogo preferido Max Players - Máximo de Jogadores + Máximo de jogadores Username - Nome de Usuário + Nome de usuário @@ -3335,12 +3581,12 @@ tela inicial do jogo. Unlisted - Não Listada + Não listada Host Room - Hospedar Sala + Hospedar sala @@ -3356,7 +3602,7 @@ tela inicial do jogo. Public Room Browser - Navegador de Salas Públicas + Navegador de salas públicas @@ -3382,52 +3628,52 @@ tela inicial do jogo. Hide Full Rooms - Esconder salas cheias + Ocultar salas cheias Refresh Lobby - Atualizar Lobby + Atualizar lobby - + Password Required to Join É necessária uma senha para entrar - + Password: Senha: - + Room Name - Nome da Sala + Nome da sala - + Preferred Game - Jogo Preferido + Jogo preferido - + Host Host - + Players Jogadores - + Refreshing Atualizando - + Refresh List - Atualizar Lista + Atualizar lista @@ -3448,220 +3694,245 @@ tela inicial do jogo. Arquivos recentes - + + Amiibo + Amiibo + + + &Emulation &Emulação - + &View &Exibir - + Debugging Debugging - + Screen Layout - Layout da tela - - - - Movie - Gravador + Estilo da tela - Multiplayer - Multiplayer + Movie + Gravações - + + Multiplayer + Multijogador + + + &Help A&juda - + Load File... Carregar arquivo... - + Install CIA... Instalar CIA... - + Load Symbol Map... - Carregar Mapa de Símbolos... + Carregar mapa de símbolos... - + E&xit &Sair - + &Start &Iniciar - + &Pause &Pausar - + &Stop P&arar - + FAQ - FAQ + Perguntas frequentes - + About Citra Sobre o Citra - + Single Window Mode - Modo Janela Única + Modo de janela única - + Configure... Configurar... - + Display Dock Widget Headers - Exibir Cabeçalhos do Widget do Dock + Exibir títulos de widgets afixados - + Show Filter Bar Mostrar barra de filtro - + Show Status Bar Mostrar barra de status - + Select Game Directory... - Selecionar diretório de jogos... + Selecionar pasta de jogos... - + Selects a folder to display in the game list Selecionar a pasta para exibir na lista de jogos - + Create Pica Surface Viewer - Visualizador do Criador de Superfície Pica + Criar visualizador de superfícies Pica - + Record Movie Gravar passos - + Play Movie Reproduzir gravação - + Stop Recording / Playback Parar gravação/reprodução - + + Enable Frame Advancing + Ativar avanço de quadros + + + + Advance Frame + Avançar quadro + + + Browse Public Game Lobby - Navegar pelas Salas Públicas + Navegar pelas salas públicas - + Create Room - Criar Sala + Criar sala - + Leave Room - Sair da Sala + Sair da sala - + Direct Connect to Room - Conectar-se diretamente a uma Sala + Conectar-se diretamente a uma sala - + Show Current Room - Mostrar Sala Atual + Mostrar sala atual - + Fullscreen Tela cheia - + Modify Citra Install Modificar instalação do Citra - + Opens the maintenance tool to modify your Citra installation Abre a ferramenta de manutenção para modificar sua instalação do Citra - + Default Padrão - + Single Screen Tela única - + Large Screen Tela grande - + Side by Side Lado a lado - + Swap Screens Trocar telas - + Check for Updates Verificar atualizações - + Report Compatibility - Informar compatibilidade + Relatar compatibilidade - + Restart Reiniciar + + + Load... + Carregar... + + + + Remove + Remover + MicroProfileDialog @@ -3677,7 +3948,7 @@ tela inicial do jogo. Current connection status - Status atual de conexão + Estado atual da conexão @@ -3687,26 +3958,26 @@ tela inicial do jogo. - + Connected Conectado - + Not Connected Não conectado - + Error Erro - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: - Falha ao anunciar a sala no lobby público. Para poder hospedar uma sala publicamente, você deve ter uma conta válida do Citra configurada em Emulação > Configurar... > Rede. Se você não quiser publicar uma sala no lobby público, deixe-a como Não Listada. + Falha ao anunciar a sala no lobby público. Para poder hospedar uma sala publicamente, você precisa ter uma conta válida do Citra configurada em Emulação > Configurar... > Rede. Se você não quiser publicar uma sala no lobby público, deixe-a como não listada. Mensagem para depuração: @@ -3715,12 +3986,12 @@ Mensagem para depuração: Username is not valid. Must be 4 to 20 alphanumeric characters. - Nome de usuário não é válido. Deve conter entre 4 e 20 caracteres alfanuméricos. + Nome de usuário inválido. Precisa ter entre 4 e 20 caracteres alfanuméricos. Room name is not valid. Must be 4 to 20 alphanumeric characters. - Nome da sala não é válido. Deve conter entre 4 e 20 caracteres alfanuméricos. + Nome da sala inválido. Precisa ter entre 4 e 20 caracteres alfanuméricos. @@ -3735,7 +4006,7 @@ Mensagem para depuração: Port must be a number between 0 to 65535. - Porta deve ser um número entre 0 e 65535. + A porta deve ser um número entre 0 e 65535. @@ -3745,7 +4016,7 @@ Mensagem para depuração: Unable to connect to the host. Verify that the connection settings are correct. If you still cannot connect, contact the room host and verify that the host is properly configured with the external port forwarded. - Não foi possível se conectar ao host. Verifique se as configurações de conexão estão corretas. Se você ainda não puder se conectar, entre em contato com o dono da sala e verifique se as configurações da sala e o encaminhamento externo da porta estão corretos. + Não foi possível se conectar ao host. Verifique se as configurações de conexão estão corretas. Se ainda assim você não conseguir se conectar, entre em contato com o dono da sala e verifique se as configurações da sala e o encaminhamento externo da porta estão corretos. @@ -3760,7 +4031,7 @@ Mensagem para depuração: Version mismatch! Please update to the latest version of Citra. If the problem persists, contact the room host and ask them to update the server. - Incompatibilidade de versões! Por favor, atualize seu Citra para a última versão. Se o problema persistir, entre em contato com o dono da sala e peça para que atualize o servidor. + Incompatibilidade de versões! Por favor, atualize seu Citra para a versão mais recente. Se o problema persistir, entre em contato com o dono da sala e peça para que atualize o servidor. @@ -3770,7 +4041,7 @@ Mensagem para depuração: An unknown error occured. If this error continues to occur, please open an issue - Ocorreu um erro desconhecido. Se esse erro persistir, abra uma issue no GitHub + Ocorreu um erro desconhecido. Se esse erro persistir, relate-o no GitHub. @@ -3785,7 +4056,7 @@ Mensagem para depuração: Leave Room - Sair da Sala + Sair da sala @@ -3822,106 +4093,106 @@ Mensagem para depuração: %1 está jogando %2 - - + + Invalid region Região inválida - + Japan Japão - + North America América do Norte - + Europe Europa - + Australia Austrália - + China China - + Korea - Coréia + Coreia - + Taiwan Taiwan - + Region free Livre de região - + Invalid Region Região inválida - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [não definido] - + Hat %1 %2 Hat %1 %2 - + Axis %1%2 Eixo %1%2 - + Button %1 Botão %1 - - + + [unknown] [desconhecido] - + [unused] - [não usado] + [não utilizado] - - + + Axis %1 Eixo %1 @@ -3943,7 +4214,7 @@ Mensagem para depuração: Open File - Abrir Arquivo + Abrir arquivo @@ -3989,27 +4260,27 @@ Mensagem para depuração: VFP System Registers - Registradores de Sistema VFP + Registradores de sistema VFP Vector Length - Comprimento de Vetor + Comprimento de vetor Vector Stride - Passo de Vetor + Passo de vetor Rounding Mode - Modo de Arredondamento + Modo de arredondamento Vector Iteration Count - Contagem de Iterações de Vetor + Contagem de iterações de vetor @@ -4046,12 +4317,12 @@ Mensagem para depuração: waiting for all objects - esperando por todos os objetos + aguardando todos os objetos waiting for one of the following objects - Esperando por um dos seguintes objetos + aguardando um dos seguintes objetos @@ -4072,7 +4343,7 @@ Mensagem para depuração: running - rodando + em execução @@ -4082,7 +4353,7 @@ Mensagem para depuração: waiting for address 0x%1 - esperando pelo endereço 0x%1 + aguardando endereço 0x%1 @@ -4092,17 +4363,17 @@ Mensagem para depuração: waiting for IPC response - esperando por resposta IPC + aguardando resposta IPC waiting for objects - esperando por objetos + aguardando objetos waiting for HLE return - esperando pelo retorno HLE + aguardando retorno HLE diff --git a/dist/languages/pt_PT.ts b/dist/languages/pt_PT.ts index fd901ad2b..9a2233588 100644 --- a/dist/languages/pt_PT.ts +++ b/dist/languages/pt_PT.ts @@ -64,47 +64,52 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Comando Pica carregado - + Pica command processed Comando Pica processado - + Incoming primitive batch Batch primitivo a chegar - + Finished primitive batch Batch primitivo terminado - + Vertex shader invocation Invocação do Vertex shader - + Incoming display transfer Transferência de display a chegar - + GSP command processed Comando GSP processado - + Buffers swapped Buffers swapped PS: you can replace "swapped" for "trocados" but between programmers we Portuguese use the English word. + + + Unknown debug context event + + CalibrationConfigurationDialog @@ -167,13 +172,13 @@ PS: you can replace "swapped" for "trocados" but between pro Jogo - - + + Block Player - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? @@ -194,17 +199,17 @@ PS: you can replace "swapped" for "trocados" but between pro ClientRoomWindow - + Connected Conectado - + Disconnected Desconectado - + %1 (%2/%3 members) - connected %1 (%2/%3 membros) - conectados @@ -297,6 +302,26 @@ PS: you can replace "swapped" for "trocados" but between pro Thank you for your submission! Obrigado pela tua submissão! + + + Submitting + + + + + Communication error + + + + + An error occured while sending the Testcase + + + + + Next + + ConfigureAudio @@ -336,9 +361,9 @@ PS: you can replace "swapped" for "trocados" but between pro - - - %1 % + + %1% + Volume percentage (e.g. 50%) @@ -602,50 +627,78 @@ PS: you can replace "swapped" for "trocados" but between pro ConfigureDialog - + Citra Configuration Configuração do Citra - + + + General Geral - + + + System Sistema - + + + Input Entrada - + + + Graphics Gráficos - + + + Audio Áudio - + + + Camera Câmara - + + + Debug Debug - + + + Web Web + + + + + UI + + + + + Controls + + ConfigureGeneral @@ -665,64 +718,54 @@ PS: you can replace "swapped" for "trocados" but between pro Confirma saída enquanto a emulação está a correr - - Interface language - Línguagem de interface - - - + Updates Atualizações - + Check for updates on start Procurar atualizações no arranque - + Silently auto update after closing Atualizar automaticamente após fechar - + Emulation Emulação - + Region: Região: - + Auto-select Seleção automática - - Theme - Tema - - - - Theme: - Tema: - - - + Hotkeys Hotkeys - - <System> - <System> + + Reset All Settings + - - English - Inglês + + Citra + + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + @@ -1022,7 +1065,7 @@ PS: you can replace "swapped" for "trocados" but between pro - + Set Analog Stick Definir Stick Analógico @@ -1063,11 +1106,44 @@ PS: you can replace "swapped" for "trocados" but between pro + Clear All + + + + Restore Defaults Restaurar Padrão - + + + Clear + + + + + + [not set] + + + + + + Restore Default + + + + + Information + + + + + After pressing OK, first move your joystick horizontally, and then vertically. + + + + [press key] [pressiona a tecla] @@ -1436,17 +1512,27 @@ PS: you can replace "swapped" for "trocados" but between pro - + + yyyy-MM-ddTHH:mm:ss + + + + + Play Coins: + + + + Console ID: ID da Consola: - + Regenerate Regenerar - + System settings are available only when game is not running. As definições do sistema estão apenas disponíveis quando o jogo não está a correr. @@ -2116,22 +2202,120 @@ PS: you can replace "swapped" for "trocados" but between pro - - + + Console ID: 0x%1 ID da Consola: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? Isto irá substituir a tua atual 3DS virtual por uma nova. A tua 3DS virtual atual não será recuperável. Isto poderá ter efeitos não esperados nos jogos. Isto poderá falhar se usar um ficheiro config savegame fora de prazo. Continuar? - + Warning Aviso + + ConfigureUi + + + Form + + + + + General + + + + + Interface language: + + + + + Theme: + + + + + Game List + + + + + Icon Size: + + + + + + None + + + + + Small (24x24) + + + + + Large (48x48) + + + + + Row 1 Text: + + + + + + File Name + + + + + + Full Path + + + + + + Title Name + + + + + + Title ID + + + + + Row 2 Text: + + + + + Hide Titles without Icon + + + + + <System> + + + + + English + + + ConfigureWeb @@ -2151,7 +2335,7 @@ PS: you can replace "swapped" for "trocados" but between pro - + Verify Verificar @@ -2211,48 +2395,48 @@ PS: you can replace "swapped" for "trocados" but between pro - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Saber mais</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Registar</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">Qual é a minha token?</span></a> - - + + Telemetry ID: 0x%1 ID de Telemetria: 0x%1 - + Username and token not verified Nome de Utilizador e token não verificados - + Username and token were not verified. The changes to your username and/or token have not been saved. O Nome de Utilizador e a token não foram verificados. As mudanças ao teu nome de utilizador e/ou token não foram guardadas. - + Verifying A Verificar - + Verification failed Falha na Verificação - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. Falha na Verificação. Verifica se inseriste o teu nome de utilizador e token corretamente, e que a tua ligação à internet está a funcionar. @@ -2313,12 +2497,12 @@ PS: you can replace "swapped" for "trocados" but between pro DirectConnectWindow - + Connecting A Conectar - + Connect Conectar @@ -2326,413 +2510,445 @@ PS: you can replace "swapped" for "trocados" but between pro GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? - + Telemetry - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Velocidade de emulação atual. Valores superiores ou inferiores a 100% indicam que a emulação está a correr mais rápida ou mais lenta que uma 3DS. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Quantos frames por segundo o jogo está atualmente a mostrar. Isto varia de jogo para jogo e de cena para cena. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Tempo demorado para emular um frame de 3DS, descontando framelimiting ou v-sync. Para velocidade total de emulação, isto deveria ser, no máximo, 16.67 ms. - + Clear Recent Files - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available - + An update is available. Would you like to install it now? - + No Update Found - + No update is found. - - + + OpenGL 3.3 Unsupported + + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + + + + + Invalid ROM Format - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + ROM Corrupted - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + ROM Encrypted - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - - + + Video Core Error - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. - + Error while loading ROM! Erro a ler a ROM! - + An unknown error occured. Please see the log for more details. Ocorreu um erro desconhecido. Por favor veja o log para mais detalhes. - + Start Iniciar - + Error Opening %1 Folder Erro ao abrir a pasta %1 - - + + Folder does not exist! A pasta não existe! - + Error Opening %1 Erro ao Abrir %1 - + Select Directory Selecionar o Diretório - - 3DS Executable - Executável 3DS + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + - - - All Files (*.*) - Todos os Ficheiros (*.*) - - - + Load File Carregar Ficheiro - + Load Files Carregar Ficheiros - + 3DS Installation File (*.CIA*) Ficheiro de instalação 3DS (*.CIA) - + + All Files (*.*) + Todos os Ficheiros (*.*) + + + %1 has been installed successfully. %1 foi instalado com sucesso. - + Unable to open File Impossível abrir o Ficheiro - + Could not open %1 Impossível abrir %1 - + Installation aborted Instalação abortada - + The installation of %1 was aborted. Please see the log for more details A instalação de %1 foi abortada. Por favor veja o log para mais detalhes - + Invalid File Ficheiro Inválido - + %1 is not a valid CIA %1 não é um CIA válido - + Encrypted File Ficheiro Encriptado - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 deve ser desencriptado antes de ser usado com o Citra. Uma 3DS real é necessária. - + File not found Ficheiro não encontrado - + File "%1" not found Ficheiro "%1" não encontrado - - - + + + Continue Continuar - + Missing Citra Account Conta Citra em Falta - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. - - - + + Amiibo File (%1);; All Files (*.*) + + + + + Load Amiibo + + + + + + + Record Movie - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + + + + + Citra TAS Movie (*.ctm) - + Recording will start once you boot a game. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. - + Revision Dismatch - + Game Dismatch - - + + Invalid Movie File - + + Play Movie - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + + + + Game Not Found - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. - + Movie recording cancelled. - + Movie Saved - + The movie is successfully saved. - + Speed: %1% / %2% Velocidade: %1% / %2% - + Speed: %1% Velocidade: %1% - + Game: %1 FPS Jogo: %1 FPS - + Frame: %1 ms Frame: %1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + System Archive Not Found Arquivo de Sistema Não Encontrado - + Fatal Error Erro Fatal - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Abort - - + + Citra Citra - + Would you like to exit now? - + The game is still running. Would you like to stop emulation? - + Playback Completed - + Movie playback completed. - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2795,37 +3011,67 @@ PS: you can replace "swapped" for "trocados" but between pro GameList - + + Name + + + + + Compatibility + + + + + Region + + + + + File type + + + + + Size + + + + Open Save Data Location Abrir a Localização de Dados Guardados - + + Open Extra Data Location + + + + Open Application Location Abrir Localização de Aplicações - + Open Update Data Location Abrir Localização de Dados de Atualização - + Navigate to GameDB entry Navegar para a entrada do GameDB - + Scan Subfolders - + Remove Game Directory - + Open Directory Location @@ -2833,77 +3079,77 @@ PS: you can replace "swapped" for "trocados" but between pro GameListItemCompat - + Perfect - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. - + Bad - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot - + The game crashes when attempting to startup. - + Not Tested - + The game has not yet been tested. @@ -2911,7 +3157,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the game list @@ -2919,27 +3165,27 @@ Screen. GameListSearchField - + of - + result - + results - + Filter: - + Enter pattern to filter @@ -2947,23 +3193,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Pica Breakpoints - - + + Emulation running Emulação a correr - + Resume Retomar - + Emulation halted at breakpoint Emulação parada num breakpoint @@ -3380,42 +3626,42 @@ Screen. Atualizar Lobby - + Password Required to Join Palavra Passe Necessária para se Juntar - + Password: Palavra Passe: - + Room Name Nome da Sala - + Preferred Game Jogo Preferido - + Host Hóspede - + Players Jogadores - + Refreshing A Atualizar - + Refresh List Atualizar a Lista @@ -3438,220 +3684,245 @@ Screen. Ficheiros Recentes - + + Amiibo + + + + &Emulation &Emulação - + &View &Vista - + Debugging Debugging - + Screen Layout Layout de Ecrã - + Movie - + Multiplayer Multi Jogador - + &Help &Ajuda - + Load File... Ler Ficheiro... - + Install CIA... Instalar CIA... - + Load Symbol Map... Ler Mapa de Símbolos... - + E&xit &Sair - + &Start &Iniciar - + &Pause &Pausar - + &Stop &Parar - + FAQ FAQ - + About Citra Sobre o Citra - + Single Window Mode Modo de Janela Única - + Configure... Configurar... - + Display Dock Widget Headers Mostrar Dock Widget Headers - + Show Filter Bar Exibir Barra de Filtro - + Show Status Bar Exibir Barra de Estado - + Select Game Directory... Selecionar o Diretório de Jogos... - + Selects a folder to display in the game list Seleciona uma pasta para mostrar a lista de jogos - + Create Pica Surface Viewer Criar uma Pica Surface Viewer - + Record Movie - + Play Movie - + Stop Recording / Playback - + + Enable Frame Advancing + + + + + Advance Frame + + + + Browse Public Game Lobby Pesquisar o Lobby de Jogos Públicos - + Create Room Criar Sala - + Leave Room Sair da Sala - + Direct Connect to Room Conecção Direta à Sala - + Show Current Room Mostrar a Sala Atual - + Fullscreen Ecrã-Inteiro - + Modify Citra Install Modificar a Instalação do Citra - + Opens the maintenance tool to modify your Citra installation Abre a ferramenta de manutenção para modificar a tua instalação do Citra - + Default Padrão - + Single Screen Ecrã Único - + Large Screen Ecrã Largo - + Side by Side Lado a Lado - + Swap Screens Trocar Ecrãs - + Check for Updates Verificar a existência de Atualizações - + Report Compatibility Reportar Compatibilidade - + Restart + + + Load... + + + + + Remove + + MicroProfileDialog @@ -3677,23 +3948,23 @@ Screen. - + Connected Conectado - + Not Connected Não Conectado - + Error Erro - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: Falhou a anunciar a sala ao lobby público. De forma a hospedar uma sala publicamente, deve possuir uma conta Citra válida configurada em Emulação -> Configurar -> Web. Se não deseja publicar uma sala no lobby público, selecione "Não Listada". @@ -3812,106 +4083,106 @@ Mensagem de Debug: %1 está a jogar %2 - - + + Invalid region Região Inválida - + Japan Japão - + North America América do Norte - + Europe Europa - + Australia Austrália - + China China - + Korea Coreia - + Taiwan Taiwan - + Region free Livre de Região - + Invalid Region Região Inválida - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [não definido] - + Hat %1 %2 - + Axis %1%2 - + Button %1 - - + + [unknown] [desconhecido] - + [unused] [não utilizado] - - + + Axis %1 diff --git a/dist/languages/ru_RU.ts b/dist/languages/ru_RU.ts index 2965f3322..d7589e7d4 100644 --- a/dist/languages/ru_RU.ts +++ b/dist/languages/ru_RU.ts @@ -70,45 +70,50 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Команда Pica загружена - + Pica command processed Команда Pica выполнена - + Incoming primitive batch Поступающий пакет примитивов - + Finished primitive batch Загрузка пакета примитивов завершена - + Vertex shader invocation Вызов вершинного шейдера - + Incoming display transfer Передача входящего отображения - + GSP command processed Команда GSP обработана - + Buffers swapped Буферы заменены + + + Unknown debug context event + Неизвестное событие с контекстом отладки + CalibrationConfigurationDialog @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } Игра - - + + Block Player Заблокировать игрока - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? Когда вы заблокируете игрока, то не сможете получать от него сообщения в чате.<br><br>Вы уверены, что хотите заблокировать %1? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected Подключился - + Disconnected Отключился - + %1 (%2/%3 members) - connected %1 (%2/%3 участников) - подключен @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! Благодарим за предоставленную информацию! + + + Submitting + Отправка + + + + Communication error + Ошибка соединения + + + + An error occured while sending the Testcase + При отправке тестовой информации произошла ошибка + + + + Next + Далее + ConfigureAudio @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + %1% @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration Настройки Citra - + + + General Общие - + + + System Система - + + + Input Управление - + + + Graphics Графика - + + + Audio Аудио - + + + Camera Камера - + + + Debug Отладка - + + + Web Веб + + + + + UI + Интерфейс + + + + Controls + Управление + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } Подтверждать выход при запущенной эмуляции - - Interface language - Язык интерфейса - - - + Updates Обновления - + Check for updates on start Проверять обновления при запуске - + Silently auto update after closing Тихое автообновление после закрытия - + Emulation Эмуляция - + Region: Регион: - + Auto-select Автоматически - - Theme - Тема - - - - Theme: - Тема: - - - + Hotkeys Горячие клавиши - - <System> - <System> + + Reset All Settings + Сбросить все настройки - - English - English + + Citra + Citra + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + Вы уверены, что хотите <b>сбросить свои настройки</b> и закрыть Citra? @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick Назначить аналоговый стик @@ -1067,11 +1110,44 @@ p, li { white-space: pre-wrap; } + Clear All + Очистить всё + + + Restore Defaults Восстановить по умолчанию - + + + Clear + Очистить + + + + + [not set] + [не назначено] + + + + + Restore Default + По умолчанию + + + + Information + Информация + + + + After pressing OK, first move your joystick horizontally, and then vertically. + После нажатия OK двигайте стик по горизонтали, а затем по вертикали. + + + [press key] [нажмите кнопку] @@ -1440,17 +1516,27 @@ p, li { white-space: pre-wrap; } Время при запуске - + + yyyy-MM-ddTHH:mm:ss + dd-MM-yyyyTHH:mm:ss + + + + Play Coins: + Игровые монеты: + + + Console ID: ID консоли: - + Regenerate Пересоздать - + System settings are available only when game is not running. Настройки системы доступны только когда игра не запущена. @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } Бермудские острова - - + + Console ID: 0x%1 ID консоли: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? Это заменит вашу нынешнюю виртуальную 3DS новой. Вашу текущую виртуальную 3DS нельзя будет вернуть. Это может иметь неожиданные эффекты в играх. Генерация может не сработать, если вы используете устаревший "Config Savegame". Продолжить? - + Warning Предупреждение + + ConfigureUi + + + Form + Форма + + + + General + Общее + + + + Interface language: + Язык интерфейса: + + + + Theme: + Тема: + + + + Game List + Список игр + + + + Icon Size: + Размер иконок: + + + + + None + Отсутствуют + + + + Small (24x24) + Маленькие (24x24) + + + + Large (48x48) + Большие (48x48) + + + + Row 1 Text: + Текст на 1-й строке: + + + + + File Name + Имя файла + + + + + Full Path + Полный путь + + + + + Title Name + Название + + + + + Title ID + Идентификатор + + + + Row 2 Text: + Текст на 2-й строке: + + + + Hide Titles without Icon + Скрывать элементы без иконок + + + + <System> + <System> + + + + English + Английский + + ConfigureWeb @@ -2155,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify Подтвердить @@ -2215,48 +2399,48 @@ p, li { white-space: pre-wrap; } Показывать текущую игру в статусе Discord - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Узнать больше</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Регистрация</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Зарегистрироваться</span></a> - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">Что такое токен?</span></a> - - + + Telemetry ID: 0x%1 ID телеметрии: 0x%1 - + Username and token not verified Имя пользователя и токен не верифицированы - + Username and token were not verified. The changes to your username and/or token have not been saved. Имя пользователя и токен не были верифицированы. Изменения в имени пользователя и/или токене не были сохранены. - + Verifying Верификация - + Verification failed Верификация не удалась - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. Ошибка верификации. Убедитесь, что вы правильно ввели свое имя пользователя и токен, и что ваше интернет-соединение работает. @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting Подключение - + Connect Подключиться @@ -2330,413 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? Для помощи в улучшении Citra <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>собираются анонимные данные</a>. <br/><br/>Вы хотите поделиться с нами своими данными об использовании? - + Telemetry Телеметрия - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Текущая скорость эмуляции. Значения выше или ниже 100% указывают, что эмуляция работает быстрее или медленнее, чем 3DS. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Сколько кадров в секунду сейчас отображается в игре. Это будет варьироваться от игры к игре и от сцены к сцене. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Время, затраченное на эмуляцию кадра 3DS, не считая ограничения кадров или вертикальной синхронизации. Для полноскоростной эмуляции это значение должно быть не более 16,67 мс. - + Clear Recent Files Очистить последние файлы - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available Доступно обновление - + An update is available. Would you like to install it now? Доступно обновление. Вы хотите установить его сейчас? - + No Update Found Обновления не найдены - + No update is found. Обновления не найдены. - - + + OpenGL 3.3 Unsupported + Не поддерживается OpenGL 3.3 + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + Ваш ГП может не поддерживать OpenGL 3.3, или у вас установлена не последняя версия драйвера видеокарты. + + + + Invalid ROM Format Некорректный формат ROM - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Формат вашего ROM не поддерживается.<br/>Следуйте инструкциям, чтобы сделать новый дамп ваших <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>игровых картриджей</a> или <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>установленных продуктов</a>. - + ROM Corrupted ROM повреждён - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Ваш ROM повреждён. <br/>Следуйте инструкциям, чтобы сделать новый дамп ваших <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>игровых картриджей</a> или <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>установленных продуктов</a>. - + ROM Encrypted ROM зашифрован - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Ваш ROM зашифрован. <br/>Следуйте инструкциям, чтобы сделать новый дамп ваших <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>игровых картриджей</a> или <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>установленных продуктов</a>. - - + + Video Core Error Ошибка видеоядра - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. Произошла ошибка. Информацию вы найдёте <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>в логе</a>. Убедитесь, что у вас стоит последняя версия драйвера для вашего ГП. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. Вы используете стандартные драйверы ГП Windows. Вам необходимо установить подходящие драйверы для вашей видеокарты с сайта производителя. - + Error while loading ROM! Ошибка при загрузке ROM! - + An unknown error occured. Please see the log for more details. Произошла неизвестная ошибка. Более подробную информацию см. в Журнале. - + Start Запуск - + Error Opening %1 Folder Ошибка открытия папки %1 - - + + Folder does not exist! Папка не существует! - + Error Opening %1 Ошибка при открытии %1 - + Select Directory Выбрать каталог - - 3DS Executable - Исполняемый файл 3DS + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + Исполняемый файл 3DS (%1);;Все файлы (*.*) - - - All Files (*.*) - Все файлы (*.*) - - - + Load File Загрузить файл - + Load Files Загрузка файлов - + 3DS Installation File (*.CIA*) Установочный файл 3DS (*.CIA*) - + + All Files (*.*) + Все файлы (*.*) + + + %1 has been installed successfully. %1 был успешно установлен. - + Unable to open File Невозможно открыть файл - + Could not open %1 Не удалось открыть %1 - + Installation aborted Установка прервана - + The installation of %1 was aborted. Please see the log for more details Установка %1 была прервана. Более подробную информацию см. в Журнале. - + Invalid File Неправильный файл - + %1 is not a valid CIA %1 не является корректным CIA - + Encrypted File Зашифрованный файл - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 должен быть расшифрован перед использованием с Citra. Требуется реальная 3DS. - + File not found Файл не найден - + File "%1" not found Файл "%1" не найден - - - + + + Continue Продолжить - + Missing Citra Account Аккаунт Citra не найден - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. Для отправки тестовой информации вы должны привязать аккаунт Citra.<br/>Это можно сделать в Эмуляция &gt; Настроить... &gt; Веб. - - - + + Amiibo File (%1);; All Files (*.*) + Файл Amiibo (%1);; Все файлы (*.*) + + + + Load Amiibo + Загрузить Amiibo + + + + + + Record Movie Записать ролик - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + Чтобы сохранить согласованность с ГСЧ, рекомендуется записывать ролики с начала игры.<br>Вы уверены, что хотите записать ролики? + + + + Citra TAS Movie (*.ctm) TAS-ролик Citra (*.ctm) - + Recording will start once you boot a game. Запись начнётся после загрузки игры. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? Файл ролика, который вы пытаетесь загрузить, создан на другой ревизии Citra.<br/>С тех пор в Citra были произведены изменения, и может возникнуть рассинхрон или другое неожиданное поведение.<br/><br/>Вы уверены, что хотите загрузить данный файл ролика? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? Файл ролика, который вы пытаетесь загрузить, записан с другой игры.<br/>Воспроизведение может привести к неожиданным результатам.<br/><br/>Вы уверены, что хотите загрузить данный файл ролика? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. Файл ролика, который вы пытаетесь загрузить, некорректный.<br/>Или файл повреждён, или в модуле записи роликов Citra произошли большие изменения.<br/>Пожалуйста, выберите другой файл ролика и попробуйте снова. - + Revision Dismatch Несоответствие ревизии - + Game Dismatch Несоответствие игры - - + + Invalid Movie File Некорректный файл ролика - + + Play Movie Воспроизвести ролик - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + Чтобы сохранить согласованность с ГСЧ, рекомендуется проигрывать ролики с начала игры.<br>Вы уверены, что хотите проиграть ролики? + + + Game Not Found Игра не найдена - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. Ролик, который вы пытаетесь воспроизвести, из игры, которой нет в вашем списке игр. Если у вас есть эта игра, пожалуйста, добавьте папку с игрой в список игр и попробуйте воспроизвести ролик ещё раз. - + Movie recording cancelled. Запись ролика отменена. - + Movie Saved Ролик сохранён - + The movie is successfully saved. Ролик успешно сохранён. - + Speed: %1% / %2% Скорость: %1% / %2% - + Speed: %1% Скорость: %1% - + Game: %1 FPS Игра: %1 FPS - + Frame: %1 ms Кадр: %1 мс - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. %1 отсутствует. Пожалуйста, <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>создайте дамп ваших системных архивов</a>.<br/>Если продолжить эмуляцию, могут быть падения и ошибки. - + System Archive Not Found Системный архив не найден - + Fatal Error Критическая ошибка - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. Произошла критическая ошибка. Более подробную информацию вы <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>найдёте в логе</a>.<br/>Если продолжить эмуляцию, могут быть падения и ошибки. - + Abort Отмена - - + + Citra Citra - + Would you like to exit now? Вы хотите выйти сейчас? - + The game is still running. Would you like to stop emulation? Игра всё ещё запущена. Вы хотите остановить эмуляцию? - + Playback Completed Воспроизведение завершено. - + Movie playback completed. Воспроизведение ролика завершено. - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2799,37 +3015,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + Название + + + + Compatibility + Совместимость + + + + Region + Регион + + + + File type + Тип файла + + + + Size + Размер + + + Open Save Data Location Открыть местоположение данных сохранений - + + Open Extra Data Location + Открыть местоположение доп. данных + + + Open Application Location Открыть местоположение приложения - + Open Update Data Location Открыть местоположение обновления - + Navigate to GameDB entry Перейти к записи в GameDB - + Scan Subfolders Сканировать подпапки - + Remove Game Directory Удалить каталог с играми - + Open Directory Location Открыть местоположение каталога @@ -2837,81 +3083,81 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect Идеально - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. Игра работает безупречно, без звуковых и визуальных искажений. Все функции работают, как положено, без использования способов обхода. - + Great Хорошо - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. Игра работает с небольшими графическими или звуковыми искажениями и играбельна от начала и до конца. Может требовать способы обхода. - + Okay Сносно - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. Игра работает с серьёзными графическими или звуковыми искажениями, но играбельна от начала и до конца со способами обхода. - + Bad Плохо - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. Игра работает, но с серьёзными графическими или звуковыми искажениями. Некоторые уровни невозможно пройти из-за глюков, даже со способами обхода. - + Intro/Menu Ролики/меню - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. Невозможно играть из-за серьёзных графических или звуковых искажений. Нельзя пройти дальше начального экрана. - + Won't Boot Не запускается - + The game crashes when attempting to startup. Игра падает во время запуска. - + Not Tested Не проверялась - + The game has not yet been tested. Эта игра ещё не проверялась. @@ -2919,7 +3165,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the game list Щёлкните дважды, чтобы добавить новую папку в список игр @@ -2927,27 +3173,27 @@ Screen. GameListSearchField - + of из - + result результат - + results результатов - + Filter: Фильтр: - + Enter pattern to filter Введите шаблон для фильтрации @@ -2955,23 +3201,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Точки прерывания Pica - - + + Emulation running Эмуляция запущена - + Resume Продолжить - + Emulation halted at breakpoint Эмуляция остановлена ​​в точке прерывания @@ -3388,42 +3634,42 @@ Screen. Обновить лобби - + Password Required to Join Для входа требуется пароль - + Password: Пароль: - + Room Name Название комнаты - + Preferred Game Желаемая игра - + Host Хост - + Players Игроки - + Refreshing Обновление - + Refresh List Обновить список @@ -3446,220 +3692,245 @@ Screen. Последние файлы - + + Amiibo + Amiibo + + + &Emulation &Эмуляция - + &View &Вид - + Debugging Отладка - + Screen Layout Компоновка экрана - + Movie Ролик - + Multiplayer Мультиплеер - + &Help &Помощь - + Load File... Загрузить файл... - + Install CIA... Установить CIA... - + Load Symbol Map... Загрузить карту символов... - + E&xit В&ыход - + &Start &Старт - + &Pause &Пауза - + &Stop &Стоп - + FAQ ЧаВо - + About Citra О Citra - + Single Window Mode Режим одиночного окна - + Configure... Настроить... - + Display Dock Widget Headers Отображать заголовки виджетов дока - + Show Filter Bar Показать панель фильтров - + Show Status Bar Показать строку состояния - + Select Game Directory... Выбрать каталог с играми... - + Selects a folder to display in the game list Выбор папки для отображения в списке игр - + Create Pica Surface Viewer Создать просмотрщик поверхностей Pica - + Record Movie Записать ролик - + Play Movie Воспроизвести ролик - + Stop Recording / Playback Остановить запись/воспроизведение - + + Enable Frame Advancing + Включить перемотку кадров + + + + Advance Frame + Следующий кадр + + + Browse Public Game Lobby Обзор публичных игровых комнат - + Create Room Создать комнату - + Leave Room Покинуть комнату - + Direct Connect to Room Прямое подключение к комнате - + Show Current Room Показать текущую комнату - + Fullscreen Полный экран - + Modify Citra Install Изменить установку Citra - + Opens the maintenance tool to modify your Citra installation Открывает инструмент обслуживания, чтобы изменить установку Citra - + Default По умолчанию - + Single Screen Один экран - + Large Screen Большой экран - + Side by Side Бок о бок - + Swap Screens Поменять местами - + Check for Updates Проверить наличие обновлений - + Report Compatibility Сообщить о совместимости - + Restart Перезапустить + + + Load... + Загрузить... + + + + Remove + Удалить + MicroProfileDialog @@ -3685,23 +3956,23 @@ Screen. - + Connected Подключен - + Not Connected Не подключен - + Error Ошибка - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: Не удалось анонсировать комнату в публичном лобби. Чтобы создать публичную комнату, у вас должен быть указан действующий аккаунт Citra в Эмуляция -> Настроить -> Веб. Если вы не хотите публиковать комнату в публичном лобби, выберите Частная. @@ -3820,106 +4091,106 @@ Debug Message: %1 играет в %2 - - + + Invalid region Некорректный регион - + Japan Япония - + North America Северная Америка - + Europe Европа - + Australia Австралия - + China Китай - + Korea Корея - + Taiwan Тайвань - + Region free Без региона - + Invalid Region Некорректный регион - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [не задано] - + Hat %1 %2 Миниджойстик %1 %2 - + Axis %1%2 Ось %1%2 - + Button %1 Кнопка %1 - - + + [unknown] [Неизвестно] - + [unused] [не использовано] - - + + Axis %1 Ось %1 diff --git a/dist/languages/tr_TR.ts b/dist/languages/tr_TR.ts index 0f8986085..388246950 100644 --- a/dist/languages/tr_TR.ts +++ b/dist/languages/tr_TR.ts @@ -70,45 +70,50 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Pica command loaded - + Pica command processed Pica command processed - + Incoming primitive batch Incoming primitive batch - + Finished primitive batch Finished primitive batch - + Vertex shader invocation Vertex shader invocation - + Incoming display transfer Incoming display transfer - + GSP command processed GSP command processed - + Buffers swapped Buffers swapped + + + Unknown debug context event + + CalibrationConfigurationDialog @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } Oyun - - + + Block Player Kullanıcıyı Engelle - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? Bir kullanıcıyı engellediğinizde ondan sohbet mesajları alamazsınız.<br><br>%1 kullanıcısını engellemek istediğinize emin misiniz? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected Bağlanıldı - + Disconnected Bağlantı Kesildi - + %1 (%2/%3 members) - connected %1 (%2/%3 kullanıcı) - bağlandı @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! Gönderiniz için teşekkürler! + + + Submitting + + + + + Communication error + + + + + An error occured while sending the Testcase + + + + + Next + + ConfigureAudio @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration Citra Yapılandırması - + + + General Genel - + + + System Sistem - + + + Input Girdi - + + + Graphics Grafikler - + + + Audio Ses - + + + Camera Kamera - + + + Debug Hata Ayıklama - + + + Web + + + + + UI + + + + + Controls + + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } Emülasyon devam ederken çıkışı onaylayın - - Interface language - Arayüz dili - - - + Updates Güncellemeler - + Check for updates on start Açılışta güncellemeleri kontrol et - + Silently auto update after closing Kapandıktan sonra arkaplanda otomatik güncelle - + Emulation Emülasyon - + Region: Bölge: - + Auto-select Otomatik seç - - Theme - Tema - - - - Theme: - Tema: - - - + Hotkeys Kısayollar - - <System> - <System> + + Reset All Settings + - - English - İngilizce + + Citra + + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick Analog Çubuğunu Ayarla @@ -1067,11 +1110,44 @@ p, li { white-space: pre-wrap; } + Clear All + + + + Restore Defaults Varsayılanlara Dön - + + + Clear + + + + + + [not set] + + + + + + Restore Default + + + + + Information + + + + + After pressing OK, first move your joystick horizontally, and then vertically. + + + + [press key] [tuşa bas] @@ -1229,7 +1305,7 @@ p, li { white-space: pre-wrap; } Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. - Sunucudan geçerli veri alınamıyor.<br>Lütfen sunucunun düzgün kurulduğundan ve adresin ve portun doğru girildiğinden emin olun. + Sunucudan geçerli veri alınamıyor.<br>Lütfen sunucunun düzgün kurulduğundan, adres ve portun doğru girildiğinden emin olun. @@ -1440,17 +1516,27 @@ p, li { white-space: pre-wrap; } - + + yyyy-MM-ddTHH:mm:ss + + + + + Play Coins: + + + + Console ID: Konsol ID: - + Regenerate Yeniden Oluştur - + System settings are available only when game is not running. Sistem ayarlarına sadece oyun çalışmıyorken erişilebilir. @@ -1507,7 +1593,7 @@ p, li { white-space: pre-wrap; } British Virgin Islands - İngiliz Virgin Adaları + İngiliz Virjin Adaları @@ -1677,7 +1763,7 @@ p, li { white-space: pre-wrap; } US Virgin Islands - Amerika Birleşik Devletleri Virgin Adaları + Amerika Birleşik Devletleri Virjin Adaları @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } Bermuda - - + + Console ID: 0x%1 Konsol ID: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? Bu mevcut sanal 3DS'nizi yenisiyle değiştirecektir. Mevcut sanal 3DS'niz geri alınamayacaktır. Bu oyunlarda beklenmedik etkilere sebep olabilir. Eğer eski yapılandırmalı oyun kayıtı kullanırsanız bu başarısız olabilir. Devam edilsin mi? - + Warning Uyarı + + ConfigureUi + + + Form + + + + + General + + + + + Interface language: + + + + + Theme: + + + + + Game List + + + + + Icon Size: + + + + + + None + + + + + Small (24x24) + + + + + Large (48x48) + + + + + Row 1 Text: + + + + + + File Name + + + + + + Full Path + + + + + + Title Name + + + + + + Title ID + + + + + Row 2 Text: + + + + + Hide Titles without Icon + + + + + <System> + + + + + English + + + ConfigureWeb @@ -2155,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify Doğrula @@ -2215,48 +2399,48 @@ p, li { white-space: pre-wrap; } - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Daha fazla bilgi edinin</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Kaydol </span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">Tokenim nedir?</span></a> - - + + Telemetry ID: 0x%1 Telemetri ID: 0x%1 - + Username and token not verified Kullanıcı Adı ve Token doğrulanmadı - + Username and token were not verified. The changes to your username and/or token have not been saved. Kullanıcı adı ve token doğrulanamadı. Kullanıcı adınıza ve/veya tokeninize yapılan değişiklikler kaydedilmedi. - + Verifying Doğrulanıyor - + Verification failed Doğrulama başarısız oldu - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. Doğrulama başarısız oldu. Kullanıcı adınızı ve tokeninizi doğru girdiğinizden ve internet bağlantınızın çalıştığından emin olun. @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting Bağlanılıyor - + Connect Bağlan @@ -2330,413 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? - <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Citrayı geliştirmeye yardımcı olmak için</a>Anonim veri toplandı. <br/><br/>Kullanım verinizi bizimle paylaşır mısınız? + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Citrayı geliştirmeye yardımcı olmak için</a> anonim veri toplandı. <br/><br/>Kullanım verinizi bizimle paylaşmak ister misiniz? - + Telemetry - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Geçerli emülasyon hızı. 100%'den az veya çok olan değerler emülasyonun bir 3DS'den daha yavaş veya daha hızlı çalıştığını gösterir. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Oyunun şu anda saniye başına kaç kare gösterdiği. Bu oyundan oyuna ve sahneden sahneye farklılık gösterebilir. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Bir 3DS karesini emüle etmekte geçen zaman, karelimitleme ve v-sync hariç. Tam hız emülasyon için bu en çok 16,67 ms. olmalı. - + Clear Recent Files Son Dosyaları Temizle - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available Güncelleme Mevcut - + An update is available. Would you like to install it now? Bir güncelleme mevcut. Şimdi yüklemek ister misiniz? - + No Update Found Güncelleme Bulunamadı - + No update is found. Güncelleme bulunamadı. - - + + OpenGL 3.3 Unsupported + + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + + + + + Invalid ROM Format Geçersiz Dosya Biçimi - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Oyun dosyanızın biçimi desteklenmiyor. <br/>Lütfen <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>oyun kartuşlarınızı</a> veya <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>yüklenmiş oyunlarınızı</a> yeniden dump etmek için rehberleri takip ediniz. - + ROM Corrupted Dosya Bozulmuş - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Oyun dosyanız bozuk. <br/>Lütfen <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>oyun kartuşlarınızı</a> veya <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>yüklenmiş oyunlarınızı</a> yeniden dump etmek için rehberleri takip ediniz. - + ROM Encrypted Dosya Şifreli - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Oyun dosyanız şifreli.<br/>Lütfen <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>oyun kartuşlarınızı</a> veya <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>yüklenmiş oyunlarınızı</a> yeniden dump etmek için rehberleri takip ediniz. - - + + Video Core Error - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. Windowsun varsayılan GPU sürücülerini kullanıyorsunuz. Üreticinin sitesinden ekran kartınız için geçerli sürücüleri yüklemelisiniz. - + Error while loading ROM! ROM yüklenirken hata oluştu! - + An unknown error occured. Please see the log for more details. Bilinmeyen bir hata meydana geldi. Lütfen daha fazla detay için kütüğe bakınız. - + Start Başlat - + Error Opening %1 Folder %1 Klasörü Açılırken Hata Oluştu - - + + Folder does not exist! Klasör mevcut değil! - + Error Opening %1 %1 Açılırken Hata Oluştu - + Select Directory Dizin Seç - - 3DS Executable - 3DS Çalıştırılabilir Dosyası + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + - - - All Files (*.*) - Tüm Dosyalar (*.*) - - - + Load File Dosya Yükle - + Load Files Dosyaları Yükle - + 3DS Installation File (*.CIA*) 3DS Kurulum Dosyası (*.CIA*) - + + All Files (*.*) + Tüm Dosyalar (*.*) + + + %1 has been installed successfully. %1 başarıyla yüklendi. - + Unable to open File Dosya açılamıyor - + Could not open %1 %1 açılamıyor - + Installation aborted Yükleme iptal edildi - + The installation of %1 was aborted. Please see the log for more details %1'in yüklemesi iptal edildi. Daha fazla detay için lütfen kütüğe bakınız. - + Invalid File Geçersiz Dosya - + %1 is not a valid CIA %1 geçerli bir CIA dosyası değil - + Encrypted File Şifrelenmiş Dosya - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 Citra ile kullanılmadan önce deşifre edilmelidir. Gerçek bir 3DS gereklidir. - + File not found Dosya bulunamadı - + File "%1" not found "%1" Dosyası bulunamadı - - - + + + Continue Devam - + Missing Citra Account Citra Hesabı Eksik - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. - - - + + Amiibo File (%1);; All Files (*.*) + + + + + Load Amiibo + + + + + + + Record Movie Klip Kaydet - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + + + + + Citra TAS Movie (*.ctm) Citra TAS Movie (*.ctm) - + Recording will start once you boot a game. Kayıt bir oyun başlattığınız zaman başlayacak. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? İzlemeye çalıştığınız klip dosyası başka bir oyun ile kaydetilmiş.<br/>Oynatma beklendiği gibi çalışmayabilir ve beklenmedik sonuçlar doğurabilir.<br/><br/>Klip dosyasını hala yüklemek istediğinize emin misiniz? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. İzlemeye çalıştığınız klip dosyası geçersiz.<br/>Dosya bozulmuş veya Citra Klip modülünde büyük değişiklikler yapılmış olabilir.<br/>Lütfen varklı bir klip dosyası seçin ve tekrardan deneyin. - + Revision Dismatch - + Game Dismatch - - + + Invalid Movie File - + + Play Movie - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + + + + Game Not Found Oyun Bulunamadı - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. Oynatmaya çalıştığınız klip oyun listenizde olmayan bir oyundan, eğer oyuna sahipseniz lütfen oyun klasörünü listeye ekleyin ve klipi tekrardan oynatmaya çalışın. - + Movie recording cancelled. Klip kaydı iptal edildi. - + Movie Saved Klip Kaydedildi - + The movie is successfully saved. Klip başarıyla kayıt edildi. - + Speed: %1% / %2% Hız: %1% / %2% - + Speed: %1% Hız: %1% - + Game: %1 FPS Oyun: %1 FPS - + Frame: %1 ms Kare: %1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. %1 eksik. Lütfen <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>sistem arşivinizi dump edin</a>.<br/>Emülasyona devam etmek çökmelerle ve hatalarla sonuçlanabilir. - + System Archive Not Found Sistem Arşivi Bulunamadı - + Fatal Error Önemli Hata - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Abort - - + + Citra Citra - + Would you like to exit now? - + The game is still running. Would you like to stop emulation? Oyun hala çalışıyor. Emülasyonu durdurmak istiyor musunuz? - + Playback Completed Oynatma Tamamlandı - + Movie playback completed. Klip oynatması tamamlandı. - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2799,37 +3015,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + + + + + Compatibility + + + + + Region + + + + + File type + + + + + Size + + + + Open Save Data Location Kayıt Dosyası Konumunu Aç - + + Open Extra Data Location + + + + Open Application Location Uygulama Konumunu Aç - + Open Update Data Location Güncelleme Dosyası Konumunu Aç - + Navigate to GameDB entry Oyun Veritabanı Girdisine Git - + Scan Subfolders Alt Dizinleri Tara - + Remove Game Directory Oyun Dizinini Kaldır - + Open Directory Location Dizinin Bulunduğu Yeri Aç @@ -2837,12 +3083,12 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect Mükemmel - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. Oyun grafik veya ses hataları olmadan sorunsuz çalışıyor, tüm test edilmiş özellikler @@ -2850,12 +3096,12 @@ geçici çözümler gerektirmeden beklendiği gibi çalışıyor. - + Great - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. Oyun küçük grafik veya ses hatalarıyla çalışıyor ve baştan sona kadar oynanabilir. Bazı @@ -2863,12 +3109,12 @@ geçici çözümler gerektirebilir. - + Okay - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. Oyun büyük grafik veya ses hatalarıyla çalışıyor fakat geçici çözümler ile baştan sona @@ -2876,12 +3122,12 @@ kadar oynanabilir. - + Bad - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. Oyun çalışıyor fakat büyük grafik veya ses hatalarına sahip. Geçici çözümlerle bile @@ -2889,33 +3135,33 @@ hatalardan dolayı bazı alanlar geçilemiyor. - + Intro/Menu - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot - + The game crashes when attempting to startup. - + Not Tested - + The game has not yet been tested. @@ -2923,7 +3169,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the game list Oyun listesine yeni bir klasör eklemek için çift-tıklayın @@ -2931,27 +3177,27 @@ Screen. GameListSearchField - + of 'nun - + result sonuç - + results sonuçlar - + Filter: Filtre: - + Enter pattern to filter Filtrelenecek düzeni girin @@ -2959,23 +3205,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Pica Breakpoints - - + + Emulation running Emulation running - + Resume Resume - + Emulation halted at breakpoint Emulation halted at breakpoint @@ -3392,42 +3638,42 @@ Screen. Lobiyi Yenile - + Password Required to Join Katılmak İçin Şifre Gerekiyor - + Password: Şifre: - + Room Name Oda İsmi - + Preferred Game Öncelikli Oyun - + Host Sunucu - + Players Oyuncular - + Refreshing Yenileniyor - + Refresh List Listeyi Yenile @@ -3450,220 +3696,245 @@ Screen. Son Kullanılan Dosyalar - + + Amiibo + + + + &Emulation &Emülasyon - + &View &Görünüm - + Debugging Hata Ayıklama - + Screen Layout Ekran Düzeni - + Movie - + Multiplayer Çok Oyunculu - + &Help &Yardım - + Load File... Dosya Yükle... - + Install CIA... CIA Yükle... - + Load Symbol Map... Load Symbol Map... - + E&xit &Çıkış - + &Start B&aşlat - + &Pause &Duraklat - + &Stop Du&rdur - + FAQ S.S.S - + About Citra Citra Hakkında - + Single Window Mode Tek Pencere Modu - + Configure... Yapılandır... - + Display Dock Widget Headers Dock Widget'ı Başlıklarını Göster - + Show Filter Bar Filtre Çubuğunu Göster - + Show Status Bar Durum Çubuğunu Göster - + Select Game Directory... Oyun Dizinini Seç... - + Selects a folder to display in the game list Oyun listesinde görüntülenecek bir klasör seçer - + Create Pica Surface Viewer Create Pica Surface Viewer - + Record Movie - + Play Movie - + Stop Recording / Playback - + + Enable Frame Advancing + + + + + Advance Frame + + + + Browse Public Game Lobby Herkese Açık Oyun Lobisi Ara - + Create Room Oda Oluştur - + Leave Room Odadan Ayrıl - + Direct Connect to Room Odaya Doğrudan Bağlan - + Show Current Room Mevcut Odayı Göster - + Fullscreen Tam ekran - + Modify Citra Install Citra Kurulumunu Değiştir - + Opens the maintenance tool to modify your Citra installation Citra kurulumunu değiştirmek için bakım aracını açar - + Default Varsayılan - + Single Screen Tek Ekran - + Large Screen Büyük Ekran - + Side by Side Yan Yana - + Swap Screens Ekranları değiştir - + Check for Updates Güncellemeleri Kontrol Et - + Report Compatibility Uyumluluk Bildir - + Restart Yeniden Başlat + + + Load... + + + + + Remove + + MicroProfileDialog @@ -3689,23 +3960,23 @@ Screen. - + Connected Bağlanıldı - + Not Connected Bağlı Değil - + Error Hata - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: Oda herkese açık lobiye yayınlanamadı. Herkese açık bir oda açmak için, Emülasyon -> Yapılandırma -> Ağ içinde geçerli bir Citra hesabı yapılandırılmış olmalı. Eğer herkese açık lobide oda yayınlamak istemiyorsanız, yerine Liste Dışı'nı seçin. @@ -3824,106 +4095,106 @@ Hata Ayıklama Mesajı: %1 %2 oynuyor - - + + Invalid region Geçersiz Bölge - + Japan Japonya - + North America Kuzey Amerika - + Europe Avrupa - + Australia Avustralya - + China Çin - + Korea Kore - + Taiwan Tayvan - + Region free Bölge kilitsiz - + Invalid Region Geçersiz Bölge - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [ayarlanmadı] - + Hat %1 %2 - + Axis %1%2 - + Button %1 - - + + [unknown] [bilinmiyor] - + [unused] [kullanılmıyor] - - + + Axis %1 diff --git a/dist/languages/vi_VN.ts b/dist/languages/vi_VN.ts index 07195863d..552030ffc 100644 --- a/dist/languages/vi_VN.ts +++ b/dist/languages/vi_VN.ts @@ -70,72 +70,77 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded Đã khởi động lệnh Pica - + Pica command processed Đã xử lý lệnh Pica - + Incoming primitive batch Đã nhận được dữ liệu nguyên thủy mới - + Finished primitive batch Dữ liệu nguyên thủy đã được xử lý - + Vertex shader invocation Gọi lệnh Vertex Shader - + Incoming display transfer Đang chuyển giao hiển thị - + GSP command processed Đã xử lý lệnh GSP - + Buffers swapped Chuyển dữ liệu tạm thời + + + Unknown debug context event + + CalibrationConfigurationDialog Communicating with the server... - + Đang kết nối với máy chủ... Cancel - + Bỏ qua Touch the top left corner <br>of your touchpad. - + Chạm vào góc trên trái <br>bảng cảm biến. Now touch the bottom right corner <br>of your touchpad. - + Giờ chạm vào góc dưới phải <br>bảng cảm biến. Configuration completed! - + Thiết lập hoàn tất! @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } Trò chơi - - + + Block Player Chặn người chơi - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? Khi bạn chặn người chơi khác, bạn sẽ không thể nhận được các tin nhắn từ họ.<br><br>Bạn có chắc muốn chặn người chơi %1? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected Đã kết nối - + Disconnected Đã ngắt kết ngối - + %1 (%2/%3 members) - connected %1 (%2/%3 thành viên) - đã kết nối @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! Rất cảm ơn bạn đã phản hồi! + + + Submitting + + + + + Communication error + + + + + An error occured while sending the Testcase + + + + + Next + + ConfigureAudio @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration Thiết lập Citra - + + + General Chung - + + + System H. thống - + + + Input Phím - + + + Graphics Đồ họa - + + + Audio Âm thanh - + + + Camera Máy ảnh - + + + Debug Gỡ lỗi - + + + Web Trang web + + + + + UI + + + + + Controls + + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } Xác nhận thoát khi đang chạy giả lập - - Interface language - Ngôn ngữ giao diện - - - + Updates Cập nhật - + Check for updates on start Kiểm tra cập nhật khi khởi chạy - + Silently auto update after closing Tự động cập nhật ngầm sau khi tắt - + Emulation Giả lập - + Region: Vùng: - + Auto-select Tự động chọn - - Theme - Giao diện - - - - Theme: - Giao diện: - - - + Hotkeys Phím tắt - - <System> - <System> + + Reset All Settings + - - English - Tiếng Anh + + Citra + + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick Thiết lập Con xoay @@ -1063,15 +1106,48 @@ p, li { white-space: pre-wrap; } Motion / Touch... - + Chuyển động / Chạm... + Clear All + + + + Restore Defaults Khôi phục mặc định - + + + Clear + + + + + + [not set] + + + + + + Restore Default + + + + + Information + + + + + After pressing OK, first move your joystick horizontally, and then vertically. + + + + [press key] [nhấn phím] @@ -1081,12 +1157,12 @@ p, li { white-space: pre-wrap; } Configure Motion / Touch - + Thiết lập chuyển động / chạm Motion - + Chuyển Động @@ -1096,12 +1172,12 @@ p, li { white-space: pre-wrap; } Sensitivity: - + Độ nhạy: Touch - + Chạm @@ -1111,7 +1187,7 @@ p, li { white-space: pre-wrap; } Calibration: - + Hiệu chuẩn: @@ -1122,27 +1198,27 @@ p, li { white-space: pre-wrap; } Configure - + Thiết lập CemuhookUDP Config - + Thiết lập Cemuhook UDP You may use any Cemuhook compatible UDP input source to provide motion and touch input. - + Bạn có thể dùng bất cứ bản Cemuhook nào tương thích với đầu vào UDP để giả lập chuyển động và hành vi chạm. Server: - + Máy chủ: Port: - + Cổng: @@ -1172,74 +1248,74 @@ p, li { white-space: pre-wrap; } Learn More - + Tìm hiểu thêm Test - + Kiểm tra Mouse (Right Click) - + Chuột (Nhấp phải) CemuhookUDP - + CemuhookUDP Emulator Window - + Cửa sổ giả lập <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - + <a href='https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Tìm hiểu thêm</span></a> Testing - + Đang kiểm tra Configuring - + Thiết lập Test Successful - + Kiểm tra thành công Successfully received data from the server. - + Đã nhận dữ liệu từ máy chủ thành công. Test Failed - + Kiểm thử thất bại Could not receive valid data from the server.<br>Please verify that the server is set up correctly and the address and port are correct. - + Không thể nhận dữ liệu nào từ máy chủ.<br>Vui lòng kiểm tra máy chủ đã được thiết đặt đúng, kiểm tra địa chỉ và cổng kết nối là chính xác. Citra - + Citra UDP Test or calibration configuration is in progress.<br>Please wait for them to finish. - + Kiểm tra UDP hoặc quá trình đang hiệu chuẩn.<br>Vui lòng đợi quá trình này hoàn tất. @@ -1422,35 +1498,45 @@ p, li { white-space: pre-wrap; } Clock - + Đồng hồ System Clock - + Đồng hồ hệ thống Fixed Time - + Giờ cố định Startup time + Giờ bắt đầu + + + + yyyy-MM-ddTHH:mm:ss - + + Play Coins: + + + + Console ID: ID Máy: - + Regenerate Tạo mới - + System settings are available only when game is not running. Chỉ có thể thay đổi thiết lập hệ thống khi đang không chơi game. @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } Bermuda - - + + Console ID: 0x%1 Tên Máy: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? Điều này có thể khiến máy ảo 3DS của bạn thay thế bởi một chiếc máy mới. Điều này không thể hoàn tác. Một số game có thể bị ảnh hưởng bởi điều này. Và có thể xảy ra lỗi nếu bạn đang dùng thiết lập lưu game cũ. Tiếp tục? - + Warning Cảnh báo + + ConfigureUi + + + Form + + + + + General + + + + + Interface language: + + + + + Theme: + + + + + Game List + + + + + Icon Size: + + + + + + None + + + + + Small (24x24) + + + + + Large (48x48) + + + + + Row 1 Text: + + + + + + File Name + + + + + + Full Path + + + + + + Title Name + + + + + + Title ID + + + + + Row 2 Text: + + + + + Hide Titles without Icon + + + + + <System> + + + + + English + + + ConfigureWeb @@ -2155,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify Xác thực @@ -2212,51 +2396,51 @@ p, li { white-space: pre-wrap; } Show Current Game in your Discord Status - + Hiển thị game đang chơi trên trạng thái Discord - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Tìm hiểu thêm</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Đăng ký</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">Token là gì?</span></a> - - + + Telemetry ID: 0x%1 Mã theo dõi: 0x%1 - + Username and token not verified Tài khoản và token chưa được xác thực - + Username and token were not verified. The changes to your username and/or token have not been saved. Tài khoản và token này chưa được xác thực. Các thay đổi về người dùng này sẽ không được lưu lại. - + Verifying Đang xác thực - + Verification failed Xác thực thất bại - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. Xác thực thất bại. Vui lòng kiểm tra tài khoản và token bạn đã nhập và kết nối đến Internet của máy. @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting Đang kết nối - + Connect Kết nối @@ -2330,413 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Dữ liệu ẩn danh được thu thập</a> để giúp cải thiện Citra. <br/><br/>Bạn có muốn chia sẻ dữ liệu của bạn với chúng tôi? - + Telemetry Theo dõi từ xa - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. Tốc độ giả lập hiện tại. Giá trị cao hoặc thấp hơn 100% thể hiện giả lập đang chạy nhanh hay chậm hơn một chiếc máy 3DS thực sự. - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. Tốc độ khung hình thực trong game. Nó sẽ thay đổi tùy game và tùy màn chơi. - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. Thời gian để giả lập một khung hình của máy 3DS, không gồm giới hạn khung hay v-sync Một giả lập tốt nhất sẽ tiệm cận 16.67 ms. - + Clear Recent Files Xóa danh sách tệp gần đây - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available Cập nhật - + An update is available. Would you like to install it now? Một bản cập nhật mới đã sẵn sàng. Bạn có muốn cài đặt ngay bây giờ không? - + No Update Found Chưa tìm thấy bản cập nhật mới - + No update is found. Chưa tìm thấy bản cập nhật mới - - + + OpenGL 3.3 Unsupported + + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + + + + + Invalid ROM Format Định dạng ROM không hợp lệ - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. Định dạng ROM của bạn không được hỗ trợ.<br/>Vui lòng làm theo hướng dẫn để trích xuất dữ liệu từ<a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>thẻ game</a> hoặc <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>game eShop</a>. - + ROM Corrupted ROM hỏng - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. ROM của bạn đã bị hỏng. <br/>Vui lòng thực hiện theo hướng dẫn đển trích xuát dữ liệu từ <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>thẻ game</a> hoặc <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>game eShop</a>. - + ROM Encrypted ROM được mã hóa - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. ROM của bạn được mã hóa. <br/>Vui lòng thực hiện theo hướng dẫn để trích xuất dữ liệu từ <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>thẻ game</a> hoặc <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>game eShop</a>. - - + + Video Core Error Lỗi Video Core - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. Đã có lỗi xảy ra. Vui lòng <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>xem tệp log</a> để biết thêm chi tiết. Hãy đảm bảo rằng bạn đã cài driver mới nhất cho card đồ họa của bạn - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. - + Bạn đang dùng driver mặc định của Windows cho GPU. Bạn cần phải cài đặt bản driver phù hợp cho card đồ họa của mình từ trang chủ của nhà sản xuất. - + Error while loading ROM! Lỗi xuất hiện khi tải ROM! - + An unknown error occured. Please see the log for more details. Một lỗi không rõ đã xảy ra. Vui lòng xem nhật ký để biết thêm chi tiết. - + Start Bắt đầu - + Error Opening %1 Folder Lỗi khi mở thư mục %1 - - + + Folder does not exist! Thư mục này không tồn tại! - + Error Opening %1 Lỗi khi mở %1 - + Select Directory Chọn thư mục - - 3DS Executable - Tệp khởi chạy 3DS + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + - - - All Files (*.*) - Tất cả tệp tin (*.*) - - - + Load File Mở tệp tin - + Load Files Mở các tệp tin - + 3DS Installation File (*.CIA*) Tệp cài đặt 3DS (*.CIA*) - + + All Files (*.*) + Tất cả tệp tin (*.*) + + + %1 has been installed successfully. %1 đã được cài đặt thành công. - + Unable to open File Không thể mở tệp tin - + Could not open %1 Không thể mở %1 - + Installation aborted Việc cài đặt đã bị hoãn - + The installation of %1 was aborted. Please see the log for more details Việc cài đặt %1 đã bị hoãn. Vui lòng xem bản ghi nhật ký để biết thêm chi tiết. - + Invalid File Tệp tin không hợp lệ - + %1 is not a valid CIA %1 không phải là một tệp CIA hợp lệ - + Encrypted File Tệp đã bị mã hóa - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 cần được giải nén trước khi dùng với Citra. Điều này cần đến một máy 3DS thực sự. - + File not found Không tìm thấy tệp - + File "%1" not found Không tìm thấy tệp tin "%1" - - - + + + Continue Tiếp tục - + Missing Citra Account Mất tài khoản Citra - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. Bạn phải kết nối với tài khoản Citra của bạn để gửi mẫu thử.<br/>Vào Emulation &gt; Configure... &gt; Web để kết nối. - - - - Record Movie + + Amiibo File (%1);; All Files (*.*) - - + + Load Amiibo + + + + + + + + Record Movie + Quay phim + + + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + + + + + Citra TAS Movie (*.ctm) - - - Recording will start once you boot a game. - - - - - The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? - - - - - The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? - - - - - - The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. - - - - - Revision Dismatch - - - - - Game Dismatch - - - - - - Invalid Movie File - - - - - Play Movie - - - - - Game Not Found - - - - - The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. - - - - - Movie recording cancelled. - - - - - Movie Saved - - - The movie is successfully saved. - + Recording will start once you boot a game. + Ghi hình sẽ bắt đầu ngay khi bạn mở một game. + + + + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? + Tệp tin phim bạn đang cố mở đã được tạo ở một phiên bản không tương thích khác của Citra.<br/>Citra có vài sự thay đổi lúc này, và bộ phát có thể bị bất đồng bộ hoặc không hoạt động chính xác.<br/><br/>Bạn có chắc tiếp tục mở tệp tin phim? + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? + Tệp phim bạn đang cố gắng mở đã được ghi từ một trò chơi khác.<br/>Kết quả phát lại sẽ có thể không chính xác, hoặc gây ra lỗi.<br/><br/>Bạn có chắc muốn tiếp tục mở tệp phim này? + + + + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. + Tệp phim bạn đang cố mở không hợp lệ.<br/>Có thể tệp tin đã bị hỏng, hoặc phiên bản này đã thay đổi lớn về mã hóa tệp phim.<br/>Vui lòng chọn một tệp phim khác xem sao. + + + + Revision Dismatch + Phiên bản không phù hợp + + + + Game Dismatch + Trò chơi không phù hợp + + + + + Invalid Movie File + Tệp tin không hợp lệ + + + + + Play Movie + Phát tệp phim + + + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + + + + + Game Not Found + Không tìm thấy trò chơi + + + + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. + Phim bạn đang định phát dường như từ một trò chơi không nằm trong danh sách game hiện có. Nếu bạn đã mua game này, vui lòng thêm vào danh sách game và thử lại. + + + + Movie recording cancelled. + Ghi hình đã bị hủy. + + + + Movie Saved + Đã lưu phim. + + + + The movie is successfully saved. + Phim đã được lưu lại thành công. + + + Speed: %1% / %2% Tốc độ: %1% / %2% - + Speed: %1% Tốc độ: %1% - + Game: %1 FPS Game: %1 FPS - + Frame: %1 ms Khung: %1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. %1 bị thiếu. Vui lòng <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>trích xuất các tệp hệ thống từ 3DS</a>.<br/>Nếu chạy tiếp giả lập có thể tự thoát hoặc lỗi. - + System Archive Not Found Không thể tìm thấy mục Lưu trữ hệ thống - + Fatal Error Lỗi nghiêm trọng - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. Lỗi nghiêm trọng đã xảy ra. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Kiểm tra tệp log</a> để biết thêm chi tiết<br/>Nếu tiếp tục chạy giả lập có thể tự thoát hoặc phát sinh lỗi. - + Abort Hủy bỏ - - + + Citra Citra - + Would you like to exit now? Bạn có muốn thoát ngay bây giờ không? - + The game is still running. Would you like to stop emulation? Trò chơi vẫn đang chạy. Bạn có muốn dừng không? - + Playback Completed - + Phát lại hoàn tất - + Movie playback completed. - + Phát lại phim hoàn tất. - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2799,37 +3015,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + + + + + Compatibility + + + + + Region + + + + + File type + + + + + Size + + + + Open Save Data Location Mở thư mục lưu game - + + Open Extra Data Location + + + + Open Application Location Mở thư mục ứng dụng - + Open Update Data Location Mở thư mục dữ liệu cập nhật - + Navigate to GameDB entry Điều hướng đến GameDB - + Scan Subfolders Quét thư mục con - + Remove Game Directory Loại bỏ thư mục chứa game - + Open Directory Location Mở thư mục @@ -2837,77 +3083,77 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect - + Hoàn mỹ - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. - + Bad - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot - + The game crashes when attempting to startup. - + Not Tested - + The game has not yet been tested. @@ -2915,7 +3161,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the game list Nhấp đúp chuột để thêm thư mục vào danh sách game @@ -2923,27 +3169,27 @@ Screen. GameListSearchField - + of của - + result kết quả - + results các kết quả - + Filter: Bộ lọc: - + Enter pattern to filter Nhập mẫu ký tự để lọc @@ -2951,23 +3197,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Điểm ngắt - - + + Emulation running Giả lập đang chạy - + Resume Tiếp tục - + Emulation halted at breakpoint Giả lập bị tạm dừng tại điểm ngắt @@ -3384,42 +3630,42 @@ Screen. Làm mới - + Password Required to Join Yêu cầu có mật khẩu để vào - + Password: Mật khẩu phòng: - + Room Name Tên phòng - + Preferred Game Game khuyến nghị - + Host Host - + Players Số người - + Refreshing Đang tải - + Refresh List Làm mới @@ -3442,220 +3688,245 @@ Screen. Tệp tin gần đây - + + Amiibo + + + + &Emulation &Giả lập - + &View &Hiển thị - + Debugging Đang sửa lỗi - + Screen Layout Bố trí màn hình - + Movie - + Phim - + Multiplayer Multiplayer - + &Help &Trợ giúp - + Load File... Mở tệp tin... - + Install CIA... Cài đặt CIA... - + Load Symbol Map... Nạp bảng ký tự... - + E&xit Thoát (&X) - + &Start &Bắt đầu - + &Pause Tạm &dừng - + &Stop Dừ&ng - + FAQ FAQ - + About Citra Về Citra - + Single Window Mode Chế độ đơn cửa sổ - + Configure... Thiết lập... - + Display Dock Widget Headers Hiển thị thanh Dock - + Show Filter Bar Hiển thị thanh tìm kiếm - + Show Status Bar Hiển thị trạng thái - + Select Game Directory... Chọn thư mục chứa game... - + Selects a folder to display in the game list Chọn thư mục để hiển thị danh sách game - + Create Pica Surface Viewer Tạo trình xem mặt bằng Pica - + Record Movie - + Ghi hình - + Play Movie - + Phát tệp phim - + Stop Recording / Playback + Dừng ghi hình/phát lại + + + + Enable Frame Advancing - + + Advance Frame + + + + Browse Public Game Lobby Tìm phòng kết nối - + Create Room Tạo phòng - + Leave Room Rời phòng - + Direct Connect to Room Kết nối trực tiếp đến phòng - + Show Current Room Xem phòng hiện tại - + Fullscreen Toàn màn hình - + Modify Citra Install Thay đổi cài đặt Citra - + Opens the maintenance tool to modify your Citra installation Mở công cụ bảo trì để thay đổi cài đặt của Citra - + Default Mặc định - + Single Screen Đơn màn hình - + Large Screen Màn hình lớn - + Side by Side Nằm kề nhau - + Swap Screens Đổi vị trí màn hình - + Check for Updates Kiểm tra cập nhật - + Report Compatibility Gửi báo cáo tính tương thích - + Restart Khởi động lại + + + Load... + + + + + Remove + + MicroProfileDialog @@ -3681,23 +3952,23 @@ Screen. - + Connected Đã kết nối - + Not Connected Chưa kết nối - + Error Lỗi - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: Tạo phòng công khai thất bại. Để tạo một phòng công khai, bạn cần có tài khoản Citra hợp lệ. Vào Giả lập - Thiết lập - Web để thiết lập tài khoản Citra. Nếu không muốn công khai phòng của mình, vui lòng chọn Ẩn danh. @@ -3816,106 +4087,106 @@ Thông tin debug: %1 đang chơi %2 - - + + Invalid region Vùng không hợp lệ - + Japan Nhật Bản - + North America Bắc Mỹ - + Europe Châu Âu - + Australia Úc - + China Trung Quốc - + Korea Hàn Quốc - + Taiwan Đài Loan - + Region free Khác - + Invalid Region Vùng không hợp lệ - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [chưa được thiết đặt] - + Hat %1 %2 - + Axis %1%2 - + Button %1 - - + + [unknown] [không rõ] - + [unused] [chưa được dùng] - - + + Axis %1 @@ -4200,7 +4471,7 @@ Thông tin debug: waited by no thread - waited by no thread + không có luồng nào chờ diff --git a/dist/languages/zh_CN.ts b/dist/languages/zh_CN.ts index 4feebacba..be0379d84 100644 --- a/dist/languages/zh_CN.ts +++ b/dist/languages/zh_CN.ts @@ -70,45 +70,50 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded 已加载 Pica 命令 - + Pica command processed 已处理 Pica 命令 - + Incoming primitive batch 正传入的原始批处理任务 - + Finished primitive batch 已完成的原始批处理任务 - + Vertex shader invocation 顶点着色器调用 - + Incoming display transfer 正传入的显示调用 - + GSP command processed 已处理的 GSP 命令 - + Buffers swapped 交换缓冲区 + + + Unknown debug context event + 未知调试上下文的事件 + CalibrationConfigurationDialog @@ -140,7 +145,7 @@ p, li { white-space: pre-wrap; } OK - OK + 确定 @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } 游戏 - - + + Block Player 屏蔽玩家 - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? 屏蔽玩家后,你将不会收到其发送的聊天信息。<br><br>确定要屏蔽 %1 吗? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected 已连接 - + Disconnected 已断开连接 - + %1 (%2/%3 members) - connected %1 (%2/%3 人) 已连接 @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! 感谢您向我们提交信息! + + + Submitting + 提交中 + + + + Communication error + 网络错误 + + + + An error occured while sending the Testcase + 在提交测试用例时发生了一个错误。 + + + + Next + 下一步 + ConfigureAudio @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + %1% @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration Citra 设置 - + + + General 通用 - + + + System 系统 - + + + Input 输入 - + + + Graphics 图形 - + + + Audio 声音 - + + + Camera 摄像头 - + + + Debug 调试 - + + + Web 网络 + + + + + UI + 界面 + + + + Controls + 控制 + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } 在游戏运行时退出需要确认 - - Interface language - 界面语言 - - - + Updates 更新 - + Check for updates on start 启动时检查更新 - + Silently auto update after closing 关闭后静默自动更新 - + Emulation 模拟 - + Region: 地区: - + Auto-select 自动选择 - - Theme - 主题 - - - - Theme: - 主题: - - - + Hotkeys 热键 - - <System> - <系统> + + Reset All Settings + 重置所有设置 - - English - English + + Citra + Citra + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + 你确定要<b>重置所有设置</b>并关闭 Citra 吗? @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick 设置摇杆 @@ -1038,7 +1081,7 @@ p, li { white-space: pre-wrap; } Misc. - 杂项. + 杂项 @@ -1067,11 +1110,44 @@ p, li { white-space: pre-wrap; } + Clear All + 全部清除 + + + Restore Defaults 恢复默认设置 - + + + Clear + 清除 + + + + + [not set] + [未设置] + + + + + Restore Default + 恢复默认 + + + + Information + 信息 + + + + After pressing OK, first move your joystick horizontally, and then vertically. + 在按下确定后,首先水平移动你的手柄,然后垂直移动它。 + + + [press key] [请按一个键] @@ -1440,17 +1516,27 @@ p, li { white-space: pre-wrap; } 启动时间 - + + yyyy-MM-ddTHH:mm:ss + yyyy-MM-ddTHH:mm:ss + + + + Play Coins: + 游戏币: + + + Console ID: 设备 ID: - + Regenerate 重置 ID - + System settings are available only when game is not running. 只有当游戏不在运行时,系统设置才可用。 @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } 百慕大群岛 - - + + Console ID: 0x%1 设备 ID: 0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? 这将使用一个新的虚拟 3DS 取代你当前的虚拟 3DS。您当前的虚拟 3DS 将无法恢复。在部分游戏中可能会出现意外效果。如果你使用一个过时的配置存档这可能会失败。确定要继续吗? - + Warning 警告 + + ConfigureUi + + + Form + Form + + + + General + 通用 + + + + Interface language: + 界面语言: + + + + Theme: + 主题: + + + + Game List + 游戏列表 + + + + Icon Size: + 图标大小: + + + + + None + + + + + Small (24x24) + 小 (24x24) + + + + Large (48x48) + 大 (48x48) + + + + Row 1 Text: + 第一行: + + + + + File Name + 文件名 + + + + + Full Path + 文件路径 + + + + + Title Name + 游戏名称 + + + + + Title ID + 游戏 ID + + + + Row 2 Text: + 第二行: + + + + Hide Titles without Icon + 隐藏没有图标的游戏 + + + + <System> + <系统> + + + + English + 英语 + + ConfigureWeb @@ -2155,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify 验证 @@ -2215,48 +2399,48 @@ p, li { white-space: pre-wrap; } 在您的 Discord 状态中显示当前运行的游戏 - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">了解更多</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">注册</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">注册</span></a> - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">什么是令牌?</span></a> - - + + Telemetry ID: 0x%1 数据 ID:0x%1 - + Username and token not verified 用户名和令牌未被验证 - + Username and token were not verified. The changes to your username and/or token have not been saved. 用户名和令牌未被验证。对用户名和/或凭证的更改尚未保存。 - + Verifying 验证中 - + Verification failed 验证失败 - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. 验证失败。检查您输入的用户名和令牌是否正确,并且您的互联网连接是否正常。 @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting 连接中 - + Connect 连接 @@ -2330,413 +2514,445 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>我们收集匿名数据</a>来帮助改进 Citra 。<br/><br/>您愿意和我们分享你的使用数据吗? - + Telemetry 使用数据共享 - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. 当前模拟速度。高于或低于 100% 的值表示模拟正在运行得比实际 3DS 更快或更慢。 - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. 游戏当前运行的帧率。这将因游戏和场景的不同而有所不同。 - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. 在不计算速度限制和垂直同步的情况下,模拟一个 3DS 帧的实际时间。若要进行全速模拟,这个数值不应超过 16.67 毫秒。 - + Clear Recent Files 清除最近文件 - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available 更新可用 - + An update is available. Would you like to install it now? 有更新可用。您想现在安装吗? - + No Update Found 没有发现更新 - + No update is found. 没有找到更新。 - - + + OpenGL 3.3 Unsupported + 不支持 OpenGL 3.3 + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + 您的 GPU 可能不支持 OpenGL 3.3,或者您没有安装最新的图形驱动程序。 + + + + Invalid ROM Format 无效 ROM 格式 - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. 您的 ROM 格式不受支持。<br/>请按照 wiki 文章来重新转储您的<a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>游戏卡带</a>或<a href='https://citra-emu.org/wiki/dumping-installed-titles/'>已安装的游戏</a>。 - + ROM Corrupted ROM 损坏 - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. 您的 ROM 已损坏。<br/> 请按照 wiki 文章来重新转储您的<a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>游戏卡带</a>或<a href='https://citra-emu.org/wiki/dumping-installed-titles/'>已安装的游戏</a>。 - + ROM Encrypted 加密 ROM - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. 您的 ROM 是加密的。<br/> 请按照 wiki 文章重新转储您的<a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>游戏卡带</a>或<a href='https://citra-emu.org/wiki/dumping-installed-titles/'>已安装的游戏</a>。 - - + + Video Core Error 视频核心错误 - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. 发生了错误。 请<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>参阅日志</a>了解更多详情。请确保您已安装最新的 GPU 图形驱动程序。 - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. 您正在运行默认的 Windows 驱动程序。您需要从制造商的网站为您的显卡安装正确的驱动程序。 - + Error while loading ROM! 加载 ROM 时出错! - + An unknown error occured. Please see the log for more details. 发生了一个未知的错误。详情请参阅日志。 - + Start 开始 - + Error Opening %1 Folder 无法打开 %1 文件夹 - - + + Folder does not exist! 文件夹不存在! - + Error Opening %1 无法打开 %1 - + Select Directory 选择目录 - - 3DS Executable - 3DS 可执行文件 + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + 3DS 可执行文件 (%1);;所有文件 (*.*) - - - All Files (*.*) - 所有文件 (*.*) - - - + Load File 加载文件 - + Load Files 加载多个文件 - + 3DS Installation File (*.CIA*) 3DS 安装文件 (*.CIA*) - + + All Files (*.*) + 所有文件 (*.*) + + + %1 has been installed successfully. %1 已成功安装。 - + Unable to open File 无法打开文件 - + Could not open %1 无法打开 %1 - + Installation aborted 安装失败 - + The installation of %1 was aborted. Please see the log for more details %1 的安装过程失败。详情请参看日志 - + Invalid File 文件无效 - + %1 is not a valid CIA %1 不是有效的 CIA 文件 - + Encrypted File 文件已加密 - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 需要解密才能被 Citra 识别。解密过程需要一台实体 3DS 游戏机。 - + File not found 找不到文件 - + File "%1" not found 文件 "%1" 未找到 - - - + + + Continue 继续 - + Missing Citra Account 没有 Citra 帐号 - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. 您必须设置您的 Citra 帐户来提交测试用例。<br/>请前往模拟 > 设置… > 网络进行设置。 - - - + + Amiibo File (%1);; All Files (*.*) + Amiibo 文件 (%1);;所有文件 (*.*) + + + + Load Amiibo + 加载 Amiibo + + + + + + Record Movie 录制影像 - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + 为保持随机数的一致性,推荐从游戏开始起录制影像。<br>你确定仍然要现在开始录制影像吗? + + + + Citra TAS Movie (*.ctm) Citra TAS 影像 (*.ctm) - + Recording will start once you boot a game. 一旦启动游戏,录制就会开始。 - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? 您要加载的影像文件是在另一个版本的 Citra 上创建的。<br/>Citra 在此期间有一些更改,您的影像可能无法正常工作。<br/><br/>您确定仍然要加载影像文件么? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? 您要加载的影像文件是使用不同的游戏录制的。<br/>播放可能无法正常工作,并且可能会导致意外结果。<br/><br/>您确定仍然要加载影像文件么? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. 您要加载的影像文件无效。<br/>可能是文件损坏,或 Citra 已对影像模块进行了一些重大更改。<br/>请选择其他影像文件重试。 - + Revision Dismatch 版本不匹配 - + Game Dismatch 游戏不匹配 - - + + Invalid Movie File 影像文件无效 - + + Play Movie 播放影像 - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + 为保持随机数的一致性,推荐从游戏开始起播放影像。<br>你确定仍然要现在开始播放影像吗? + + + Game Not Found 游戏未找到 - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. 您尝试播放的影像来自一个不在游戏列表中的游戏。如果您拥有该游戏,请将游戏文件夹添加到游戏列表中,并尝试再次播放该影像。 - + Movie recording cancelled. 影像录制已取消。 - + Movie Saved 影像已保存 - + The movie is successfully saved. 影像已成功保存。 - + Speed: %1% / %2% 速度: %1% / %2% - + Speed: %1% 速度: %1% - + Game: %1 FPS FPS: %1 - + Frame: %1 ms 帧延迟:%1 毫秒 - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. 未找到 %1。 请<a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>转储您的系统档案</a>。<br/>继续进行模拟可能会导致崩溃和错误。 - + System Archive Not Found 未找到系统档案 - + Fatal Error 致命错误 - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. 发生了致命错误。请<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>参阅日志</a>了解详细信息。<br/>继续进行模拟可能会导致崩溃和错误。 - + Abort 中止 - - + + Citra Citra - + Would you like to exit now? 您现在要退出么? - + The game is still running. Would you like to stop emulation? 游戏仍在运行。您想停止模拟吗? - + Playback Completed 播放完成 - + Movie playback completed. 影像播放完成。 - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2799,37 +3015,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + 名称 + + + + Compatibility + 兼容性 + + + + Region + 地区 + + + + File type + 文件类型 + + + + Size + 大小 + + + Open Save Data Location 打开存档位置 - + + Open Extra Data Location + 打开附加存档数据位置 + + + Open Application Location 打开应用程序位置 - + Open Update Data Location 打开更新数据位置 - + Navigate to GameDB entry 查看兼容性报告 - + Scan Subfolders 扫描子文件夹 - + Remove Game Directory 删除游戏目录 - + Open Directory Location 打开目录位置 @@ -2837,77 +3083,77 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect 完美 - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. 游戏功能完美,没有音频或图形问题。所有测试的功能均能工作,不需要任何特殊技巧去完成游戏。 - + Great 良好 - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. 游戏运行时会有非常轻微的图像或音频问题,但是能从头玩到尾。可能需要一些技巧才能完成游戏。 - + Okay 一般 - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. 游戏运行时会有很多图像或音频错误,但是在使用一些特殊技巧之后能完整地完成游戏。 - + Bad 较差 - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. 游戏能运行,但是会有大量图像或音频错误。即使使用一些技巧仍无法通过游戏的某些区域。 - + Intro/Menu 开场 / 菜单 - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. 游戏完全没法玩,图像或音频有重大错误。通过开场菜单后无法继续。 - + Won't Boot 无法打开 - + The game crashes when attempting to startup. 在启动游戏时直接崩溃了。 - + Not Tested 未测试 - + The game has not yet been tested. 游戏尚未经过测试。 @@ -2915,7 +3161,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the game list 双击添加游戏文件夹 @@ -2923,27 +3169,27 @@ Screen. GameListSearchField - + of - + result 结果 - + results 结果 - + Filter: 搜索: - + Enter pattern to filter 搜索游戏 @@ -2951,23 +3197,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Pica 断点 - - + + Emulation running 模拟正在运行 - + Resume 继续 - + Emulation halted at breakpoint 模拟停止在断点处 @@ -3384,42 +3630,42 @@ Screen. 刷新大厅 - + Password Required to Join 需要密码 - + Password: 密码: - + Room Name 房间名称 - + Preferred Game 首选游戏 - + Host 创建者 - + Players 玩家 - + Refreshing 正在刷新 - + Refresh List 刷新列表 @@ -3442,220 +3688,245 @@ Screen. 最近文件 - + + Amiibo + Amiibo + + + &Emulation 模拟 (&E) - + &View 视图 (&V) - + Debugging 调试 - + Screen Layout 屏幕布局 - + Movie 影像 - + Multiplayer 多人游戏 - + &Help 帮助 (&H) - + Load File... 加载文件… - + Install CIA... 安装 CIA… - + Load Symbol Map... 加载符号表… - + E&xit 退出 (&X) - + &Start 开始 (&S) - + &Pause 暂停 (&P) - + &Stop 停止 (&S) - + FAQ 常见问题 - + About Citra 关于 Citra - + Single Window Mode 单窗口模式 - + Configure... 设置… - + Display Dock Widget Headers 显示停靠小部件的标题 - + Show Filter Bar 显示过滤栏 - + Show Status Bar 显示状态栏 - + Select Game Directory... 选择游戏路径… - + Selects a folder to display in the game list 选择一个文件夹在游戏列表中显示 - + Create Pica Surface Viewer 新建 Pica 表面浏览器 - + Record Movie 录制影像 - + Play Movie 播放影像 - + Stop Recording / Playback 停止录制 / 播放 - + + Enable Frame Advancing + 逐帧播放 + + + + Advance Frame + 播放下一帧 + + + Browse Public Game Lobby 浏览公共游戏大厅 - + Create Room 创建房间 - + Leave Room 离开房间 - + Direct Connect to Room 直接连接到房间 - + Show Current Room 显示当前房间 - + Fullscreen 全屏 - + Modify Citra Install 更改 Citra 安装 - + Opens the maintenance tool to modify your Citra installation 打开维护工具修改 Citra 安装 - + Default 默认 - + Single Screen 单屏 - + Large Screen 大屏 - + Side by Side 横屏 - + Swap Screens 交换上下屏 - + Check for Updates 检查更新 - + Report Compatibility 报告兼容性 - + Restart 重新启动 + + + Load... + 加载... + + + + Remove + 移除 + MicroProfileDialog @@ -3681,23 +3952,23 @@ Screen. - + Connected 已连接 - + Not Connected 未连接 - + Error 错误 - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: 未能创建公开房间。您必须在模拟 - 设置 - 网络中配置有效的 Citra 账户。如果您不希望您的房间在公共游戏大厅中显示,请选择“私有”。 @@ -3816,106 +4087,106 @@ Debug Message: %1 在玩 %2 - - + + Invalid region 无效的地区 - + Japan 日本 - + North America 北美洲 - + Europe 欧洲 - + Australia 澳大利亚 - + China 中国 - + Korea 朝鲜 - + Taiwan 台湾 - + Region free 不锁区 - + Invalid Region 无效的地区 - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [未设置] - + Hat %1 %2 方向键 %1 %2 - + Axis %1%2 轴 %1%2 - + Button %1 按键 %1 - - + + [unknown] [未知] - + [unused] [未使用] - - + + Axis %1 轴 %1 diff --git a/dist/languages/zh_TW.ts b/dist/languages/zh_TW.ts index 31e1f2660..5a3204e83 100644 --- a/dist/languages/zh_TW.ts +++ b/dist/languages/zh_TW.ts @@ -70,45 +70,50 @@ p, li { white-space: pre-wrap; } BreakPointModel - + Pica command loaded 已讀取 Pica 命令 - + Pica command processed 已處理 Pica 命令 - + Incoming primitive batch 原始批次任務傳入 - + Finished primitive batch 原始批次任務結束 - + Vertex shader invocation 頂點著色器調用 - + Incoming display transfer 畫面轉移傳入 - + GSP command processed 已處理 GSP 命令 - + Buffers swapped 已交換緩衝 + + + Unknown debug context event + + CalibrationConfigurationDialog @@ -171,13 +176,13 @@ p, li { white-space: pre-wrap; } 遊戲 - - + + Block Player 阻擋玩家 - + When you block a player, you will no longer receive chat messages from them.<br><br>Are you sure you would like to block %1? 阻擋玩家後,你將不會收到他傳送的聊天訊息。<br><br>你確定你想要阻擋「%1」嗎? @@ -198,17 +203,17 @@ p, li { white-space: pre-wrap; } ClientRoomWindow - + Connected 已連線 - + Disconnected 已斷線 - + %1 (%2/%3 members) - connected %1(%2/%3 人)- 已連線 @@ -301,6 +306,26 @@ p, li { white-space: pre-wrap; } Thank you for your submission! 感謝您的回報! + + + Submitting + + + + + Communication error + + + + + An error occured while sending the Testcase + + + + + Next + + ConfigureAudio @@ -340,10 +365,10 @@ p, li { white-space: pre-wrap; } 0 % - - - %1 % - %1 % + + %1% + Volume percentage (e.g. 50%) + @@ -606,50 +631,78 @@ p, li { white-space: pre-wrap; } ConfigureDialog - + Citra Configuration Citra 設定 - + + + General 一般 - + + + System 系統 - + + + Input 輸入 - + + + Graphics 圖形 - + + + Audio 音效 - + + + Camera 相機 - + + + Debug 除錯 - + + + Web 網路 + + + + + UI + + + + + Controls + + ConfigureGeneral @@ -669,64 +722,54 @@ p, li { white-space: pre-wrap; } 在遊戲執行中離開時確認 - - Interface language - 介面語言 - - - + Updates 更新 - + Check for updates on start 啟動時檢查更新 - + Silently auto update after closing 關閉後在背景自動更新 - + Emulation 模擬 - + Region: 地區: - + Auto-select 自動選擇 - - Theme - 主題 - - - - Theme: - 面版主題: - - - + Hotkeys 熱鍵 - - <System> - < 系統 > + + Reset All Settings + - - English - English + + Citra + + + + + Are you sure you want to <b>reset your settings</b> and close Citra? + @@ -1026,7 +1069,7 @@ p, li { white-space: pre-wrap; } - + Set Analog Stick 設定類比搖桿 @@ -1067,11 +1110,44 @@ p, li { white-space: pre-wrap; } + Clear All + + + + Restore Defaults 還原預設 - + + + Clear + + + + + + [not set] + + + + + + Restore Default + + + + + Information + + + + + After pressing OK, first move your joystick horizontally, and then vertically. + + + + [press key] [ 請輸入按鍵 ] @@ -1440,17 +1516,27 @@ p, li { white-space: pre-wrap; } - + + yyyy-MM-ddTHH:mm:ss + + + + + Play Coins: + + + + Console ID: 裝置 ID: - + Regenerate 更換 ID - + System settings are available only when game is not running. 遊戲執行時不能修改系統設定。 @@ -2120,22 +2206,120 @@ p, li { white-space: pre-wrap; } - - + + Console ID: 0x%1 裝置 ID:0x%1 - + This will replace your current virtual 3DS with a new one. Your current virtual 3DS will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue? 更換 ID 等同於更換一台 3DS,產生新 ID 後將無法還原目前 ID,且可能造成部分遊戲出現錯誤。如果您的遊戲存檔使用過期設定,可能造成這個動作失敗。確定繼續嗎? - + Warning 警告 + + ConfigureUi + + + Form + + + + + General + + + + + Interface language: + + + + + Theme: + + + + + Game List + + + + + Icon Size: + + + + + + None + + + + + Small (24x24) + + + + + Large (48x48) + + + + + Row 1 Text: + + + + + + File Name + + + + + + Full Path + + + + + + Title Name + + + + + + Title ID + + + + + Row 2 Text: + + + + + Hide Titles without Icon + + + + + <System> + + + + + English + + + ConfigureWeb @@ -2155,7 +2339,7 @@ p, li { white-space: pre-wrap; } - + Verify 驗證 @@ -2215,48 +2399,48 @@ p, li { white-space: pre-wrap; } - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a> <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'><span style="text-decoration: underline; color:#039be5;">了解更多</span></a> - - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> - <a href='https://services.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">註冊</span></a> + + <a href='https://profile.citra-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a> + - + <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a> <a href='https://citra-emu.org/wiki/citra-web-service/'><span style="text-decoration: underline; color:#039be5;">什麼是 Citra 權杖?</span></a> - - + + Telemetry ID: 0x%1 遙測 ID:0x%1 - + Username and token not verified 未驗證使用者名稱和權杖 - + Username and token were not verified. The changes to your username and/or token have not been saved. 尚未驗證使用者名稱和權杖,您修改的使用者名稱或權杖尚未儲存。 - + Verifying 驗證中 - + Verification failed 驗證失敗 - + Verification failed. Check that you have entered your username and token correctly, and that your internet connection is working. 驗證失敗,請檢查您輸入的使用者名稱和權杖是否正確,且確認網路連線正常。 @@ -2317,12 +2501,12 @@ p, li { white-space: pre-wrap; } DirectConnectWindow - + Connecting 連線中 - + Connect 連線 @@ -2330,415 +2514,447 @@ p, li { white-space: pre-wrap; } GMainWindow - + <a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous data is collected</a> to help improve Citra. <br/><br/>Would you like to share your usage data with us? - + Telemetry - - + + Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a 3DS. 目前模擬速度, 「高於/低於」100% 代表模擬速度比 3DS 實機「更快/更慢」。 - - + + How many frames per second the game is currently displaying. This will vary from game to game and scene to scene. 遊戲目前的 FPS,不同的遊戲和場景會有不同數值。 - - + + Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms. 不計算影格限制或垂直同步時, 模擬一個 3DS 影格所花的時間。全速模擬時,這個數值最多應為 16.67 毫秒。 - + Clear Recent Files 清除檔案使用紀錄 - + F9 F9 - + F10 F10 - + CTRL+F CTRL+F - + Update Available - + An update is available. Would you like to install it now? - + No Update Found - + No update is found. - - + + OpenGL 3.3 Unsupported + + + + + Your GPU may not support OpenGL 3.3, or you do not have the latest graphics driver. + + + + + Invalid ROM Format - - + + Your ROM format is not supported.<br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + ROM Corrupted - + Your ROM is corrupted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - + ROM Encrypted - + Your ROM is encrypted. <br/>Please follow the guides to redump your <a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>game cartridges</a> or <a href='https://citra-emu.org/wiki/dumping-installed-titles/'>installed titles</a>. - - + + Video Core Error - + An error has occured. Please <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see the log</a> for more details. Ensure that you have the latest graphics drivers for your GPU. - + You are running default Windows drivers for your GPU. You need to install the proper drivers for your graphics card from the manufacturer's website. - + Error while loading ROM! 讀取 ROM 時出現錯誤! - + An unknown error occured. Please see the log for more details. 出現未知的錯誤,請參閱日誌了解細節。 - + Start 開始 - + Error Opening %1 Folder 開啟 %1 資料夾時錯誤 - - + + Folder does not exist! 資料夾不存在! - + Error Opening %1 開啟 %1 時錯誤 - + Select Directory 選擇目錄 - - 3DS Executable - 3DS 可執行檔案 + + 3DS Executable (%1);;All Files (*.*) + %1 is an identifier for the 3DS executable file extensions. + - - - All Files (*.*) - 所有檔案 (*.*) - - - + Load File 讀取檔案 - + Load Files 讀取多個檔案 - + 3DS Installation File (*.CIA*) 3DS 安裝檔 (*.CIA) - + + All Files (*.*) + 所有檔案 (*.*) + + + %1 has been installed successfully. 已成功安裝 %1。 - + Unable to open File 無法開啟檔案 - + Could not open %1 無法開啟 %1 - + Installation aborted 安裝中斷 - + The installation of %1 was aborted. Please see the log for more details 安裝 %1 時中斷,請參閱日誌了解細節。 - + Invalid File 無效的檔案 - + %1 is not a valid CIA %1 不是有效的 CIA 檔案 - + Encrypted File 檔案未解密 - + %1 must be decrypted before being used with Citra. A real 3DS is required. %1 需要先解密才能在 Citra 執行,正規的解密方式需要 3DS 實機。 - + File not found 找不到檔案 - + File "%1" not found 找不到「%1」 - - - + + + Continue 繼續 - + Missing Citra Account 找不到 Citra 帳號 - + You must link your Citra account to submit test cases.<br/>Go to Emulation &gt; Configure... &gt; Web to do so. - - - + + Amiibo File (%1);; All Files (*.*) + + + + + Load Amiibo + + + + + + + Record Movie - - + + To keep consistency with the RNG, it is recommended to record the movie from game start.<br>Are you sure you still want to record movies now? + + + + + Citra TAS Movie (*.ctm) - + Recording will start once you boot a game. - + The movie file you are trying to load was created on a different revision of Citra.<br/>Citra has had some changes during the time, and the playback may desync or not work as expected.<br/><br/>Are you sure you still want to load the movie file? - + The movie file you are trying to load was recorded with a different game.<br/>The playback may not work as expected, and it may cause unexpected results.<br/><br/>Are you sure you still want to load the movie file? - - + + The movie file you are trying to load is invalid.<br/>Either the file is corrupted, or Citra has had made some major changes to the Movie module.<br/>Please choose a different movie file and try again. - + Revision Dismatch - + Game Dismatch - - + + Invalid Movie File - + + Play Movie - + + To keep consistency with the RNG, it is recommended to play the movie from game start.<br>Are you sure you still want to play movies now? + + + + Game Not Found - + The movie you are trying to play is from a game that is not in the game list. If you own the game, please add the game folder to the game list and try to play the movie again. - + Movie recording cancelled. - + Movie Saved - + The movie is successfully saved. - + Speed: %1% / %2% 速度:%1% / %2% - + Speed: %1% 速度:%1% - + Game: %1 FPS FPS:%1 - + Frame: %1 ms 影格:%1 ms - + %1 is missing. Please <a href='https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + System Archive Not Found 找不到系統檔案 - + Fatal Error 嚴重錯誤 - + A fatal error occured. <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Abort - - + + Citra Citra - + Would you like to exit now? - + The game is still running. Would you like to stop emulation? - + Playback Completed - + Movie playback completed. - + Citra %1 Citra %1 - + Citra %1| %2 Citra %1| %2 @@ -2801,37 +3017,67 @@ p, li { white-space: pre-wrap; } GameList - + + Name + + + + + Compatibility + + + + + Region + + + + + File type + + + + + Size + + + + Open Save Data Location 開啟存檔位置 - + + Open Extra Data Location + + + + Open Application Location 開啟應用程式位置 - + Open Update Data Location 開啟更新檔位置 - + Navigate to GameDB entry 開啟遊戲相容性網頁 - + Scan Subfolders 掃描子資料夾 - + Remove Game Directory 在列表中移除此路徑 - + Open Directory Location 開啟資料夾位置 @@ -2839,77 +3085,77 @@ p, li { white-space: pre-wrap; } GameListItemCompat - + Perfect - + Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed. - + Great - + Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds. - + Okay - + Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds. - + Bad - + Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds. - + Intro/Menu - + Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen. - + Won't Boot - + The game crashes when attempting to startup. - + Not Tested - + The game has not yet been tested. @@ -2917,7 +3163,7 @@ Screen. GameListPlaceholder - + Double-click to add a new folder to the game list 在這裡點兩下新增資料夾到遊戲列表 @@ -2925,27 +3171,27 @@ Screen. GameListSearchField - + of / - + result 項符合 - + results 項符合 - + Filter: 項目篩選 - + Enter pattern to filter 輸入項目關鍵字 @@ -2953,23 +3199,23 @@ Screen. GraphicsBreakPointsWidget - + Pica Breakpoints Pica 斷點 - - + + Emulation running 正在模擬 - + Resume 繼續 - + Emulation halted at breakpoint 模擬停止在斷點 @@ -3386,42 +3632,42 @@ Screen. 重新整理 - + Password Required to Join 需要密碼 - + Password: 密碼: - + Room Name 房間名稱 - + Preferred Game 首選遊戲 - + Host 建立者 - + Players 玩家數 - + Refreshing 正在重新整理 - + Refresh List 重新整理 @@ -3444,220 +3690,245 @@ Screen. 最近開啟的檔案 - + + Amiibo + + + + &Emulation 模擬 (&E) - + &View 檢視 (&V) - + Debugging 除錯 - + Screen Layout 螢幕布局 - + Movie - + Multiplayer 多人連線 (&M) - + &Help 說明 (&H) - + Load File... 讀取檔案… - + Install CIA... 安裝 CIA… - + Load Symbol Map... 讀取符號圖… - + E&xit 離開 (&X) - + &Start 開始 (&S) - + &Pause 暫停 (&P) - + &Stop 停止 (&S) - + FAQ 常見問題 - + About Citra 關於 Citra - + Single Window Mode 統一視窗 - + Configure... 設定… - + Display Dock Widget Headers 顯示小工具的標題 - + Show Filter Bar 顯示項目篩選列 - + Show Status Bar 顯示狀態列 - + Select Game Directory... 選擇遊戲目錄… - + Selects a folder to display in the game list 選擇遊戲資料夾以顯示遊戲列表 - + Create Pica Surface Viewer 建立 Pica 表層檢視器 - + Record Movie - + Play Movie - + Stop Recording / Playback - + + Enable Frame Advancing + + + + + Advance Frame + + + + Browse Public Game Lobby 瀏覽公共房間 - + Create Room 建立房間 - + Leave Room 離開房間 - + Direct Connect to Room 連線到特定房間 - + Show Current Room 顯示目前房間 - + Fullscreen 全螢幕 - + Modify Citra Install 修改 Citra 安裝細節 - + Opens the maintenance tool to modify your Citra installation 開啟管理工具修改 Citra 的安裝細節 - + Default 預設 - + Single Screen 單一畫面 - + Large Screen 大畫面 - + Side by Side 並排 - + Swap Screens 交換上下畫面 - + Check for Updates 檢查更新 - + Report Compatibility 回報遊戲相容性 - + Restart 重新開始 + + + Load... + + + + + Remove + + MicroProfileDialog @@ -3683,23 +3954,23 @@ Screen. - + Connected 已連線 - + Not Connected 未連線 - + Error 錯誤 - + Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid Citra account configured in Emulation -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. Debug Message: 無法發布公共房間,您必須先在設定介面的「網路」標籤頁中設定有效的 Citra 帳號。如果您不希望在公共房間列表中顯示您的房間,請在下方選擇「不列出」。 @@ -3818,106 +4089,106 @@ Debug Message: %1 正在玩 %2 - - + + Invalid region 無效的地區 - + Japan 日本 - + North America 北美洲 - + Europe 歐洲 - + Australia 澳洲 - + China 中國 - + Korea 南韓 - + Taiwan 台灣 - + Region free 不鎖區 - + Invalid Region 無效的地區 - + Shift Shift - + Ctrl Ctrl - + Alt Alt - - + + [not set] [ 無設定 ] - + Hat %1 %2 - + Axis %1%2 - + Button %1 - - + + [unknown] [ 未知 ] - + [unused] [ 未使用 ] - - + + Axis %1 From 57e1f47a52983ac0999b75c8aeb41c7a6228e04e Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sun, 4 Nov 2018 04:24:37 -0500 Subject: [PATCH 089/102] Kernel: destruct thread/timer managers after processes (#4399) Processes can keep some Thread/Timer object alive while the manager is already destructed, resulting use-after-free in Thread::Stop and Timer::dtor. To resolve this, the manager objects should be destructed after all related object destructed. Fixes a bug where quiting citra causes crash while the game is using a Timer. --- src/core/hle/kernel/kernel.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index f010cd388..f09fd99b2 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -228,6 +228,9 @@ private: std::unique_ptr resource_limits; std::atomic next_object_id{0}; + std::unique_ptr thread_manager; + std::unique_ptr timer_manager; + // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are // reserved for low-level services u32 next_process_id = 10; @@ -237,9 +240,6 @@ private: SharedPtr current_process; - std::unique_ptr thread_manager; - std::unique_ptr timer_manager; - std::unique_ptr config_mem_handler; std::unique_ptr shared_page_handler; }; From 2d9dfe5bceccf8175fde15ac12b2ee14c724d323 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sun, 4 Nov 2018 09:29:28 -0500 Subject: [PATCH 090/102] Kernel: thread manager still has to be destructed first --- src/core/hle/kernel/kernel.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index f09fd99b2..2beaaa067 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -228,7 +228,13 @@ private: std::unique_ptr resource_limits; std::atomic next_object_id{0}; - std::unique_ptr thread_manager; + // Note: keep the member order below in order to perform correct destruction. + // Thread manager is destructed before process list in order to Stop threads and clear thread + // info from their parent processes first. Timer manager is destructed after process list + // because timers are destructed along with process list and they need to clear info from the + // timer manager. + // TODO (wwylele): refactor the cleanup sequence to make this less complicated and sensitive. + std::unique_ptr timer_manager; // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are @@ -240,6 +246,8 @@ private: SharedPtr current_process; + std::unique_ptr thread_manager; + std::unique_ptr config_mem_handler; std::unique_ptr shared_page_handler; }; From 9458e4d8ec168b1cc673de72c9d22fda27c25b04 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sat, 27 Oct 2018 15:53:20 -0400 Subject: [PATCH 091/102] CoreTiming: wrap into class --- src/audio_core/hle/hle.cpp | 14 +- src/core/arm/dynarmic/arm_dynarmic.cpp | 12 +- src/core/arm/dynarmic/arm_dynarmic.h | 7 +- src/core/arm/dyncom/arm_dyncom.cpp | 4 +- .../arm/dyncom/arm_dyncom_interpreter.cpp | 3 +- src/core/core.cpp | 22 +- src/core/core.h | 9 + src/core/core_timing.cpp | 131 +++-------- src/core/core_timing.h | 150 +++++++----- src/core/hle/applets/applet.cpp | 16 +- src/core/hle/kernel/shared_page.cpp | 14 +- src/core/hle/kernel/shared_page.h | 6 +- src/core/hle/kernel/svc.cpp | 5 +- src/core/hle/kernel/thread.cpp | 22 +- src/core/hle/kernel/thread.h | 2 +- src/core/hle/kernel/timer.cpp | 20 +- src/core/hle/kernel/timer.h | 2 +- src/core/hle/service/cam/cam.cpp | 8 +- src/core/hle/service/cam/cam.h | 7 +- src/core/hle/service/hid/hid.cpp | 38 ++-- src/core/hle/service/hid/hid.h | 10 +- src/core/hle/service/ir/extra_hid.cpp | 16 +- src/core/hle/service/ir/extra_hid.h | 8 +- src/core/hle/service/ir/ir_rst.cpp | 17 +- src/core/hle/service/ir/ir_rst.h | 7 +- src/core/hle/service/ir/ir_user.h | 4 - src/core/hle/service/nwm/nwm_uds.cpp | 22 +- src/core/hle/service/nwm/nwm_uds.h | 2 + src/core/hw/gpu.cpp | 9 +- src/tests/core/arm/arm_test_common.cpp | 4 +- src/tests/core/core_timing.cpp | 215 +++++++++--------- src/tests/core/hle/kernel/hle_ipc.cpp | 11 +- src/tests/core/memory/memory.cpp | 6 +- .../renderer_opengl/renderer_opengl.cpp | 3 +- 34 files changed, 413 insertions(+), 413 deletions(-) diff --git a/src/audio_core/hle/hle.cpp b/src/audio_core/hle/hle.cpp index 58604d861..db50c0bff 100644 --- a/src/audio_core/hle/hle.cpp +++ b/src/audio_core/hle/hle.cpp @@ -12,6 +12,7 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" +#include "core/core.h" #include "core/core_timing.h" using InterruptType = Service::DSP::DSP_DSP::InterruptType; @@ -63,7 +64,7 @@ private: HLE::Mixers mixers; DspHle& parent; - CoreTiming::EventType* tick_event; + Core::TimingEventType* tick_event; std::weak_ptr dsp_dsp; }; @@ -71,15 +72,17 @@ private: DspHle::Impl::Impl(DspHle& parent_) : parent(parent_) { dsp_memory.raw_memory.fill(0); + Core::Timing& timing = Core::System::GetInstance().CoreTiming(); tick_event = - CoreTiming::RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) { + timing.RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) { this->AudioTickCallback(cycles_late); }); - CoreTiming::ScheduleEvent(audio_frame_ticks, tick_event); + timing.ScheduleEvent(audio_frame_ticks, tick_event); } DspHle::Impl::~Impl() { - CoreTiming::UnscheduleEvent(tick_event, 0); + Core::Timing& timing = Core::System::GetInstance().CoreTiming(); + timing.UnscheduleEvent(tick_event, 0); } DspState DspHle::Impl::GetDspState() const { @@ -328,7 +331,8 @@ void DspHle::Impl::AudioTickCallback(s64 cycles_late) { } // Reschedule recurrent event - CoreTiming::ScheduleEvent(audio_frame_ticks - cycles_late, tick_event); + Core::Timing& timing = Core::System::GetInstance().CoreTiming(); + timing.ScheduleEvent(audio_frame_ticks - cycles_late, tick_event); } DspHle::DspHle() : impl(std::make_unique(*this)) {} diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index b079afa9a..e3965f2fe 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -71,7 +71,8 @@ private: class DynarmicUserCallbacks final : public Dynarmic::A32::UserCallbacks { public: - explicit DynarmicUserCallbacks(ARM_Dynarmic& parent) : parent(parent) {} + explicit DynarmicUserCallbacks(ARM_Dynarmic& parent) + : parent(parent), timing(parent.system.CoreTiming()) {} ~DynarmicUserCallbacks() = default; std::uint8_t MemoryRead8(VAddr vaddr) override { @@ -148,18 +149,19 @@ public: } void AddTicks(std::uint64_t ticks) override { - CoreTiming::AddTicks(ticks); + timing.AddTicks(ticks); } std::uint64_t GetTicksRemaining() override { - s64 ticks = CoreTiming::GetDowncount(); + s64 ticks = timing.GetDowncount(); return static_cast(ticks <= 0 ? 0 : ticks); } ARM_Dynarmic& parent; + Core::Timing& timing; }; -ARM_Dynarmic::ARM_Dynarmic(PrivilegeMode initial_mode) - : cb(std::make_unique(*this)) { +ARM_Dynarmic::ARM_Dynarmic(Core::System& system, PrivilegeMode initial_mode) + : system(system), cb(std::make_unique(*this)) { interpreter_state = std::make_shared(initial_mode); PageTableChanged(); } diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index 5a1f85e22..0a73c05ac 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -15,11 +15,15 @@ namespace Memory { struct PageTable; } // namespace Memory +namespace Core { +struct System; +} + class DynarmicUserCallbacks; class ARM_Dynarmic final : public ARM_Interface { public: - explicit ARM_Dynarmic(PrivilegeMode initial_mode); + ARM_Dynarmic(Core::System& system, PrivilegeMode initial_mode); ~ARM_Dynarmic(); void Run() override; @@ -50,6 +54,7 @@ public: private: friend class DynarmicUserCallbacks; + Core::System& system; std::unique_ptr cb; std::unique_ptr MakeJit(); diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index 3dc1aa2f0..d3113632c 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp @@ -75,7 +75,7 @@ ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { ARM_DynCom::~ARM_DynCom() {} void ARM_DynCom::Run() { - ExecuteInstructions(std::max(CoreTiming::GetDowncount(), 0)); + ExecuteInstructions(std::max(Core::System::GetInstance().CoreTiming().GetDowncount(), 0)); } void ARM_DynCom::Step() { @@ -146,7 +146,7 @@ void ARM_DynCom::SetCP15Register(CP15Register reg, u32 value) { void ARM_DynCom::ExecuteInstructions(u64 num_instructions) { state->NumInstrsToExecute = num_instructions; unsigned ticks_executed = InterpreterMainLoop(state.get()); - CoreTiming::AddTicks(ticks_executed); + Core::System::GetInstance().CoreTiming().AddTicks(ticks_executed); state->ServeBreak(); } diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index cd70b8da3..c6be38873 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -18,6 +18,7 @@ #include "core/arm/skyeye_common/armstate.h" #include "core/arm/skyeye_common/armsupp.h" #include "core/arm/skyeye_common/vfp/vfp.h" +#include "core/core.h" #include "core/core_timing.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/svc.h" @@ -3859,7 +3860,7 @@ SUB_INST : { SWI_INST : { if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { swi_inst* const inst_cream = (swi_inst*)inst_base->component; - CoreTiming::AddTicks(num_instrs); + Core::System::GetInstance().CoreTiming().AddTicks(num_instrs); cpu->NumInstrsToExecute = num_instrs >= cpu->NumInstrsToExecute ? 0 : cpu->NumInstrsToExecute - num_instrs; num_instrs = 0; diff --git a/src/core/core.cpp b/src/core/core.cpp index 78585380c..52b27a6ca 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -61,11 +61,11 @@ System::ResultStatus System::RunLoop(bool tight_loop) { // instead advance to the next event and try to yield to the next thread if (kernel->GetThreadManager().GetCurrentThread() == nullptr) { LOG_TRACE(Core_ARM11, "Idling"); - CoreTiming::Idle(); - CoreTiming::Advance(); + timing->Idle(); + timing->Advance(); PrepareReschedule(); } else { - CoreTiming::Advance(); + timing->Advance(); if (tight_loop) { cpu_core->Run(); } else { @@ -155,7 +155,7 @@ void System::PrepareReschedule() { } PerfStats::Results System::GetAndResetPerfStats() { - return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs()); + return perf_stats.GetAndResetStats(timing->GetGlobalTimeUs()); } void System::Reschedule() { @@ -170,11 +170,11 @@ void System::Reschedule() { System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { LOG_DEBUG(HW_Memory, "initialized OK"); - CoreTiming::Init(); + timing = std::make_unique(); if (Settings::values.use_cpu_jit) { #ifdef ARCHITECTURE_x86_64 - cpu_core = std::make_unique(USER32MODE); + cpu_core = std::make_unique(*this, USER32MODE); #else cpu_core = std::make_unique(USER32MODE); LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); @@ -239,6 +239,14 @@ const Kernel::KernelSystem& System::Kernel() const { return *kernel; } +Timing& System::CoreTiming() { + return *timing; +} + +const Timing& System::CoreTiming() const { + return *timing; +} + void System::RegisterSoftwareKeyboard(std::shared_ptr swkbd) { registered_swkbd = std::move(swkbd); } @@ -265,7 +273,7 @@ void System::Shutdown() { service_manager.reset(); dsp_core.reset(); cpu_core.reset(); - CoreTiming::Shutdown(); + timing.reset(); app_loader.reset(); if (auto room_member = Network::GetRoomMember().lock()) { diff --git a/src/core/core.h b/src/core/core.h index 0cb53475f..af1291856 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -41,6 +41,8 @@ class KernelSystem; namespace Core { +class Timing; + class System { public: /** @@ -176,6 +178,12 @@ public: /// Gets a const reference to the kernel const Kernel::KernelSystem& Kernel() const; + /// Gets a reference to the timing system + Timing& CoreTiming(); + + /// Gets a const reference to the timing system + const Timing& CoreTiming() const; + PerfStats perf_stats; FrameLimiter frame_limiter; @@ -246,6 +254,7 @@ private: public: // HACK: this is temporary exposed for tests, // due to WIP kernel refactor causing desync state in memory std::unique_ptr kernel; + std::unique_ptr timing; private: static System s_instance; diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index ccee38243..df355ab27 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -2,75 +2,25 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "core/core_timing.h" - #include #include -#include -#include #include -#include -#include #include "common/assert.h" #include "common/logging/log.h" -#include "common/thread.h" -#include "common/threadsafe_queue.h" +#include "core/core_timing.h" -namespace CoreTiming { - -static s64 global_timer; -static s64 slice_length; -static s64 downcount; - -struct EventType { - TimedCallback callback; - const std::string* name; -}; - -struct Event { - s64 time; - u64 fifo_order; - u64 userdata; - const EventType* type; -}; +namespace Core { // Sort by time, unless the times are the same, in which case sort by the order added to the queue -static bool operator>(const Event& left, const Event& right) { - return std::tie(left.time, left.fifo_order) > std::tie(right.time, right.fifo_order); +bool Timing::Event::operator>(const Event& right) const { + return std::tie(time, fifo_order) > std::tie(right.time, right.fifo_order); } -static bool operator<(const Event& left, const Event& right) { - return std::tie(left.time, left.fifo_order) < std::tie(right.time, right.fifo_order); +bool Timing::Event::operator<(const Event& right) const { + return std::tie(time, fifo_order) < std::tie(right.time, right.fifo_order); } -// unordered_map stores each element separately as a linked list node so pointers to elements -// remain stable regardless of rehashes/resizing. -static std::unordered_map event_types; - -// The queue is a min-heap using std::make_heap/push_heap/pop_heap. -// We don't use std::priority_queue because we need to be able to serialize, unserialize and -// erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't accomodated -// by the standard adaptor class. -static std::vector event_queue; -static u64 event_fifo_id; -// the queue for storing the events from other threads threadsafe until they will be added -// to the event_queue by the emu thread -static Common::MPSCQueue ts_queue; - -static constexpr int MAX_SLICE_LENGTH = 20000; - -static s64 idled_cycles; - -// Are we in a function that has been called from Advance() -// If events are sheduled from a function that gets called from Advance(), -// don't change slice_length and downcount. -static bool is_global_timer_sane; - -static EventType* ev_lost = nullptr; - -static void EmptyTimedCallback(u64 userdata, s64 cyclesLate) {} - -EventType* RegisterEvent(const std::string& name, TimedCallback callback) { +TimingEventType* Timing::RegisterEvent(const std::string& name, TimedCallback callback) { // check for existing type with same name. // we want event type names to remain unique so that we can use them for serialization. ASSERT_MSG(event_types.find(name) == event_types.end(), @@ -78,42 +28,17 @@ EventType* RegisterEvent(const std::string& name, TimedCallback callback) { "during Init to avoid breaking save states.", name); - auto info = event_types.emplace(name, EventType{callback, nullptr}); - EventType* event_type = &info.first->second; + auto info = event_types.emplace(name, TimingEventType{callback, nullptr}); + TimingEventType* event_type = &info.first->second; event_type->name = &info.first->first; return event_type; } -void UnregisterAllEvents() { - ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending"); - event_types.clear(); -} - -void Init() { - downcount = MAX_SLICE_LENGTH; - slice_length = MAX_SLICE_LENGTH; - global_timer = 0; - idled_cycles = 0; - - // The time between CoreTiming being intialized and the first call to Advance() is considered - // the slice boundary between slice -1 and slice 0. Dispatcher loops must call Advance() before - // executing the first cycle of each slice to prepare the slice length and downcount for - // that slice. - is_global_timer_sane = true; - - event_fifo_id = 0; - ev_lost = RegisterEvent("_lost_event", &EmptyTimedCallback); -} - -void Shutdown() { +Timing::~Timing() { MoveEvents(); - ClearPendingEvents(); - UnregisterAllEvents(); } -// This should only be called from the CPU thread. If you are calling -// it from any other thread, you are doing something evil -u64 GetTicks() { +u64 Timing::GetTicks() const { u64 ticks = static_cast(global_timer); if (!is_global_timer_sane) { ticks += slice_length - downcount; @@ -121,19 +46,16 @@ u64 GetTicks() { return ticks; } -void AddTicks(u64 ticks) { +void Timing::AddTicks(u64 ticks) { downcount -= ticks; } -u64 GetIdleTicks() { +u64 Timing::GetIdleTicks() const { return static_cast(idled_cycles); } -void ClearPendingEvents() { - event_queue.clear(); -} - -void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) { +void Timing::ScheduleEvent(s64 cycles_into_future, const TimingEventType* event_type, + u64 userdata) { ASSERT(event_type != nullptr); s64 timeout = GetTicks() + cycles_into_future; @@ -145,11 +67,12 @@ void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 user std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); } -void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata) { +void Timing::ScheduleEventThreadsafe(s64 cycles_into_future, const TimingEventType* event_type, + u64 userdata) { ts_queue.Push(Event{global_timer + cycles_into_future, 0, userdata, event_type}); } -void UnscheduleEvent(const EventType* event_type, u64 userdata) { +void Timing::UnscheduleEvent(const TimingEventType* event_type, u64 userdata) { auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { return e.type == event_type && e.userdata == userdata; }); @@ -161,7 +84,7 @@ void UnscheduleEvent(const EventType* event_type, u64 userdata) { } } -void RemoveEvent(const EventType* event_type) { +void Timing::RemoveEvent(const TimingEventType* event_type) { auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { return e.type == event_type; }); @@ -172,12 +95,12 @@ void RemoveEvent(const EventType* event_type) { } } -void RemoveNormalAndThreadsafeEvent(const EventType* event_type) { +void Timing::RemoveNormalAndThreadsafeEvent(const TimingEventType* event_type) { MoveEvents(); RemoveEvent(event_type); } -void ForceExceptionCheck(s64 cycles) { +void Timing::ForceExceptionCheck(s64 cycles) { cycles = std::max(0, cycles); if (downcount > cycles) { slice_length -= downcount - cycles; @@ -185,7 +108,7 @@ void ForceExceptionCheck(s64 cycles) { } } -void MoveEvents() { +void Timing::MoveEvents() { for (Event ev; ts_queue.Pop(ev);) { ev.fifo_order = event_fifo_id++; event_queue.emplace_back(std::move(ev)); @@ -193,7 +116,7 @@ void MoveEvents() { } } -void Advance() { +void Timing::Advance() { MoveEvents(); s64 cycles_executed = slice_length - downcount; @@ -220,17 +143,17 @@ void Advance() { downcount = slice_length; } -void Idle() { +void Timing::Idle() { idled_cycles += downcount; downcount = 0; } -std::chrono::microseconds GetGlobalTimeUs() { +std::chrono::microseconds Timing::GetGlobalTimeUs() const { return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE_ARM11}; } -s64 GetDowncount() { +s64 Timing::GetDowncount() const { return downcount; } -} // namespace CoreTiming +} // namespace Core diff --git a/src/core/core_timing.h b/src/core/core_timing.h index bfafe4b6b..617c7c6d6 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -21,8 +21,11 @@ #include #include #include +#include +#include #include "common/common_types.h" #include "common/logging/log.h" +#include "common/threadsafe_queue.h" // The timing we get from the assembly is 268,111,855.956 Hz // It is possible that this number isn't just an integer because the compiler could have @@ -120,73 +123,112 @@ inline u64 cyclesToMs(s64 cycles) { return cycles * 1000 / BASE_CLOCK_RATE_ARM11; } -namespace CoreTiming { - -struct EventType; +namespace Core { using TimedCallback = std::function; -/** - * CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is - * required to end slice -1 and start slice 0 before the first cycle of code is executed. - */ -void Init(); -void Shutdown(); +struct TimingEventType { + TimedCallback callback; + const std::string* name; +}; -/** - * This should only be called from the emu thread, if you are calling it any other thread, you are - * doing something evil - */ -u64 GetTicks(); -u64 GetIdleTicks(); -void AddTicks(u64 ticks); +class Timing { +public: + ~Timing(); -/** - * Returns the event_type identifier. if name is not unique, it will assert. - */ -EventType* RegisterEvent(const std::string& name, TimedCallback callback); -void UnregisterAllEvents(); + /** + * This should only be called from the emu thread, if you are calling it any other thread, you + * are doing something evil + */ + u64 GetTicks() const; + u64 GetIdleTicks() const; + void AddTicks(u64 ticks); -/** - * After the first Advance, the slice lengths and the downcount will be reduced whenever an event - * is scheduled earlier than the current values. - * Scheduling from a callback will not update the downcount until the Advance() completes. - */ -void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata = 0); + /** + * Returns the event_type identifier. if name is not unique, it will assert. + */ + TimingEventType* RegisterEvent(const std::string& name, TimedCallback callback); -/** - * This is to be called when outside of hle threads, such as the graphics thread, wants to - * schedule things to be executed on the main thread. - * Not that this doesn't change slice_length and thus events scheduled by this might be called - * with a delay of up to MAX_SLICE_LENGTH - */ -void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata); + /** + * After the first Advance, the slice lengths and the downcount will be reduced whenever an + * event is scheduled earlier than the current values. Scheduling from a callback will not + * update the downcount until the Advance() completes. + */ + void ScheduleEvent(s64 cycles_into_future, const TimingEventType* event_type, u64 userdata = 0); -void UnscheduleEvent(const EventType* event_type, u64 userdata); + /** + * This is to be called when outside of hle threads, such as the graphics thread, wants to + * schedule things to be executed on the main thread. + * Not that this doesn't change slice_length and thus events scheduled by this might be called + * with a delay of up to MAX_SLICE_LENGTH + */ + void ScheduleEventThreadsafe(s64 cycles_into_future, const TimingEventType* event_type, + u64 userdata); -/// We only permit one event of each type in the queue at a time. -void RemoveEvent(const EventType* event_type); -void RemoveNormalAndThreadsafeEvent(const EventType* event_type); + void UnscheduleEvent(const TimingEventType* event_type, u64 userdata); -/** Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends - * the previous timing slice and begins the next one, you must Advance from the previous - * slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an - * Advance() is required to initialize the slice length before the first cycle of emulated - * instructions is executed. - */ -void Advance(); -void MoveEvents(); + /// We only permit one event of each type in the queue at a time. + void RemoveEvent(const TimingEventType* event_type); + void RemoveNormalAndThreadsafeEvent(const TimingEventType* event_type); -/// Pretend that the main CPU has executed enough cycles to reach the next event. -void Idle(); + /** Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends + * the previous timing slice and begins the next one, you must Advance from the previous + * slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an + * Advance() is required to initialize the slice length before the first cycle of emulated + * instructions is executed. + */ + void Advance(); + void MoveEvents(); -/// Clear all pending events. This should ONLY be done on exit. -void ClearPendingEvents(); + /// Pretend that the main CPU has executed enough cycles to reach the next event. + void Idle(); -void ForceExceptionCheck(s64 cycles); + void ForceExceptionCheck(s64 cycles); -std::chrono::microseconds GetGlobalTimeUs(); + std::chrono::microseconds GetGlobalTimeUs() const; -s64 GetDowncount(); + s64 GetDowncount() const; -} // namespace CoreTiming +private: + struct Event { + s64 time; + u64 fifo_order; + u64 userdata; + const TimingEventType* type; + + bool operator>(const Event& right) const; + bool operator<(const Event& right) const; + }; + + static constexpr int MAX_SLICE_LENGTH = 20000; + + s64 global_timer = 0; + s64 slice_length = MAX_SLICE_LENGTH; + s64 downcount = MAX_SLICE_LENGTH; + + // unordered_map stores each element separately as a linked list node so pointers to + // elements remain stable regardless of rehashes/resizing. + std::unordered_map event_types; + + // The queue is a min-heap using std::make_heap/push_heap/pop_heap. + // We don't use std::priority_queue because we need to be able to serialize, unserialize and + // erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't + // accomodated by the standard adaptor class. + std::vector event_queue; + u64 event_fifo_id = 0; + // the queue for storing the events from other threads threadsafe until they will be added + // to the event_queue by the emu thread + Common::MPSCQueue ts_queue; + s64 idled_cycles = 0; + + // Are we in a function that has been called from Advance() + // If events are sheduled from a function that gets called from Advance(), + // don't change slice_length and downcount. + // The time between CoreTiming being intialized and the first call to Advance() is considered + // the slice boundary between slice -1 and slice 0. Dispatcher loops must call Advance() before + // executing the first cycle of each slice to prepare the slice length and downcount for + // that slice. + bool is_global_timer_sane = true; +}; + +} // namespace Core diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp index 751b85815..f41157d2f 100644 --- a/src/core/hle/applets/applet.cpp +++ b/src/core/hle/applets/applet.cpp @@ -8,6 +8,7 @@ #include #include "common/assert.h" #include "common/common_types.h" +#include "core/core.h" #include "core/core_timing.h" #include "core/hle/applets/applet.h" #include "core/hle/applets/erreula.h" @@ -38,7 +39,7 @@ namespace Applets { static std::unordered_map> applets; /// The CoreTiming event identifier for the Applet update callback. -static CoreTiming::EventType* applet_update_event = nullptr; +static Core::TimingEventType* applet_update_event = nullptr; /// The interval at which the Applet update callback will be called, 16.6ms static const u64 applet_update_interval_us = 16666; @@ -88,8 +89,8 @@ static void AppletUpdateEvent(u64 applet_id, s64 cycles_late) { // If the applet is still running after the last update, reschedule the event if (applet->IsRunning()) { - CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late, - applet_update_event, applet_id); + Core::System::GetInstance().CoreTiming().ScheduleEvent( + usToCycles(applet_update_interval_us) - cycles_late, applet_update_event, applet_id); } else { // Otherwise the applet has terminated, in which case we should clean it up applets[id] = nullptr; @@ -101,8 +102,8 @@ ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) if (result.IsError()) return result; // Schedule the update event - CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, - static_cast(id)); + Core::System::GetInstance().CoreTiming().ScheduleEvent( + usToCycles(applet_update_interval_us), applet_update_event, static_cast(id)); return result; } @@ -128,11 +129,12 @@ bool IsLibraryAppletRunning() { void Init() { // Register the applet update callback - applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent); + applet_update_event = Core::System::GetInstance().CoreTiming().RegisterEvent( + "HLE Applet Update Event", AppletUpdateEvent); } void Shutdown() { - CoreTiming::RemoveEvent(applet_update_event); + Core::System::GetInstance().CoreTiming().RemoveEvent(applet_update_event); } } // namespace Applets } // namespace HLE diff --git a/src/core/hle/kernel/shared_page.cpp b/src/core/hle/kernel/shared_page.cpp index 831782458..e2af01e0d 100644 --- a/src/core/hle/kernel/shared_page.cpp +++ b/src/core/hle/kernel/shared_page.cpp @@ -4,6 +4,7 @@ #include #include +#include "core/core.h" #include "core/core_timing.h" #include "core/hle/kernel/shared_page.h" #include "core/hle/service/ptm/ptm.h" @@ -53,9 +54,9 @@ Handler::Handler() { init_time = GetInitTime(); using namespace std::placeholders; - update_time_event = CoreTiming::RegisterEvent( + update_time_event = Core::System::GetInstance().CoreTiming().RegisterEvent( "SharedPage::UpdateTimeCallback", std::bind(&Handler::UpdateTimeCallback, this, _1, _2)); - CoreTiming::ScheduleEvent(0, update_time_event); + Core::System::GetInstance().CoreTiming().ScheduleEvent(0, update_time_event); float slidestate = Settings::values.toggle_3d ? (float_le)Settings::values.factor_3d / 100 : 0.0f; @@ -65,8 +66,8 @@ Handler::Handler() { /// Gets system time in 3DS format. The epoch is Jan 1900, and the unit is millisecond. u64 Handler::GetSystemTime() const { std::chrono::milliseconds now = - init_time + - std::chrono::duration_cast(CoreTiming::GetGlobalTimeUs()); + init_time + std::chrono::duration_cast( + Core::System::GetInstance().CoreTiming().GetGlobalTimeUs()); // 3DS system does't allow user to set a time before Jan 1 2000, // so we use it as an auxiliary epoch to calculate the console time. @@ -97,14 +98,15 @@ void Handler::UpdateTimeCallback(u64 userdata, int cycles_late) { shared_page.date_time_counter % 2 ? shared_page.date_time_0 : shared_page.date_time_1; date_time.date_time = GetSystemTime(); - date_time.update_tick = CoreTiming::GetTicks(); + date_time.update_tick = Core::System::GetInstance().CoreTiming().GetTicks(); date_time.tick_to_second_coefficient = BASE_CLOCK_RATE_ARM11; date_time.tick_offset = 0; ++shared_page.date_time_counter; // system time is updated hourly - CoreTiming::ScheduleEvent(msToCycles(60 * 60 * 1000) - cycles_late, update_time_event); + Core::System::GetInstance().CoreTiming().ScheduleEvent(msToCycles(60 * 60 * 1000) - cycles_late, + update_time_event); } void Handler::SetMacAddress(const MacAddress& addr) { diff --git a/src/core/hle/kernel/shared_page.h b/src/core/hle/kernel/shared_page.h index 57f3bc3f2..7b6dc2e06 100644 --- a/src/core/hle/kernel/shared_page.h +++ b/src/core/hle/kernel/shared_page.h @@ -21,8 +21,8 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// -namespace CoreTiming { -struct EventType; +namespace Core { +struct TimingEventType; } namespace SharedPage { @@ -96,7 +96,7 @@ public: private: u64 GetSystemTime() const; void UpdateTimeCallback(u64 userdata, int cycles_late); - CoreTiming::EventType* update_time_event; + Core::TimingEventType* update_time_event; std::chrono::seconds init_time; SharedPageDef shared_page; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index f23b569d7..000b16e19 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1111,9 +1111,10 @@ static void SleepThread(s64 nanoseconds) { /// This returns the total CPU ticks elapsed since the CPU was powered-on static s64 GetSystemTick() { - s64 result = CoreTiming::GetTicks(); + s64 result = Core::System::GetInstance().CoreTiming().GetTicks(); // Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end. - CoreTiming::AddTicks(150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b + // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b + Core::System::GetInstance().CoreTiming().AddTicks(150); return result; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 236e1d7b0..8dd0bcaa5 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -48,7 +48,8 @@ Thread* ThreadManager::GetCurrentThread() const { void Thread::Stop() { // Cancel any outstanding wakeup events for this thread - CoreTiming::UnscheduleEvent(thread_manager.ThreadWakeupEventType, thread_id); + Core::System::GetInstance().CoreTiming().UnscheduleEvent(thread_manager.ThreadWakeupEventType, + thread_id); thread_manager.wakeup_callback_table.erase(thread_id); // Clean up thread from ready queue @@ -80,9 +81,11 @@ void Thread::Stop() { void ThreadManager::SwitchContext(Thread* new_thread) { Thread* previous_thread = GetCurrentThread(); + Core::Timing& timing = Core::System::GetInstance().CoreTiming(); + // Save context for previous thread if (previous_thread) { - previous_thread->last_running_ticks = CoreTiming::GetTicks(); + previous_thread->last_running_ticks = timing.GetTicks(); Core::CPU().SaveContext(previous_thread->context); if (previous_thread->status == ThreadStatus::Running) { @@ -99,7 +102,7 @@ void ThreadManager::SwitchContext(Thread* new_thread) { "Thread must be ready to become running."); // Cancel any outstanding wakeup events for this thread - CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->thread_id); + timing.UnscheduleEvent(ThreadWakeupEventType, new_thread->thread_id); auto previous_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); @@ -182,8 +185,8 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { if (nanoseconds == -1) return; - CoreTiming::ScheduleEvent(nsToCycles(nanoseconds), thread_manager.ThreadWakeupEventType, - thread_id); + Core::System::GetInstance().CoreTiming().ScheduleEvent( + nsToCycles(nanoseconds), thread_manager.ThreadWakeupEventType, thread_id); } void Thread::ResumeFromWait() { @@ -316,7 +319,7 @@ ResultVal> KernelSystem::CreateThread(std::string name, VAddr thread->entry_point = entry_point; thread->stack_top = stack_top; thread->nominal_priority = thread->current_priority = priority; - thread->last_running_ticks = CoreTiming::GetTicks(); + thread->last_running_ticks = Core::System::GetInstance().CoreTiming().GetTicks(); thread->processor_id = processor_id; thread->wait_objects.clear(); thread->wait_address = 0; @@ -462,10 +465,9 @@ VAddr Thread::GetCommandBufferAddress() const { } ThreadManager::ThreadManager() { - ThreadWakeupEventType = - CoreTiming::RegisterEvent("ThreadWakeupCallback", [this](u64 thread_id, s64 cycle_late) { - ThreadWakeupCallback(thread_id, cycle_late); - }); + ThreadWakeupEventType = Core::System::GetInstance().CoreTiming().RegisterEvent( + "ThreadWakeupCallback", + [this](u64 thread_id, s64 cycle_late) { ThreadWakeupCallback(thread_id, cycle_late); }); } ThreadManager::~ThreadManager() { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 06a7c5f4f..acb75a374 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -127,7 +127,7 @@ private: std::unordered_map wakeup_callback_table; /// Event type for the thread wake up event - CoreTiming::EventType* ThreadWakeupEventType = nullptr; + Core::TimingEventType* ThreadWakeupEventType = nullptr; // Lists all threadsthat aren't deleted. std::vector> thread_list; diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 07a98a659..98e180aa6 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -6,6 +6,7 @@ #include #include "common/assert.h" #include "common/logging/log.h" +#include "core/core.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/thread.h" @@ -55,13 +56,14 @@ void Timer::Set(s64 initial, s64 interval) { // Immediately invoke the callback Signal(0); } else { - CoreTiming::ScheduleEvent(nsToCycles(initial), timer_manager.timer_callback_event_type, - callback_id); + Core::System::GetInstance().CoreTiming().ScheduleEvent( + nsToCycles(initial), timer_manager.timer_callback_event_type, callback_id); } } void Timer::Cancel() { - CoreTiming::UnscheduleEvent(timer_manager.timer_callback_event_type, callback_id); + Core::System::GetInstance().CoreTiming().UnscheduleEvent( + timer_manager.timer_callback_event_type, callback_id); } void Timer::Clear() { @@ -85,8 +87,9 @@ void Timer::Signal(s64 cycles_late) { if (interval_delay != 0) { // Reschedule the timer with the interval delay - CoreTiming::ScheduleEvent(nsToCycles(interval_delay) - cycles_late, - timer_manager.timer_callback_event_type, callback_id); + Core::System::GetInstance().CoreTiming().ScheduleEvent( + nsToCycles(interval_delay) - cycles_late, timer_manager.timer_callback_event_type, + callback_id); } } @@ -103,10 +106,9 @@ void TimerManager::TimerCallback(u64 callback_id, s64 cycles_late) { } TimerManager::TimerManager() { - timer_callback_event_type = - CoreTiming::RegisterEvent("TimerCallback", [this](u64 thread_id, s64 cycle_late) { - TimerCallback(thread_id, cycle_late); - }); + timer_callback_event_type = Core::System::GetInstance().CoreTiming().RegisterEvent( + "TimerCallback", + [this](u64 thread_id, s64 cycle_late) { TimerCallback(thread_id, cycle_late); }); } } // namespace Kernel diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h index e0eccaa33..3e446675c 100644 --- a/src/core/hle/kernel/timer.h +++ b/src/core/hle/kernel/timer.h @@ -20,7 +20,7 @@ private: void TimerCallback(u64 callback_id, s64 cycles_late); /// The event type of the generic timer callback event - CoreTiming::EventType* timer_callback_event_type = nullptr; + Core::TimingEventType* timer_callback_event_type = nullptr; u64 next_timer_callback_id = 0; std::unordered_map timer_callback_table; diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp index 21ae00f49..78d2e268e 100644 --- a/src/core/hle/service/cam/cam.cpp +++ b/src/core/hle/service/cam/cam.cpp @@ -151,7 +151,7 @@ void Module::StartReceiving(int port_id) { // schedules a completion event according to the frame rate. The event will block on the // capture task if it is not finished within the expected time - CoreTiming::ScheduleEvent( + system.CoreTiming().ScheduleEvent( msToCycles(LATENCY_BY_FRAME_RATE[static_cast(camera.frame_rate)]), completion_event_callback, port_id); } @@ -160,7 +160,7 @@ void Module::CancelReceiving(int port_id) { if (!ports[port_id].is_receiving) return; LOG_WARNING(Service_CAM, "tries to cancel an ongoing receiving process."); - CoreTiming::UnscheduleEvent(completion_event_callback, port_id); + system.CoreTiming().UnscheduleEvent(completion_event_callback, port_id); ports[port_id].capture_result.wait(); ports[port_id].is_receiving = false; } @@ -1019,7 +1019,7 @@ void Module::Interface::DriverFinalize(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_CAM, "called"); } -Module::Module(Core::System& system) { +Module::Module(Core::System& system) : system(system) { using namespace Kernel; for (PortConfig& port : ports) { port.completion_event = @@ -1029,7 +1029,7 @@ Module::Module(Core::System& system) { port.vsync_interrupt_event = system.Kernel().CreateEvent(ResetType::OneShot, "CAM::vsync_interrupt_event"); } - completion_event_callback = CoreTiming::RegisterEvent( + completion_event_callback = system.CoreTiming().RegisterEvent( "CAM::CompletionEventCallBack", [this](u64 userdata, s64 cycles_late) { CompletionEventCallBack(userdata, cycles_late); }); } diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h index 4f608fc8e..32b5bb0b4 100644 --- a/src/core/hle/service/cam/cam.h +++ b/src/core/hle/service/cam/cam.h @@ -21,8 +21,8 @@ namespace Camera { class CameraInterface; } -namespace CoreTiming { -struct EventType; +namespace Core { +struct TimingEventType; } namespace Kernel { @@ -779,9 +779,10 @@ private: void LoadCameraImplementation(CameraConfig& camera, int camera_id); + Core::System& system; std::array cameras; std::array ports; - CoreTiming::EventType* completion_event_callback; + Core::TimingEventType* completion_event_callback; std::atomic is_camera_reload_pending{false}; }; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 205d7860e..805cc6c91 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -128,7 +128,7 @@ void Module::UpdatePadCallback(u64 userdata, s64 cycles_late) { // If we just updated index 0, provide a new timestamp if (mem->pad.index == 0) { mem->pad.index_reset_ticks_previous = mem->pad.index_reset_ticks; - mem->pad.index_reset_ticks = (s64)CoreTiming::GetTicks(); + mem->pad.index_reset_ticks = (s64)system.CoreTiming().GetTicks(); } mem->touch.index = next_touch_index; @@ -152,7 +152,7 @@ void Module::UpdatePadCallback(u64 userdata, s64 cycles_late) { // If we just updated index 0, provide a new timestamp if (mem->touch.index == 0) { mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks; - mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks(); + mem->touch.index_reset_ticks = (s64)system.CoreTiming().GetTicks(); } // Signal both handles when there's an update to Pad or touch @@ -160,7 +160,7 @@ void Module::UpdatePadCallback(u64 userdata, s64 cycles_late) { event_pad_or_touch_2->Signal(); // Reschedule recurrent event - CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); + system.CoreTiming().ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); } void Module::UpdateAccelerometerCallback(u64 userdata, s64 cycles_late) { @@ -198,13 +198,14 @@ void Module::UpdateAccelerometerCallback(u64 userdata, s64 cycles_late) { // If we just updated index 0, provide a new timestamp if (mem->accelerometer.index == 0) { mem->accelerometer.index_reset_ticks_previous = mem->accelerometer.index_reset_ticks; - mem->accelerometer.index_reset_ticks = (s64)CoreTiming::GetTicks(); + mem->accelerometer.index_reset_ticks = (s64)system.CoreTiming().GetTicks(); } event_accelerometer->Signal(); // Reschedule recurrent event - CoreTiming::ScheduleEvent(accelerometer_update_ticks - cycles_late, accelerometer_update_event); + system.CoreTiming().ScheduleEvent(accelerometer_update_ticks - cycles_late, + accelerometer_update_event); } void Module::UpdateGyroscopeCallback(u64 userdata, s64 cycles_late) { @@ -233,13 +234,13 @@ void Module::UpdateGyroscopeCallback(u64 userdata, s64 cycles_late) { // If we just updated index 0, provide a new timestamp if (mem->gyroscope.index == 0) { mem->gyroscope.index_reset_ticks_previous = mem->gyroscope.index_reset_ticks; - mem->gyroscope.index_reset_ticks = (s64)CoreTiming::GetTicks(); + mem->gyroscope.index_reset_ticks = (s64)system.CoreTiming().GetTicks(); } event_gyroscope->Signal(); // Reschedule recurrent event - CoreTiming::ScheduleEvent(gyroscope_update_ticks - cycles_late, gyroscope_update_event); + system.CoreTiming().ScheduleEvent(gyroscope_update_ticks - cycles_late, gyroscope_update_event); } void Module::Interface::GetIPCHandles(Kernel::HLERequestContext& ctx) { @@ -257,7 +258,8 @@ void Module::Interface::EnableAccelerometer(Kernel::HLERequestContext& ctx) { // Schedules the accelerometer update event if the accelerometer was just enabled if (hid->enable_accelerometer_count == 1) { - CoreTiming::ScheduleEvent(accelerometer_update_ticks, hid->accelerometer_update_event); + hid->system.CoreTiming().ScheduleEvent(accelerometer_update_ticks, + hid->accelerometer_update_event); } IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); @@ -273,7 +275,7 @@ void Module::Interface::DisableAccelerometer(Kernel::HLERequestContext& ctx) { // Unschedules the accelerometer update event if the accelerometer was just disabled if (hid->enable_accelerometer_count == 0) { - CoreTiming::UnscheduleEvent(hid->accelerometer_update_event, 0); + hid->system.CoreTiming().UnscheduleEvent(hid->accelerometer_update_event, 0); } IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); @@ -289,7 +291,7 @@ void Module::Interface::EnableGyroscopeLow(Kernel::HLERequestContext& ctx) { // Schedules the gyroscope update event if the gyroscope was just enabled if (hid->enable_gyroscope_count == 1) { - CoreTiming::ScheduleEvent(gyroscope_update_ticks, hid->gyroscope_update_event); + hid->system.CoreTiming().ScheduleEvent(gyroscope_update_ticks, hid->gyroscope_update_event); } IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); @@ -305,7 +307,7 @@ void Module::Interface::DisableGyroscopeLow(Kernel::HLERequestContext& ctx) { // Unschedules the gyroscope update event if the gyroscope was just disabled if (hid->enable_gyroscope_count == 0) { - CoreTiming::UnscheduleEvent(hid->gyroscope_update_event, 0); + hid->system.CoreTiming().UnscheduleEvent(hid->gyroscope_update_event, 0); } IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); @@ -371,19 +373,21 @@ Module::Module(Core::System& system) : system(system) { event_debug_pad = system.Kernel().CreateEvent(ResetType::OneShot, "HID:EventDebugPad"); // Register update callbacks + Core::Timing& timing = system.CoreTiming(); pad_update_event = - CoreTiming::RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) { + timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) { UpdatePadCallback(userdata, cycles_late); }); - accelerometer_update_event = CoreTiming::RegisterEvent( + accelerometer_update_event = timing.RegisterEvent( "HID::UpdateAccelerometerCallback", [this](u64 userdata, s64 cycles_late) { UpdateAccelerometerCallback(userdata, cycles_late); }); - gyroscope_update_event = CoreTiming::RegisterEvent( - "HID::UpdateGyroscopeCallback", - [this](u64 userdata, s64 cycles_late) { UpdateGyroscopeCallback(userdata, cycles_late); }); + gyroscope_update_event = + timing.RegisterEvent("HID::UpdateGyroscopeCallback", [this](u64 userdata, s64 cycles_late) { + UpdateGyroscopeCallback(userdata, cycles_late); + }); - CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); + timing.ScheduleEvent(pad_update_ticks, pad_update_event); } void Module::ReloadInputDevices() { diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 45f94bb30..de0b6f0a9 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -27,8 +27,8 @@ class Event; class SharedMemory; } // namespace Kernel -namespace CoreTiming { -struct EventType; +namespace Core { +struct TimingEventType; }; namespace Service::HID { @@ -325,9 +325,9 @@ private: int enable_accelerometer_count = 0; // positive means enabled int enable_gyroscope_count = 0; // positive means enabled - CoreTiming::EventType* pad_update_event; - CoreTiming::EventType* accelerometer_update_event; - CoreTiming::EventType* gyroscope_update_event; + Core::TimingEventType* pad_update_event; + Core::TimingEventType* accelerometer_update_event; + Core::TimingEventType* gyroscope_update_event; std::atomic is_device_reload_pending{true}; std::array, Settings::NativeButton::NUM_BUTTONS_HID> diff --git a/src/core/hle/service/ir/extra_hid.cpp b/src/core/hle/service/ir/extra_hid.cpp index a53c9fbf7..31b63257e 100644 --- a/src/core/hle/service/ir/extra_hid.cpp +++ b/src/core/hle/service/ir/extra_hid.cpp @@ -4,6 +4,7 @@ #include "common/alignment.h" #include "common/string_util.h" +#include "core/core.h" #include "core/core_timing.h" #include "core/hle/service/ir/extra_hid.h" #include "core/movie.h" @@ -144,11 +145,11 @@ ExtraHID::ExtraHID(SendFunc send_func) : IRDevice(send_func) { 0x65, }}; - hid_polling_callback_id = - CoreTiming::RegisterEvent("ExtraHID::SendHIDStatus", [this](u64, s64 cycles_late) { + hid_polling_callback_id = Core::System::GetInstance().CoreTiming().RegisterEvent( + "ExtraHID::SendHIDStatus", [this](u64, s64 cycles_late) { SendHIDStatus(); - CoreTiming::ScheduleEvent(msToCycles(hid_period) - cycles_late, - hid_polling_callback_id); + Core::System::GetInstance().CoreTiming().ScheduleEvent( + msToCycles(hid_period) - cycles_late, hid_polling_callback_id); }); } @@ -159,7 +160,7 @@ ExtraHID::~ExtraHID() { void ExtraHID::OnConnect() {} void ExtraHID::OnDisconnect() { - CoreTiming::UnscheduleEvent(hid_polling_callback_id, 0); + Core::System::GetInstance().CoreTiming().UnscheduleEvent(hid_polling_callback_id, 0); } void ExtraHID::HandleConfigureHIDPollingRequest(const std::vector& request) { @@ -170,9 +171,10 @@ void ExtraHID::HandleConfigureHIDPollingRequest(const std::vector& request) } // Change HID input polling interval - CoreTiming::UnscheduleEvent(hid_polling_callback_id, 0); + Core::System::GetInstance().CoreTiming().UnscheduleEvent(hid_polling_callback_id, 0); hid_period = request[1]; - CoreTiming::ScheduleEvent(msToCycles(hid_period), hid_polling_callback_id); + Core::System::GetInstance().CoreTiming().ScheduleEvent(msToCycles(hid_period), + hid_polling_callback_id); } void ExtraHID::HandleReadCalibrationDataRequest(const std::vector& request_buf) { diff --git a/src/core/hle/service/ir/extra_hid.h b/src/core/hle/service/ir/extra_hid.h index dc4691d87..f9c2f050b 100644 --- a/src/core/hle/service/ir/extra_hid.h +++ b/src/core/hle/service/ir/extra_hid.h @@ -11,9 +11,9 @@ #include "core/frontend/input.h" #include "core/hle/service/ir/ir_user.h" -namespace CoreTiming { -struct EventType; -} // namespace CoreTiming +namespace Core { +struct TimingEventType; +} // namespace Core namespace Service::IR { @@ -57,7 +57,7 @@ private: void LoadInputDevices(); u8 hid_period; - CoreTiming::EventType* hid_polling_callback_id; + Core::TimingEventType* hid_polling_callback_id; std::array calibration_data; std::unique_ptr zl; std::unique_ptr zr; diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp index 147c91861..33e4fc0ff 100644 --- a/src/core/hle/service/ir/ir_rst.cpp +++ b/src/core/hle/service/ir/ir_rst.cpp @@ -100,13 +100,13 @@ void IR_RST::UpdateCallback(u64 userdata, s64 cycles_late) { // If we just updated index 0, provide a new timestamp if (mem->index == 0) { mem->index_reset_ticks_previous = mem->index_reset_ticks; - mem->index_reset_ticks = CoreTiming::GetTicks(); + mem->index_reset_ticks = system.CoreTiming().GetTicks(); } update_event->Signal(); // Reschedule recurrent event - CoreTiming::ScheduleEvent(msToCycles(update_period) - cycles_late, update_callback_id); + system.CoreTiming().ScheduleEvent(msToCycles(update_period) - cycles_late, update_callback_id); } void IR_RST::GetHandles(Kernel::HLERequestContext& ctx) { @@ -126,7 +126,7 @@ void IR_RST::Initialize(Kernel::HLERequestContext& ctx) { next_pad_index = 0; is_device_reload_pending.store(true); - CoreTiming::ScheduleEvent(msToCycles(update_period), update_callback_id); + system.CoreTiming().ScheduleEvent(msToCycles(update_period), update_callback_id); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); @@ -137,7 +137,7 @@ void IR_RST::Initialize(Kernel::HLERequestContext& ctx) { void IR_RST::Shutdown(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x03, 0, 0); - CoreTiming::UnscheduleEvent(update_callback_id, 0); + system.CoreTiming().UnscheduleEvent(update_callback_id, 0); UnloadInputDevices(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); @@ -145,7 +145,7 @@ void IR_RST::Shutdown(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_IR, "called"); } -IR_RST::IR_RST(Core::System& system) : ServiceFramework("ir:rst", 1) { +IR_RST::IR_RST(Core::System& system) : ServiceFramework("ir:rst", 1), system(system) { using namespace Kernel; // Note: these two kernel objects are even available before Initialize service function is // called. @@ -154,10 +154,9 @@ IR_RST::IR_RST(Core::System& system) : ServiceFramework("ir:rst", 1) { MemoryRegion::BASE, "IRRST:SharedMemory"); update_event = system.Kernel().CreateEvent(ResetType::OneShot, "IRRST:UpdateEvent"); - update_callback_id = - CoreTiming::RegisterEvent("IRRST:UpdateCallBack", [this](u64 userdata, s64 cycles_late) { - UpdateCallback(userdata, cycles_late); - }); + update_callback_id = system.CoreTiming().RegisterEvent( + "IRRST:UpdateCallBack", + [this](u64 userdata, s64 cycles_late) { UpdateCallback(userdata, cycles_late); }); static const FunctionInfo functions[] = { {0x00010000, &IR_RST::GetHandles, "GetHandles"}, diff --git a/src/core/hle/service/ir/ir_rst.h b/src/core/hle/service/ir/ir_rst.h index 821fb0b2f..e72adae7c 100644 --- a/src/core/hle/service/ir/ir_rst.h +++ b/src/core/hle/service/ir/ir_rst.h @@ -18,8 +18,8 @@ class Event; class SharedMemory; } // namespace Kernel -namespace CoreTiming { -struct EventType; +namespace Core { +struct TimingEventType; }; namespace Service::IR { @@ -77,10 +77,11 @@ private: void UnloadInputDevices(); void UpdateCallback(u64 userdata, s64 cycles_late); + Core::System& system; Kernel::SharedPtr update_event; Kernel::SharedPtr shared_memory; u32 next_pad_index{0}; - CoreTiming::EventType* update_callback_id; + Core::TimingEventType* update_callback_id; std::unique_ptr zl_button; std::unique_ptr zr_button; std::unique_ptr c_stick; diff --git a/src/core/hle/service/ir/ir_user.h b/src/core/hle/service/ir/ir_user.h index fea0794bc..71d5e1630 100644 --- a/src/core/hle/service/ir/ir_user.h +++ b/src/core/hle/service/ir/ir_user.h @@ -14,10 +14,6 @@ class Event; class SharedMemory; } // namespace Kernel -namespace CoreTiming { -struct EventType; -}; - namespace Service::IR { class BufferManager; diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp index 92d712263..85b309f43 100644 --- a/src/core/hle/service/nwm/nwm_uds.cpp +++ b/src/core/hle/service/nwm/nwm_uds.cpp @@ -88,7 +88,7 @@ struct Node { static std::map node_map; // Event that will generate and send the 802.11 beacon frames. -static CoreTiming::EventType* beacon_broadcast_event; +static Core::TimingEventType* beacon_broadcast_event; // Callback identifier for the OnWifiPacketReceived event. static Network::RoomMember::CallbackHandle wifi_packet_received; @@ -955,8 +955,8 @@ void NWM_UDS::BeginHostingNetwork(Kernel::HLERequestContext& ctx) { connection_status_event->Signal(); // Start broadcasting the network, send a beacon frame every 102.4ms. - CoreTiming::ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU), - beacon_broadcast_event, 0); + system.CoreTiming().ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU), + beacon_broadcast_event, 0); LOG_DEBUG(Service_NWM, "An UDS network has been created."); @@ -976,7 +976,7 @@ void NWM_UDS::DestroyNetwork(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x08, 0, 0); // Unschedule the beacon broadcast event. - CoreTiming::UnscheduleEvent(beacon_broadcast_event, 0); + system.CoreTiming().UnscheduleEvent(beacon_broadcast_event, 0); // Only a host can destroy std::lock_guard lock(connection_status_mutex); @@ -1336,7 +1336,7 @@ void NWM_UDS::DecryptBeaconData(Kernel::HLERequestContext& ctx) { } // Sends a 802.11 beacon frame with information about the current network. -static void BeaconBroadcastCallback(u64 userdata, s64 cycles_late) { +void NWM_UDS::BeaconBroadcastCallback(u64 userdata, s64 cycles_late) { // Don't do anything if we're not actually hosting a network if (connection_status.status != static_cast(NetworkStatus::ConnectedAsHost)) return; @@ -1353,8 +1353,9 @@ static void BeaconBroadcastCallback(u64 userdata, s64 cycles_late) { SendPacket(packet); // Start broadcasting the network, send a beacon frame every 102.4ms. - CoreTiming::ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU) - cycles_late, - beacon_broadcast_event, 0); + system.CoreTiming().ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU) - + cycles_late, + beacon_broadcast_event, 0); } NWM_UDS::NWM_UDS(Core::System& system) : ServiceFramework("nwm::UDS"), system(system) { @@ -1394,8 +1395,9 @@ NWM_UDS::NWM_UDS(Core::System& system) : ServiceFramework("nwm::UDS"), system(sy RegisterHandlers(functions); - beacon_broadcast_event = - CoreTiming::RegisterEvent("UDS::BeaconBroadcastCallback", BeaconBroadcastCallback); + beacon_broadcast_event = system.CoreTiming().RegisterEvent( + "UDS::BeaconBroadcastCallback", + [this](u64 userdata, s64 cycles_late) { BeaconBroadcastCallback(userdata, cycles_late); }); CryptoPP::AutoSeededRandomPool rng; auto mac = SharedPage::DefaultMac; @@ -1428,7 +1430,7 @@ NWM_UDS::~NWM_UDS() { if (auto room_member = Network::GetRoomMember().lock()) room_member->Unbind(wifi_packet_received); - CoreTiming::UnscheduleEvent(beacon_broadcast_event, 0); + system.CoreTiming().UnscheduleEvent(beacon_broadcast_event, 0); } } // namespace Service::NWM diff --git a/src/core/hle/service/nwm/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h index b6cac1ee0..3f050b5a5 100644 --- a/src/core/hle/service/nwm/nwm_uds.h +++ b/src/core/hle/service/nwm/nwm_uds.h @@ -352,6 +352,8 @@ private: * 2, 3: output buffer return descriptor & ptr */ void DecryptBeaconData(Kernel::HLERequestContext& ctx); + + void BeaconBroadcastCallback(u64 userdata, s64 cycles_late); }; } // namespace Service::NWM diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index d68068cbb..47bb852f8 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -31,7 +31,7 @@ Regs g_regs; /// 268MHz CPU clocks / 60Hz frames per second const u64 frame_ticks = static_cast(BASE_CLOCK_RATE_ARM11 / SCREEN_REFRESH_RATE); /// Event id for CoreTiming -static CoreTiming::EventType* vblank_event; +static Core::TimingEventType* vblank_event; template inline void Read(T& var, const u32 raw_addr) { @@ -522,7 +522,7 @@ static void VBlankCallback(u64 userdata, s64 cycles_late) { Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC1); // Reschedule recurrent event - CoreTiming::ScheduleEvent(frame_ticks - cycles_late, vblank_event); + Core::System::GetInstance().CoreTiming().ScheduleEvent(frame_ticks - cycles_late, vblank_event); } /// Initialize hardware @@ -555,8 +555,9 @@ void Init() { framebuffer_sub.color_format.Assign(Regs::PixelFormat::RGB8); framebuffer_sub.active_fb = 0; - vblank_event = CoreTiming::RegisterEvent("GPU::VBlankCallback", VBlankCallback); - CoreTiming::ScheduleEvent(frame_ticks, vblank_event); + Core::Timing& timing = Core::System::GetInstance().CoreTiming(); + vblank_event = timing.RegisterEvent("GPU::VBlankCallback", VBlankCallback); + timing.ScheduleEvent(frame_ticks, vblank_event); LOG_DEBUG(HW_GPU, "initialized OK"); } diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp index 1127a504f..58b60f506 100644 --- a/src/tests/core/arm/arm_test_common.cpp +++ b/src/tests/core/arm/arm_test_common.cpp @@ -16,10 +16,10 @@ static Memory::PageTable* page_table = nullptr; TestEnvironment::TestEnvironment(bool mutable_memory_) : mutable_memory(mutable_memory_), test_memory(std::make_shared(this)) { - CoreTiming::Init(); // HACK: some memory functions are currently referring kernel from the global instance, // so we need to create the kernel object there. // Change this when all global states are eliminated. + Core::System::GetInstance().timing = std::make_unique(); Core::System::GetInstance().kernel = std::make_unique(0); kernel = Core::System::GetInstance().kernel.get(); @@ -38,8 +38,6 @@ TestEnvironment::TestEnvironment(bool mutable_memory_) TestEnvironment::~TestEnvironment() { Memory::UnmapRegion(*page_table, 0x80000000, 0x80000000); Memory::UnmapRegion(*page_table, 0x00000000, 0x80000000); - - CoreTiming::Shutdown(); } void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) { diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp index 2242c14cf..1cfd9e971 100644 --- a/src/tests/core/core_timing.cpp +++ b/src/tests/core/core_timing.cpp @@ -28,100 +28,90 @@ void CallbackTemplate(u64 userdata, s64 cycles_late) { REQUIRE(lateness == cycles_late); } -class ScopeInit final { -public: - ScopeInit() { - CoreTiming::Init(); - } - ~ScopeInit() { - CoreTiming::Shutdown(); - } -}; - -static void AdvanceAndCheck(u32 idx, int downcount, int expected_lateness = 0, +static void AdvanceAndCheck(Core::Timing& timing, u32 idx, int downcount, int expected_lateness = 0, int cpu_downcount = 0) { callbacks_ran_flags = 0; expected_callback = CB_IDS[idx]; lateness = expected_lateness; - CoreTiming::AddTicks(CoreTiming::GetDowncount() - - cpu_downcount); // Pretend we executed X cycles of instructions. - CoreTiming::Advance(); + timing.AddTicks(timing.GetDowncount() - + cpu_downcount); // Pretend we executed X cycles of instructions. + timing.Advance(); REQUIRE(decltype(callbacks_ran_flags)().set(idx) == callbacks_ran_flags); - REQUIRE(downcount == CoreTiming::GetDowncount()); + REQUIRE(downcount == timing.GetDowncount()); } TEST_CASE("CoreTiming[BasicOrder]", "[core]") { - ScopeInit guard; + Core::Timing timing; - CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); - CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); - CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>); - CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>); - CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>); + Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>); + Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>); + Core::TimingEventType* cb_c = timing.RegisterEvent("callbackC", CallbackTemplate<2>); + Core::TimingEventType* cb_d = timing.RegisterEvent("callbackD", CallbackTemplate<3>); + Core::TimingEventType* cb_e = timing.RegisterEvent("callbackE", CallbackTemplate<4>); // Enter slice 0 - CoreTiming::Advance(); + timing.Advance(); // D -> B -> C -> A -> E - CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]); - REQUIRE(1000 == CoreTiming::GetDowncount()); - CoreTiming::ScheduleEvent(500, cb_b, CB_IDS[1]); - REQUIRE(500 == CoreTiming::GetDowncount()); - CoreTiming::ScheduleEvent(800, cb_c, CB_IDS[2]); - REQUIRE(500 == CoreTiming::GetDowncount()); - CoreTiming::ScheduleEvent(100, cb_d, CB_IDS[3]); - REQUIRE(100 == CoreTiming::GetDowncount()); - CoreTiming::ScheduleEvent(1200, cb_e, CB_IDS[4]); - REQUIRE(100 == CoreTiming::GetDowncount()); + timing.ScheduleEvent(1000, cb_a, CB_IDS[0]); + REQUIRE(1000 == timing.GetDowncount()); + timing.ScheduleEvent(500, cb_b, CB_IDS[1]); + REQUIRE(500 == timing.GetDowncount()); + timing.ScheduleEvent(800, cb_c, CB_IDS[2]); + REQUIRE(500 == timing.GetDowncount()); + timing.ScheduleEvent(100, cb_d, CB_IDS[3]); + REQUIRE(100 == timing.GetDowncount()); + timing.ScheduleEvent(1200, cb_e, CB_IDS[4]); + REQUIRE(100 == timing.GetDowncount()); - AdvanceAndCheck(3, 400); - AdvanceAndCheck(1, 300); - AdvanceAndCheck(2, 200); - AdvanceAndCheck(0, 200); - AdvanceAndCheck(4, MAX_SLICE_LENGTH); + AdvanceAndCheck(timing, 3, 400); + AdvanceAndCheck(timing, 1, 300); + AdvanceAndCheck(timing, 2, 200); + AdvanceAndCheck(timing, 0, 200); + AdvanceAndCheck(timing, 4, MAX_SLICE_LENGTH); } TEST_CASE("CoreTiming[Threadsave]", "[core]") { - ScopeInit guard; + Core::Timing timing; - CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); - CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); - CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>); - CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>); - CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>); + Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>); + Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>); + Core::TimingEventType* cb_c = timing.RegisterEvent("callbackC", CallbackTemplate<2>); + Core::TimingEventType* cb_d = timing.RegisterEvent("callbackD", CallbackTemplate<3>); + Core::TimingEventType* cb_e = timing.RegisterEvent("callbackE", CallbackTemplate<4>); // Enter slice 0 - CoreTiming::Advance(); + timing.Advance(); // D -> B -> C -> A -> E - CoreTiming::ScheduleEventThreadsafe(1000, cb_a, CB_IDS[0]); + timing.ScheduleEventThreadsafe(1000, cb_a, CB_IDS[0]); // Manually force since ScheduleEventThreadsafe doesn't call it - CoreTiming::ForceExceptionCheck(1000); - REQUIRE(1000 == CoreTiming::GetDowncount()); - CoreTiming::ScheduleEventThreadsafe(500, cb_b, CB_IDS[1]); + timing.ForceExceptionCheck(1000); + REQUIRE(1000 == timing.GetDowncount()); + timing.ScheduleEventThreadsafe(500, cb_b, CB_IDS[1]); // Manually force since ScheduleEventThreadsafe doesn't call it - CoreTiming::ForceExceptionCheck(500); - REQUIRE(500 == CoreTiming::GetDowncount()); - CoreTiming::ScheduleEventThreadsafe(800, cb_c, CB_IDS[2]); + timing.ForceExceptionCheck(500); + REQUIRE(500 == timing.GetDowncount()); + timing.ScheduleEventThreadsafe(800, cb_c, CB_IDS[2]); // Manually force since ScheduleEventThreadsafe doesn't call it - CoreTiming::ForceExceptionCheck(800); - REQUIRE(500 == CoreTiming::GetDowncount()); - CoreTiming::ScheduleEventThreadsafe(100, cb_d, CB_IDS[3]); + timing.ForceExceptionCheck(800); + REQUIRE(500 == timing.GetDowncount()); + timing.ScheduleEventThreadsafe(100, cb_d, CB_IDS[3]); // Manually force since ScheduleEventThreadsafe doesn't call it - CoreTiming::ForceExceptionCheck(100); - REQUIRE(100 == CoreTiming::GetDowncount()); - CoreTiming::ScheduleEventThreadsafe(1200, cb_e, CB_IDS[4]); + timing.ForceExceptionCheck(100); + REQUIRE(100 == timing.GetDowncount()); + timing.ScheduleEventThreadsafe(1200, cb_e, CB_IDS[4]); // Manually force since ScheduleEventThreadsafe doesn't call it - CoreTiming::ForceExceptionCheck(1200); - REQUIRE(100 == CoreTiming::GetDowncount()); + timing.ForceExceptionCheck(1200); + REQUIRE(100 == timing.GetDowncount()); - AdvanceAndCheck(3, 400); - AdvanceAndCheck(1, 300); - AdvanceAndCheck(2, 200); - AdvanceAndCheck(0, 200); - AdvanceAndCheck(4, MAX_SLICE_LENGTH); + AdvanceAndCheck(timing, 3, 400); + AdvanceAndCheck(timing, 1, 300); + AdvanceAndCheck(timing, 2, 200); + AdvanceAndCheck(timing, 0, 200); + AdvanceAndCheck(timing, 4, MAX_SLICE_LENGTH); } namespace SharedSlotTest { @@ -141,97 +131,98 @@ void FifoCallback(u64 userdata, s64 cycles_late) { TEST_CASE("CoreTiming[SharedSlot]", "[core]") { using namespace SharedSlotTest; - ScopeInit guard; + Core::Timing timing; - CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", FifoCallback<0>); - CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", FifoCallback<1>); - CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", FifoCallback<2>); - CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", FifoCallback<3>); - CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", FifoCallback<4>); + Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", FifoCallback<0>); + Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", FifoCallback<1>); + Core::TimingEventType* cb_c = timing.RegisterEvent("callbackC", FifoCallback<2>); + Core::TimingEventType* cb_d = timing.RegisterEvent("callbackD", FifoCallback<3>); + Core::TimingEventType* cb_e = timing.RegisterEvent("callbackE", FifoCallback<4>); - CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]); - CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]); - CoreTiming::ScheduleEvent(1000, cb_c, CB_IDS[2]); - CoreTiming::ScheduleEvent(1000, cb_d, CB_IDS[3]); - CoreTiming::ScheduleEvent(1000, cb_e, CB_IDS[4]); + timing.ScheduleEvent(1000, cb_a, CB_IDS[0]); + timing.ScheduleEvent(1000, cb_b, CB_IDS[1]); + timing.ScheduleEvent(1000, cb_c, CB_IDS[2]); + timing.ScheduleEvent(1000, cb_d, CB_IDS[3]); + timing.ScheduleEvent(1000, cb_e, CB_IDS[4]); // Enter slice 0 - CoreTiming::Advance(); - REQUIRE(1000 == CoreTiming::GetDowncount()); + timing.Advance(); + REQUIRE(1000 == timing.GetDowncount()); callbacks_ran_flags = 0; counter = 0; lateness = 0; - CoreTiming::AddTicks(CoreTiming::GetDowncount()); - CoreTiming::Advance(); - REQUIRE(MAX_SLICE_LENGTH == CoreTiming::GetDowncount()); + timing.AddTicks(timing.GetDowncount()); + timing.Advance(); + REQUIRE(MAX_SLICE_LENGTH == timing.GetDowncount()); REQUIRE(0x1FULL == callbacks_ran_flags.to_ullong()); } TEST_CASE("CoreTiming[PredictableLateness]", "[core]") { - ScopeInit guard; + Core::Timing timing; - CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); - CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); + Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>); + Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>); // Enter slice 0 - CoreTiming::Advance(); + timing.Advance(); - CoreTiming::ScheduleEvent(100, cb_a, CB_IDS[0]); - CoreTiming::ScheduleEvent(200, cb_b, CB_IDS[1]); + timing.ScheduleEvent(100, cb_a, CB_IDS[0]); + timing.ScheduleEvent(200, cb_b, CB_IDS[1]); - AdvanceAndCheck(0, 90, 10, -10); // (100 - 10) - AdvanceAndCheck(1, MAX_SLICE_LENGTH, 50, -50); + AdvanceAndCheck(timing, 0, 90, 10, -10); // (100 - 10) + AdvanceAndCheck(timing, 1, MAX_SLICE_LENGTH, 50, -50); } namespace ChainSchedulingTest { static int reschedules = 0; -static void RescheduleCallback(u64 userdata, s64 cycles_late) { +static void RescheduleCallback(Core::Timing& timing, u64 userdata, s64 cycles_late) { --reschedules; REQUIRE(reschedules >= 0); REQUIRE(lateness == cycles_late); if (reschedules > 0) - CoreTiming::ScheduleEvent(1000, reinterpret_cast(userdata), - userdata); + timing.ScheduleEvent(1000, reinterpret_cast(userdata), userdata); } } // namespace ChainSchedulingTest TEST_CASE("CoreTiming[ChainScheduling]", "[core]") { using namespace ChainSchedulingTest; - ScopeInit guard; + Core::Timing timing; - CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); - CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); - CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>); - CoreTiming::EventType* cb_rs = - CoreTiming::RegisterEvent("callbackReschedule", RescheduleCallback); + Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>); + Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>); + Core::TimingEventType* cb_c = timing.RegisterEvent("callbackC", CallbackTemplate<2>); + Core::TimingEventType* cb_rs = + timing.RegisterEvent("callbackReschedule", [&timing](u64 userdata, s64 cycles_late) { + RescheduleCallback(timing, userdata, cycles_late); + }); // Enter slice 0 - CoreTiming::Advance(); + timing.Advance(); - CoreTiming::ScheduleEvent(800, cb_a, CB_IDS[0]); - CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]); - CoreTiming::ScheduleEvent(2200, cb_c, CB_IDS[2]); - CoreTiming::ScheduleEvent(1000, cb_rs, reinterpret_cast(cb_rs)); - REQUIRE(800 == CoreTiming::GetDowncount()); + timing.ScheduleEvent(800, cb_a, CB_IDS[0]); + timing.ScheduleEvent(1000, cb_b, CB_IDS[1]); + timing.ScheduleEvent(2200, cb_c, CB_IDS[2]); + timing.ScheduleEvent(1000, cb_rs, reinterpret_cast(cb_rs)); + REQUIRE(800 == timing.GetDowncount()); reschedules = 3; - AdvanceAndCheck(0, 200); // cb_a - AdvanceAndCheck(1, 1000); // cb_b, cb_rs + AdvanceAndCheck(timing, 0, 200); // cb_a + AdvanceAndCheck(timing, 1, 1000); // cb_b, cb_rs REQUIRE(2 == reschedules); - CoreTiming::AddTicks(CoreTiming::GetDowncount()); - CoreTiming::Advance(); // cb_rs + timing.AddTicks(timing.GetDowncount()); + timing.Advance(); // cb_rs REQUIRE(1 == reschedules); - REQUIRE(200 == CoreTiming::GetDowncount()); + REQUIRE(200 == timing.GetDowncount()); - AdvanceAndCheck(2, 800); // cb_c + AdvanceAndCheck(timing, 2, 800); // cb_c - CoreTiming::AddTicks(CoreTiming::GetDowncount()); - CoreTiming::Advance(); // cb_rs + timing.AddTicks(timing.GetDowncount()); + timing.Advance(); // cb_rs REQUIRE(0 == reschedules); - REQUIRE(MAX_SLICE_LENGTH == CoreTiming::GetDowncount()); + REQUIRE(MAX_SLICE_LENGTH == timing.GetDowncount()); } diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp index 068d767b6..2e404a32d 100644 --- a/src/tests/core/hle/kernel/hle_ipc.cpp +++ b/src/tests/core/hle/kernel/hle_ipc.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include "core/core.h" #include "core/core_timing.h" #include "core/hle/ipc.h" #include "core/hle/kernel/client_port.h" @@ -20,7 +21,8 @@ static SharedPtr MakeObject(Kernel::KernelSystem& kernel) { } TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") { - CoreTiming::Init(); + // HACK: see comments of member timing + Core::System::GetInstance().timing = std::make_unique(); Kernel::KernelSystem kernel(0); auto session = std::get>(kernel.CreateSessionPair()); HLERequestContext context(std::move(session)); @@ -227,12 +229,11 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel REQUIRE(process->vm_manager.UnmapRange(target_address_mapped, buffer_mapped->size()) == RESULT_SUCCESS); } - - CoreTiming::Shutdown(); } TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { - CoreTiming::Init(); + // HACK: see comments of member timing + Core::System::GetInstance().timing = std::make_unique(); Kernel::KernelSystem kernel(0); auto session = std::get>(kernel.CreateSessionPair()); HLERequestContext context(std::move(session)); @@ -369,8 +370,6 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { REQUIRE(process->vm_manager.UnmapRange(target_address, output_buffer->size()) == RESULT_SUCCESS); } - - CoreTiming::Shutdown(); } } // namespace Kernel diff --git a/src/tests/core/memory/memory.cpp b/src/tests/core/memory/memory.cpp index 150ec8f66..196cd78ef 100644 --- a/src/tests/core/memory/memory.cpp +++ b/src/tests/core/memory/memory.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include "core/core.h" #include "core/core_timing.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/process.h" @@ -10,7 +11,8 @@ #include "core/memory.h" TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { - CoreTiming::Init(); + // HACK: see comments of member timing + Core::System::GetInstance().timing = std::make_unique(); Kernel::KernelSystem kernel(0); SECTION("these regions should not be mapped on an empty process") { auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); @@ -51,6 +53,4 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") { process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE); CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false); } - - CoreTiming::Shutdown(); } diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index f83d8d91f..b3c83ca78 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -146,7 +146,8 @@ void RendererOpenGL::SwapBuffers() { render_window.PollEvents(); render_window.SwapBuffers(); - Core::System::GetInstance().frame_limiter.DoFrameLimiting(CoreTiming::GetGlobalTimeUs()); + Core::System::GetInstance().frame_limiter.DoFrameLimiting( + Core::System::GetInstance().CoreTiming().GetGlobalTimeUs()); Core::System::GetInstance().perf_stats.BeginSystemFrame(); prev_state.Apply(); From 2067946f59766d2328820c699269429d5d2e1aee Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Tue, 6 Nov 2018 15:00:47 -0500 Subject: [PATCH 092/102] Kernel: reimplement memory management on physical FCRAM (#4392) * Kernel: reimplement memory management on physical FCRAM * Kernel/Process: Unmap does not care the source memory permission What game usually does is after mapping the memory, they reprotect the source memory as no permission to avoid modification there * Kernel/SharedMemory: zero initialize new-allocated memory * Process/Thread: zero new TLS entry * Kernel: fix a bug where code segments memory usage are accumulated twice It is added to both misc and heap (done inside HeapAlloc), which results a doubled number reported by svcGetProcessInfo. While we are on it, we just merge the three number misc, heap and linear heap usage together, as there is no where they are distinguished. Question: is TLS page also added to this number? * Kernel/SharedMemory: add more object info on mapping error * Process: lower log level; SharedMemory: store phys offset * VMManager: add helper function to retrieve backing block list for a range --- src/core/hle/applets/erreula.cpp | 4 +- src/core/hle/applets/mii_selector.cpp | 4 +- src/core/hle/applets/mint.cpp | 4 +- src/core/hle/applets/swkbd.cpp | 4 +- src/core/hle/kernel/errors.h | 4 + src/core/hle/kernel/kernel.h | 4 +- src/core/hle/kernel/memory.cpp | 79 ++++++++- src/core/hle/kernel/memory.h | 47 ++++- src/core/hle/kernel/process.cpp | 238 ++++++++++++++++---------- src/core/hle/kernel/process.h | 17 +- src/core/hle/kernel/shared_memory.cpp | 100 +++++------ src/core/hle/kernel/shared_memory.h | 11 +- src/core/hle/kernel/svc.cpp | 10 +- src/core/hle/kernel/thread.cpp | 21 +-- src/core/hle/kernel/vm_manager.cpp | 21 +++ src/core/hle/kernel/vm_manager.h | 4 + src/core/hle/service/apt/apt.cpp | 4 +- src/core/memory.cpp | 16 +- src/core/memory.h | 5 + 19 files changed, 389 insertions(+), 208 deletions(-) diff --git a/src/core/hle/applets/erreula.cpp b/src/core/hle/applets/erreula.cpp index 7b8cf1d02..ef9da4989 100644 --- a/src/core/hle/applets/erreula.cpp +++ b/src/core/hle/applets/erreula.cpp @@ -28,11 +28,9 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param // TODO: allocated memory never released using Kernel::MemoryPermission; - // Allocate a heap block of the required size for this applet. - heap_memory = std::make_shared>(capture_info.size); // Create a SharedMemory that directly points to this heap block. framebuffer_memory = Core::System::GetInstance().Kernel().CreateSharedMemoryForApplet( - heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, + 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "ErrEula Memory"); // Send the response message with the newly created SharedMemory diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp index dd57f0efd..f51b720a0 100644 --- a/src/core/hle/applets/mii_selector.cpp +++ b/src/core/hle/applets/mii_selector.cpp @@ -35,11 +35,9 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info)); using Kernel::MemoryPermission; - // Allocate a heap block of the required size for this applet. - heap_memory = std::make_shared>(capture_info.size); // Create a SharedMemory that directly points to this heap block. framebuffer_memory = Core::System::GetInstance().Kernel().CreateSharedMemoryForApplet( - heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, + 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "MiiSelector Memory"); // Send the response message with the newly created SharedMemory diff --git a/src/core/hle/applets/mint.cpp b/src/core/hle/applets/mint.cpp index ee70ba615..1986961bf 100644 --- a/src/core/hle/applets/mint.cpp +++ b/src/core/hle/applets/mint.cpp @@ -28,11 +28,9 @@ ResultCode Mint::ReceiveParameter(const Service::APT::MessageParameter& paramete // TODO: allocated memory never released using Kernel::MemoryPermission; - // Allocate a heap block of the required size for this applet. - heap_memory = std::make_shared>(capture_info.size); // Create a SharedMemory that directly points to this heap block. framebuffer_memory = Core::System::GetInstance().Kernel().CreateSharedMemoryForApplet( - heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, + 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "Mint Memory"); // Send the response message with the newly created SharedMemory diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp index cd8a9f57a..750a20849 100644 --- a/src/core/hle/applets/swkbd.cpp +++ b/src/core/hle/applets/swkbd.cpp @@ -39,11 +39,9 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info)); using Kernel::MemoryPermission; - // Allocate a heap block of the required size for this applet. - heap_memory = std::make_shared>(capture_info.size); // Create a SharedMemory that directly points to this heap block. framebuffer_memory = Core::System::GetInstance().Kernel().CreateSharedMemoryForApplet( - heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, + 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "SoftwareKeyboard Memory"); // Send the response message with the newly created SharedMemory diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index 509ffee58..2e9d63c30 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -67,6 +67,10 @@ constexpr ResultCode ERR_MISALIGNED_SIZE(ErrorDescription::MisalignedSize, Error constexpr ResultCode ERR_OUT_OF_MEMORY(ErrorDescription::OutOfMemory, ErrorModule::Kernel, ErrorSummary::OutOfResource, ErrorLevel::Permanent); // 0xD86007F3 +/// Returned when out of heap or linear heap memory when allocating +constexpr ResultCode ERR_OUT_OF_HEAP_MEMORY(ErrorDescription::OutOfMemory, ErrorModule::OS, + ErrorSummary::OutOfResource, + ErrorLevel::Status); // 0xC860180A constexpr ResultCode ERR_NOT_IMPLEMENTED(ErrorDescription::NotImplemented, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E01BF4 diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 2beaaa067..a6db1eb39 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -179,7 +179,6 @@ public: /** * Creates a shared memory object from a block of memory managed by an HLE applet. - * @param heap_block Heap block of the HLE applet. * @param offset The offset into the heap block that the SharedMemory will map. * @param size Size of the memory block. Must be page-aligned. * @param permissions Permission restrictions applied to the process which created the block. @@ -187,8 +186,7 @@ public: * block. * @param name Optional object name, used for debugging purposes. */ - SharedPtr CreateSharedMemoryForApplet(std::shared_ptr> heap_block, - u32 offset, u32 size, + SharedPtr CreateSharedMemoryForApplet(u32 offset, u32 size, MemoryPermission permissions, MemoryPermission other_permissions, std::string name = "Unknown Applet"); diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp index 3a2e9957a..b53c273fe 100644 --- a/src/core/hle/kernel/memory.cpp +++ b/src/core/hle/kernel/memory.cpp @@ -50,13 +50,7 @@ void KernelSystem::MemoryInit(u32 mem_type) { // the sizes specified in the memory_region_sizes table. VAddr base = 0; for (int i = 0; i < 3; ++i) { - memory_regions[i].base = base; - memory_regions[i].size = memory_region_sizes[mem_type][i]; - memory_regions[i].used = 0; - memory_regions[i].linear_heap_memory = std::make_shared>(); - // Reserve enough space for this region of FCRAM. - // We do not want this block of memory to be relocated when allocating from it. - memory_regions[i].linear_heap_memory->reserve(memory_regions[i].size); + memory_regions[i].Reset(base, memory_region_sizes[mem_type][i]); base += memory_regions[i].size; } @@ -164,4 +158,75 @@ void KernelSystem::MapSharedPages(VMManager& address_space) { address_space.Reprotect(shared_page_vma, VMAPermission::Read); } +void MemoryRegionInfo::Reset(u32 base, u32 size) { + this->base = base; + this->size = size; + used = 0; + free_blocks.clear(); + + // mark the entire region as free + free_blocks.insert(Interval::right_open(base, base + size)); +} + +MemoryRegionInfo::IntervalSet MemoryRegionInfo::HeapAllocate(u32 size) { + IntervalSet result; + u32 rest = size; + + // Try allocating from the higher address + for (auto iter = free_blocks.rbegin(); iter != free_blocks.rend(); ++iter) { + ASSERT(iter->bounds() == boost::icl::interval_bounds::right_open()); + if (iter->upper() - iter->lower() >= rest) { + // Requested size is fulfilled with this block + result += Interval(iter->upper() - rest, iter->upper()); + rest = 0; + break; + } + result += *iter; + rest -= iter->upper() - iter->lower(); + } + + if (rest != 0) { + // There is no enough free space + return {}; + } + + free_blocks -= result; + used += size; + return result; +} + +bool MemoryRegionInfo::LinearAllocate(u32 offset, u32 size) { + Interval interval(offset, offset + size); + if (!boost::icl::contains(free_blocks, interval)) { + // The requested range is already allocated + return false; + } + free_blocks -= interval; + used += size; + return true; +} + +std::optional MemoryRegionInfo::LinearAllocate(u32 size) { + // Find the first sufficient continuous block from the lower address + for (const auto& interval : free_blocks) { + ASSERT(interval.bounds() == boost::icl::interval_bounds::right_open()); + if (interval.upper() - interval.lower() >= size) { + Interval allocated(interval.lower(), interval.lower() + size); + free_blocks -= allocated; + used += size; + return allocated.lower(); + } + } + + // No sufficient block found + return {}; +} + +void MemoryRegionInfo::Free(u32 offset, u32 size) { + Interval interval(offset, offset + size); + ASSERT(!boost::icl::intersects(free_blocks, interval)); // must be allocated blocks + free_blocks += interval; + used -= size; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h index 14a38bdb9..67512df79 100644 --- a/src/core/hle/kernel/memory.h +++ b/src/core/hle/kernel/memory.h @@ -4,8 +4,8 @@ #pragma once -#include -#include +#include +#include #include "common/common_types.h" namespace Kernel { @@ -18,7 +18,48 @@ struct MemoryRegionInfo { u32 size; u32 used; - std::shared_ptr> linear_heap_memory; + // The domain of the interval_set are offsets from start of FCRAM + using IntervalSet = boost::icl::interval_set; + using Interval = IntervalSet::interval_type; + + IntervalSet free_blocks; + + /** + * Reset the allocator state + * @param base The base offset the beginning of FCRAM. + * @param size The region size this allocator manages + */ + void Reset(u32 base, u32 size); + + /** + * Allocates memory from the heap. + * @param size The size of memory to allocate. + * @returns The set of blocks that make up the allocation request. Empty set if there is no + * enough space. + */ + IntervalSet HeapAllocate(u32 size); + + /** + * Allocates memory from the linear heap with specific address and size. + * @param offset the address offset to the beginning of FCRAM. + * @param size size of the memory to allocate. + * @returns true if the allocation is successful. false if the requested region is not free. + */ + bool LinearAllocate(u32 offset, u32 size); + + /** + * Allocates memory from the linear heap with only size specified. + * @param size size of the memory to allocate. + * @returns the address offset to the beginning of FCRAM; null if there is no enough space + */ + std::optional LinearAllocate(u32 size); + + /** + * Frees one segment of memory. The memory must have been allocated as heap or linear heap. + * @param offset the region address offset to the beginning of FCRAM. + * @param size the size of the region to free. + */ + void Free(u32 offset, u32 size); }; void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping); diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index c41d4ebd9..5e699937b 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -119,13 +119,9 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) { - auto vma = vm_manager - .MapMemoryBlock(segment.addr, codeset->memory, segment.offset, segment.size, - memory_state) - .Unwrap(); - vm_manager.Reprotect(vma, permissions); - misc_memory_used += segment.size; - memory_region->used += segment.size; + HeapAllocate(segment.addr, segment.size, permissions, memory_state, true); + Memory::WriteBlock(*this, segment.addr, codeset->memory->data() + segment.offset, + segment.size); }; // Map CodeSet segments @@ -134,13 +130,8 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { MapSegment(codeset->DataSegment(), VMAPermission::ReadWrite, MemoryState::Private); // Allocate and map stack - vm_manager - .MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size, - std::make_shared>(stack_size, 0), 0, stack_size, - MemoryState::Locked) - .Unwrap(); - misc_memory_used += stack_size; - memory_region->used += stack_size; + HeapAllocate(Memory::HEAP_VADDR_END - stack_size, stack_size, VMAPermission::ReadWrite, + MemoryState::Locked, true); // Map special address mappings kernel.MapSharedPages(vm_manager); @@ -168,44 +159,55 @@ VAddr Process::GetLinearHeapLimit() const { return GetLinearHeapBase() + memory_region->size; } -ResultVal Process::HeapAllocate(VAddr target, u32 size, VMAPermission perms) { +ResultVal Process::HeapAllocate(VAddr target, u32 size, VMAPermission perms, + MemoryState memory_state, bool skip_range_check) { + LOG_DEBUG(Kernel, "Allocate heap target={:08X}, size={:08X}", target, size); if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || target + size < target) { - return ERR_INVALID_ADDRESS; + if (!skip_range_check) { + LOG_ERROR(Kernel, "Invalid heap address"); + return ERR_INVALID_ADDRESS; + } } - if (heap_memory == nullptr) { - // Initialize heap - heap_memory = std::make_shared>(); - heap_start = heap_end = target; + auto vma = vm_manager.FindVMA(target); + if (vma->second.type != VMAType::Free || vma->second.base + vma->second.size < target + size) { + LOG_ERROR(Kernel, "Trying to allocate already allocated memory"); + return ERR_INVALID_ADDRESS_STATE; } - // If necessary, expand backing vector to cover new heap extents. - if (target < heap_start) { - heap_memory->insert(begin(*heap_memory), heap_start - target, 0); - heap_start = target; - vm_manager.RefreshMemoryBlockMappings(heap_memory.get()); + auto allocated_fcram = memory_region->HeapAllocate(size); + if (allocated_fcram.empty()) { + LOG_ERROR(Kernel, "Not enough space"); + return ERR_OUT_OF_HEAP_MEMORY; } - if (target + size > heap_end) { - heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0); - heap_end = target + size; - vm_manager.RefreshMemoryBlockMappings(heap_memory.get()); + + // Maps heap block by block + VAddr interval_target = target; + for (const auto& interval : allocated_fcram) { + u32 interval_size = interval.upper() - interval.lower(); + LOG_DEBUG(Kernel, "Allocated FCRAM region lower={:08X}, upper={:08X}", interval.lower(), + interval.upper()); + std::fill(Memory::fcram.begin() + interval.lower(), + Memory::fcram.begin() + interval.upper(), 0); + auto vma = vm_manager.MapBackingMemory( + interval_target, Memory::fcram.data() + interval.lower(), interval_size, memory_state); + ASSERT(vma.Succeeded()); + vm_manager.Reprotect(vma.Unwrap(), perms); + interval_target += interval_size; } - ASSERT(heap_end - heap_start == heap_memory->size()); - CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start, - size, MemoryState::Private)); - vm_manager.Reprotect(vma, perms); + memory_used += size; + resource_limit->current_commit += size; - heap_used += size; - memory_region->used += size; - - return MakeResult(heap_end - size); + return MakeResult(target); } ResultCode Process::HeapFree(VAddr target, u32 size) { + LOG_DEBUG(Kernel, "Free heap target={:08X}, size={:08X}", target, size); if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || target + size < target) { + LOG_ERROR(Kernel, "Invalid heap address"); return ERR_INVALID_ADDRESS; } @@ -213,59 +215,72 @@ ResultCode Process::HeapFree(VAddr target, u32 size) { return RESULT_SUCCESS; } - ResultCode result = vm_manager.UnmapRange(target, size); - if (result.IsError()) - return result; + // Free heaps block by block + CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(target, size)); + for (const auto [backing_memory, block_size] : backing_blocks) { + memory_region->Free(Memory::GetFCRAMOffset(backing_memory), block_size); + } - heap_used -= size; - memory_region->used -= size; + ResultCode result = vm_manager.UnmapRange(target, size); + ASSERT(result.IsSuccess()); + + memory_used -= size; + resource_limit->current_commit -= size; return RESULT_SUCCESS; } ResultVal Process::LinearAllocate(VAddr target, u32 size, VMAPermission perms) { - auto& linheap_memory = memory_region->linear_heap_memory; - - VAddr heap_end = GetLinearHeapBase() + (u32)linheap_memory->size(); - // Games and homebrew only ever seem to pass 0 here (which lets the kernel decide the address), - // but explicit addresses are also accepted and respected. + LOG_DEBUG(Kernel, "Allocate linear heap target={:08X}, size={:08X}", target, size); + u32 physical_offset; if (target == 0) { - target = heap_end; + auto offset = memory_region->LinearAllocate(size); + if (!offset) { + LOG_ERROR(Kernel, "Not enough space"); + return ERR_OUT_OF_HEAP_MEMORY; + } + physical_offset = *offset; + target = physical_offset + GetLinearHeapAreaAddress(); + } else { + if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() || + target + size < target) { + LOG_ERROR(Kernel, "Invalid linear heap address"); + return ERR_INVALID_ADDRESS; + } + + // Kernel would crash/return error when target doesn't meet some requirement. + // It seems that target is required to follow immediately after the allocated linear heap, + // or cover the entire hole if there is any. + // Right now we just ignore these checks because they are still unclear. Further more, + // games and homebrew only ever seem to pass target = 0 here (which lets the kernel decide + // the address), so this not important. + + physical_offset = target - GetLinearHeapAreaAddress(); // relative to FCRAM + if (!memory_region->LinearAllocate(physical_offset, size)) { + LOG_ERROR(Kernel, "Trying to allocate already allocated memory"); + return ERR_INVALID_ADDRESS_STATE; + } } - if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() || target > heap_end || - target + size < target) { + u8* backing_memory = Memory::fcram.data() + physical_offset; - return ERR_INVALID_ADDRESS; - } + std::fill(backing_memory, backing_memory + size, 0); + auto vma = vm_manager.MapBackingMemory(target, backing_memory, size, MemoryState::Continuous); + ASSERT(vma.Succeeded()); + vm_manager.Reprotect(vma.Unwrap(), perms); - // Expansion of the linear heap is only allowed if you do an allocation immediately at its - // end. It's possible to free gaps in the middle of the heap and then reallocate them later, - // but expansions are only allowed at the end. - if (target == heap_end) { - linheap_memory->insert(linheap_memory->end(), size, 0); - vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); - } - - // TODO(yuriks): As is, this lets processes map memory allocated by other processes from the - // same region. It is unknown if or how the 3DS kernel checks against this. - std::size_t offset = target - GetLinearHeapBase(); - CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, linheap_memory, offset, size, - MemoryState::Continuous)); - vm_manager.Reprotect(vma, perms); - - linear_heap_used += size; - memory_region->used += size; + memory_used += size; + resource_limit->current_commit += size; + LOG_DEBUG(Kernel, "Allocated at target={:08X}", target); return MakeResult(target); } ResultCode Process::LinearFree(VAddr target, u32 size) { - auto& linheap_memory = memory_region->linear_heap_memory; - + LOG_DEBUG(Kernel, "Free linear heap target={:08X}, size={:08X}", target, size); if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() || target + size < target) { - + LOG_ERROR(Kernel, "Invalid linear heap address"); return ERR_INVALID_ADDRESS; } @@ -273,32 +288,75 @@ ResultCode Process::LinearFree(VAddr target, u32 size) { return RESULT_SUCCESS; } - VAddr heap_end = GetLinearHeapBase() + (u32)linheap_memory->size(); - if (target + size > heap_end) { + ResultCode result = vm_manager.UnmapRange(target, size); + if (result.IsError()) { + LOG_ERROR(Kernel, "Trying to free already freed memory"); + return result; + } + + memory_used -= size; + resource_limit->current_commit -= size; + + u32 physical_offset = target - GetLinearHeapAreaAddress(); // relative to FCRAM + memory_region->Free(physical_offset, size); + + return RESULT_SUCCESS; +} + +ResultCode Process::Map(VAddr target, VAddr source, u32 size, VMAPermission perms) { + LOG_DEBUG(Kernel, "Map memory target={:08X}, source={:08X}, size={:08X}, perms={:08X}", target, + source, size, static_cast(perms)); + if (source < Memory::HEAP_VADDR || source + size > Memory::HEAP_VADDR_END || + source + size < source) { + LOG_ERROR(Kernel, "Invalid source address"); + return ERR_INVALID_ADDRESS; + } + + // TODO(wwylele): check target address range. Is it also restricted to heap region? + + auto vma = vm_manager.FindVMA(target); + if (vma->second.type != VMAType::Free || vma->second.base + vma->second.size < target + size) { + LOG_ERROR(Kernel, "Trying to map to already allocated memory"); return ERR_INVALID_ADDRESS_STATE; } - ResultCode result = vm_manager.UnmapRange(target, size); - if (result.IsError()) - return result; + // Mark source region as Aliased + CASCADE_CODE(vm_manager.ChangeMemoryState(source, size, MemoryState::Private, + VMAPermission::ReadWrite, MemoryState::Aliased, + VMAPermission::ReadWrite)); - linear_heap_used -= size; - memory_region->used -= size; - - if (target + size == heap_end) { - // End of linear heap has been freed, so check what's the last allocated block in it and - // reduce the size. - auto vma = vm_manager.FindVMA(target); - ASSERT(vma != vm_manager.vma_map.end()); - ASSERT(vma->second.type == VMAType::Free); - VAddr new_end = vma->second.base; - if (new_end >= GetLinearHeapBase()) { - linheap_memory->resize(new_end - GetLinearHeapBase()); - } + CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(source, size)); + VAddr interval_target = target; + for (const auto [backing_memory, block_size] : backing_blocks) { + auto target_vma = vm_manager.MapBackingMemory(interval_target, backing_memory, block_size, + MemoryState::Alias); + interval_target += block_size; } return RESULT_SUCCESS; } +ResultCode Process::Unmap(VAddr target, VAddr source, u32 size, VMAPermission perms) { + LOG_DEBUG(Kernel, "Unmap memory target={:08X}, source={:08X}, size={:08X}, perms={:08X}", + target, source, size, static_cast(perms)); + if (source < Memory::HEAP_VADDR || source + size > Memory::HEAP_VADDR_END || + source + size < source) { + LOG_ERROR(Kernel, "Invalid source address"); + return ERR_INVALID_ADDRESS; + } + + // TODO(wwylele): check target address range. Is it also restricted to heap region? + + // TODO(wwylele): check that the source and the target are actually a pair created by Map + // Should return error 0xD8E007F5 in this case + + CASCADE_CODE(vm_manager.UnmapRange(target, size)); + + // Change back source region state. Note that the permission is reprotected according to param + CASCADE_CODE(vm_manager.ChangeMemoryState(source, size, MemoryState::Aliased, + VMAPermission::None, MemoryState::Private, perms)); + + return RESULT_SUCCESS; +} Kernel::Process::Process(KernelSystem& kernel) : Object(kernel), handle_table(kernel), kernel(kernel) {} diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index d1f529943..6924afe36 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -165,15 +165,7 @@ public: VMManager vm_manager; - // Memory used to back the allocations in the regular heap. A single vector is used to cover - // the entire virtual address space extents that bound the allocations, including any holes. - // This makes deallocation and reallocation of holes fast and keeps process memory contiguous - // in the emulator address space, allowing Memory::GetPointer to be reasonably safe. - std::shared_ptr> heap_memory; - // The left/right bounds of the address space covered by heap_memory. - VAddr heap_start = 0, heap_end = 0; - - u32 heap_used = 0, linear_heap_used = 0, misc_memory_used = 0; + u32 memory_used = 0; MemoryRegionInfo* memory_region = nullptr; @@ -188,12 +180,17 @@ public: VAddr GetLinearHeapBase() const; VAddr GetLinearHeapLimit() const; - ResultVal HeapAllocate(VAddr target, u32 size, VMAPermission perms); + ResultVal HeapAllocate(VAddr target, u32 size, VMAPermission perms, + MemoryState memory_state = MemoryState::Private, + bool skip_range_check = false); ResultCode HeapFree(VAddr target, u32 size); ResultVal LinearAllocate(VAddr target, u32 size, VMAPermission perms); ResultCode LinearFree(VAddr target, u32 size); + ResultCode Map(VAddr target, VAddr source, u32 size, VMAPermission perms); + ResultCode Unmap(VAddr target, VAddr source, u32 size, VMAPermission perms); + private: explicit Process(Kernel::KernelSystem& kernel); ~Process() override; diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 4f0b2e8ee..560d3f3ac 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -11,8 +11,13 @@ namespace Kernel { -SharedMemory::SharedMemory(KernelSystem& kernel) : Object(kernel) {} -SharedMemory::~SharedMemory() {} +SharedMemory::SharedMemory(KernelSystem& kernel) : Object(kernel), kernel(kernel) {} +SharedMemory::~SharedMemory() { + for (const auto& interval : holding_memory) { + kernel.GetMemoryRegion(MemoryRegion::SYSTEM) + ->Free(interval.lower(), interval.upper() - interval.lower()); + } +} SharedPtr KernelSystem::CreateSharedMemory(Process* owner_process, u32 size, MemoryPermission permissions, @@ -31,44 +36,26 @@ SharedPtr KernelSystem::CreateSharedMemory(Process* owner_process, // We need to allocate a block from the Linear Heap ourselves. // We'll manually allocate some memory from the linear heap in the specified region. MemoryRegionInfo* memory_region = GetMemoryRegion(region); - auto& linheap_memory = memory_region->linear_heap_memory; + auto offset = memory_region->LinearAllocate(size); - ASSERT_MSG(linheap_memory->size() + size <= memory_region->size, - "Not enough space in region to allocate shared memory!"); + ASSERT_MSG(offset, "Not enough space in region to allocate shared memory!"); - shared_memory->backing_block = linheap_memory; - shared_memory->backing_block_offset = linheap_memory->size(); - // Allocate some memory from the end of the linear heap for this region. - linheap_memory->insert(linheap_memory->end(), size, 0); - memory_region->used += size; - - shared_memory->linear_heap_phys_address = - Memory::FCRAM_PADDR + memory_region->base + - static_cast(shared_memory->backing_block_offset); + std::fill(Memory::fcram.data() + *offset, Memory::fcram.data() + *offset + size, 0); + shared_memory->backing_blocks = {{Memory::fcram.data() + *offset, size}}; + shared_memory->holding_memory += MemoryRegionInfo::Interval(*offset, *offset + size); + shared_memory->linear_heap_phys_offset = *offset; // Increase the amount of used linear heap memory for the owner process. if (shared_memory->owner_process != nullptr) { - shared_memory->owner_process->linear_heap_used += size; - } - - // Refresh the address mappings for the current process. - if (current_process != nullptr) { - current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); + shared_memory->owner_process->memory_used += size; } } else { auto& vm_manager = shared_memory->owner_process->vm_manager; // The memory is already available and mapped in the owner process. - auto vma = vm_manager.FindVMA(address); - ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address"); - ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address"); - // The returned VMA might be a bigger one encompassing the desired address. - auto vma_offset = address - vma->first; - ASSERT_MSG(vma_offset + size <= vma->second.size, - "Shared memory exceeds bounds of mapped block"); - - shared_memory->backing_block = vma->second.backing_block; - shared_memory->backing_block_offset = vma->second.offset + vma_offset; + auto backing_blocks = vm_manager.GetBackingBlocksForRange(address, size); + ASSERT_MSG(backing_blocks.Succeeded(), "Trying to share freed memory"); + shared_memory->backing_blocks = std::move(backing_blocks).Unwrap(); } shared_memory->base_address = address; @@ -76,17 +63,26 @@ SharedPtr KernelSystem::CreateSharedMemory(Process* owner_process, } SharedPtr KernelSystem::CreateSharedMemoryForApplet( - std::shared_ptr> heap_block, u32 offset, u32 size, MemoryPermission permissions, - MemoryPermission other_permissions, std::string name) { + u32 offset, u32 size, MemoryPermission permissions, MemoryPermission other_permissions, + std::string name) { SharedPtr shared_memory(new SharedMemory(*this)); + // Allocate memory in heap + MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::SYSTEM); + auto backing_blocks = memory_region->HeapAllocate(size); + ASSERT_MSG(!backing_blocks.empty(), "Not enough space in region to allocate shared memory!"); + shared_memory->holding_memory = backing_blocks; shared_memory->owner_process = nullptr; shared_memory->name = std::move(name); shared_memory->size = size; shared_memory->permissions = permissions; shared_memory->other_permissions = other_permissions; - shared_memory->backing_block = heap_block; - shared_memory->backing_block_offset = offset; + for (const auto& interval : backing_blocks) { + shared_memory->backing_blocks.push_back( + {Memory::fcram.data() + interval.lower(), interval.upper() - interval.lower()}); + std::fill(Memory::fcram.data() + interval.lower(), Memory::fcram.data() + interval.upper(), + 0); + } shared_memory->base_address = Memory::HEAP_VADDR + offset; return shared_memory; @@ -146,24 +142,29 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi if (base_address == 0 && target_address == 0) { // Calculate the address at which to map the memory block. - auto maybe_vaddr = Memory::PhysicalToVirtualAddress(linear_heap_phys_address); - ASSERT(maybe_vaddr); - target_address = *maybe_vaddr; + target_address = linear_heap_phys_offset + target_process->GetLinearHeapAreaAddress(); + } + + auto vma = target_process->vm_manager.FindVMA(target_address); + if (vma->second.type != VMAType::Free || + vma->second.base + vma->second.size < target_address + size) { + LOG_ERROR(Kernel, + "cannot map id={}, address=0x{:08X} name={}, mapping to already allocated memory", + GetObjectId(), address, name); + return ERR_INVALID_ADDRESS_STATE; } // Map the memory block into the target process - auto result = target_process->vm_manager.MapMemoryBlock( - target_address, backing_block, backing_block_offset, size, MemoryState::Shared); - if (result.Failed()) { - LOG_ERROR( - Kernel, - "cannot map id={}, target_address=0x{:08X} name={}, error mapping to virtual memory", - GetObjectId(), target_address, name); - return result.Code(); + VAddr interval_target = target_address; + for (const auto& interval : backing_blocks) { + auto vma = target_process->vm_manager.MapBackingMemory( + interval_target, interval.first, interval.second, MemoryState::Shared); + ASSERT(vma.Succeeded()); + target_process->vm_manager.Reprotect(vma.Unwrap(), ConvertPermissions(permissions)); + interval_target += interval.second; } - return target_process->vm_manager.ReprotectRange(target_address, size, - ConvertPermissions(permissions)); + return RESULT_SUCCESS; } ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { @@ -179,7 +180,10 @@ VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { }; u8* SharedMemory::GetPointer(u32 offset) { - return backing_block->data() + backing_block_offset + offset; + if (backing_blocks.size() != 1) { + LOG_WARNING(Kernel, "Unsafe GetPointer on discontinuous SharedMemory"); + } + return backing_blocks[0].first + offset; } } // namespace Kernel diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 18a87b9fe..a48f607ba 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -61,13 +61,11 @@ public: Process* owner_process; /// Address of shared memory block in the owner process if specified. VAddr base_address; - /// Physical address of the shared memory block in the linear heap if no address was specified + /// Offset in FCRAM of the shared memory block in the linear heap if no address was specified /// during creation. - PAddr linear_heap_phys_address; + PAddr linear_heap_phys_offset; /// Backing memory for this shared memory block. - std::shared_ptr> backing_block; - /// Offset into the backing block for this shared memory. - std::size_t backing_block_offset; + std::vector> backing_blocks; /// Size of the memory block. Page-aligned. u32 size; /// Permission restrictions applied to the process which created the block. @@ -77,11 +75,14 @@ public: /// Name of shared memory object. std::string name; + MemoryRegionInfo::IntervalSet holding_memory; + private: explicit SharedMemory(KernelSystem& kernel); ~SharedMemory() override; friend class KernelSystem; + KernelSystem& kernel; }; } // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index f23b569d7..1594c2ade 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -114,16 +114,12 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add } case MEMOP_MAP: { - // TODO: This is just a hack to avoid regressions until memory aliasing is implemented - CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions)); + CASCADE_CODE(process.Map(addr0, addr1, size, vma_permissions)); break; } case MEMOP_UNMAP: { - // TODO: This is just a hack to avoid regressions until memory aliasing is implemented - ResultCode result = process.HeapFree(addr0, size); - if (result.IsError()) - return result; + CASCADE_CODE(process.Unmap(addr0, addr1, size, vma_permissions)); break; } @@ -1289,7 +1285,7 @@ static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) { case 2: // TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure // what's the difference between them. - *out = process->heap_used + process->linear_heap_used + process->misc_memory_used; + *out = process->memory_used; if (*out % Memory::PAGE_SIZE != 0) { LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned"); return ERR_MISALIGNED_SIZE; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 236e1d7b0..c0a2ccee9 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -333,32 +333,27 @@ ResultVal> KernelSystem::CreateThread(std::string name, VAddr // There are no already-allocated pages with free slots, lets allocate a new one. // TLS pages are allocated from the BASE region in the linear heap. MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::BASE); - auto& linheap_memory = memory_region->linear_heap_memory; - if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) { + // Allocate some memory from the end of the linear heap for this region. + auto offset = memory_region->LinearAllocate(Memory::PAGE_SIZE); + if (!offset) { LOG_ERROR(Kernel_SVC, "Not enough space in region to allocate a new TLS page for thread"); return ERR_OUT_OF_MEMORY; } - - std::size_t offset = linheap_memory->size(); - - // Allocate some memory from the end of the linear heap for this region. - linheap_memory->insert(linheap_memory->end(), Memory::PAGE_SIZE, 0); - memory_region->used += Memory::PAGE_SIZE; - owner_process.linear_heap_used += Memory::PAGE_SIZE; + owner_process.memory_used += Memory::PAGE_SIZE; tls_slots.emplace_back(0); // The page is completely available at the start available_page = tls_slots.size() - 1; available_slot = 0; // Use the first slot in the new page auto& vm_manager = owner_process.vm_manager; - vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); // Map the page to the current process' address space. // TODO(Subv): Find the correct MemoryState for this region. - vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE, - linheap_memory, offset, Memory::PAGE_SIZE, MemoryState::Private); + vm_manager.MapBackingMemory(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE, + Memory::fcram.data() + *offset, Memory::PAGE_SIZE, + MemoryState::Private); } // Mark the slot as used @@ -366,6 +361,8 @@ ResultVal> KernelSystem::CreateThread(std::string name, VAddr thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE; + Memory::ZeroBlock(owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE); + // 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); diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 36e24682b..bab8891bc 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -408,4 +408,25 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { break; } } + +ResultVal>> VMManager::GetBackingBlocksForRange(VAddr address, + u32 size) { + std::vector> backing_blocks; + VAddr interval_target = address; + while (interval_target != address + size) { + auto vma = FindVMA(interval_target); + if (vma->second.type != VMAType::BackingMemory) { + LOG_ERROR(Kernel, "Trying to use already freed memory"); + return ERR_INVALID_ADDRESS_STATE; + } + + VAddr interval_end = std::min(address + size, vma->second.base + vma->second.size); + u32 interval_size = interval_end - interval_target; + u8* backing_memory = vma->second.backing_memory + (interval_target - vma->second.base); + backing_blocks.push_back({backing_memory, interval_size}); + + interval_target += interval_size; + } + return MakeResult(backing_blocks); +} } // namespace Kernel diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 7ac5c3b01..5464ad50b 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -6,6 +6,7 @@ #include #include +#include #include #include "common/common_types.h" #include "core/hle/result.h" @@ -213,6 +214,9 @@ public: /// Dumps the address space layout to the log, for debugging void LogLayout(Log::Level log_level) const; + /// Gets a list of backing memory blocks for the specified range + ResultVal>> GetBackingBlocksForRange(VAddr address, u32 size); + /// Each VMManager has its own page table, which is set as the main one when the owning process /// is scheduled. Memory::PageTable page_table; diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 13c278158..741a288e8 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -207,8 +207,8 @@ void Module::Interface::GetSharedFont(Kernel::HLERequestContext& ctx) { // The shared font has to be relocated to the new address before being passed to the // application. - auto maybe_vaddr = - Memory::PhysicalToVirtualAddress(apt->shared_font_mem->linear_heap_phys_address); + auto maybe_vaddr = Memory::PhysicalToVirtualAddress( + apt->shared_font_mem->linear_heap_phys_offset + Memory::FCRAM_PADDR); ASSERT(maybe_vaddr); VAddr target_address = *maybe_vaddr; if (!apt->shared_font_relocated) { diff --git a/src/core/memory.cpp b/src/core/memory.cpp index eed279c9a..697345ea7 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -23,6 +23,7 @@ namespace Memory { static std::array vram; static std::array n3ds_extra_ram; +std::array fcram; static PageTable* current_page_table = nullptr; @@ -305,15 +306,7 @@ u8* GetPhysicalPointer(PAddr address) { target_pointer = Core::DSP().GetDspMemory().data() + offset_into_region; break; case FCRAM_PADDR: - for (const auto& region : Core::System::GetInstance().Kernel().memory_regions) { - if (offset_into_region >= region.base && - offset_into_region < region.base + region.size) { - target_pointer = - region.linear_heap_memory->data() + offset_into_region - region.base; - break; - } - } - ASSERT_MSG(target_pointer != nullptr, "Invalid FCRAM address"); + target_pointer = fcram.data() + offset_into_region; break; case N3DS_EXTRA_RAM_PADDR: target_pointer = n3ds_extra_ram.data() + offset_into_region; @@ -846,4 +839,9 @@ std::optional PhysicalToVirtualAddress(const PAddr addr) { return {}; } +u32 GetFCRAMOffset(u8* pointer) { + ASSERT(pointer >= fcram.data() && pointer < fcram.data() + fcram.size()); + return pointer - fcram.data(); +} + } // namespace Memory diff --git a/src/core/memory.h b/src/core/memory.h index f457ec934..bad47375a 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -176,6 +176,8 @@ enum : VAddr { NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE, }; +extern std::array fcram; + /// Currently active page table void SetCurrentPageTable(PageTable* page_table); PageTable* GetCurrentPageTable(); @@ -271,4 +273,7 @@ enum class FlushMode { */ void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode); +/// Gets offset in FCRAM from a pointer inside FCRAM range +u32 GetFCRAMOffset(u8* pointer); + } // namespace Memory From 0f4a6e39c9fc33fde4b3422a7023ac8ea192d1ba Mon Sep 17 00:00:00 2001 From: Valentin Vanelslande Date: Wed, 7 Nov 2018 13:38:52 -0500 Subject: [PATCH 093/102] ldr_ro: change std::tie to structured binding --- src/core/hle/service/ldr_ro/ldr_ro.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/hle/service/ldr_ro/ldr_ro.cpp b/src/core/hle/service/ldr_ro/ldr_ro.cpp index ceae8be20..2313bb188 100644 --- a/src/core/hle/service/ldr_ro/ldr_ro.cpp +++ b/src/core/hle/service/ldr_ro/ldr_ro.cpp @@ -353,9 +353,7 @@ void RO::LoadCRO(Kernel::HLERequestContext& ctx, bool link_on_load_bug_fix) { slot->memory_synchronizer.ResizeMemoryBlock(cro_address, cro_buffer_ptr, fix_size); } - VAddr exe_begin; - u32 exe_size; - std::tie(exe_begin, exe_size) = cro.GetExecutablePages(); + auto [exe_begin, exe_size] = cro.GetExecutablePages(); if (exe_begin) { result = process->vm_manager.ReprotectRange(exe_begin, exe_size, Kernel::VMAPermission::ReadExecute); From 81cbc3fa15e98daf50769bd343f75b8edbd71f08 Mon Sep 17 00:00:00 2001 From: Brendan Szymanski Date: Wed, 7 Nov 2018 21:33:36 -0500 Subject: [PATCH 094/102] Flatpak support (#4383) * Initial flatpak support * Fix compatibility list directory * Hard-code SSH mount location * Add workaround documentation * Change SSH repo directory * Change SSH repo directory (again) * Fix variable name * Remove temporary testing branch placeholder * Use a flatpak-specific docker image * Enable network access during the flatpak build so we can download compatibility list the right way * Fix flatpak tag support * Fix typo * Use cloned git for the build * Change SSH repo location * Disable shallow git cloning, needed for tagged building --- .gitignore | 4 + .travis.yml | 12 ++ .travis/linux-flatpak/build.sh | 4 + .travis/linux-flatpak/deps.sh | 4 + .travis/linux-flatpak/docker.sh | 35 +++++ .travis/linux-flatpak/finish.sh | 9 ++ .travis/linux-flatpak/generate-data.sh | 142 ++++++++++++++++++++ .travis/linux-flatpak/travis-ci-flatpak.env | 9 ++ keys.tar.enc | Bin 0 -> 10256 bytes 9 files changed, 219 insertions(+) create mode 100755 .travis/linux-flatpak/build.sh create mode 100755 .travis/linux-flatpak/deps.sh create mode 100755 .travis/linux-flatpak/docker.sh create mode 100755 .travis/linux-flatpak/finish.sh create mode 100644 .travis/linux-flatpak/generate-data.sh create mode 100644 .travis/linux-flatpak/travis-ci-flatpak.env create mode 100644 keys.tar.enc diff --git a/.gitignore b/.gitignore index 9e11b5d75..37591363a 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,7 @@ Thumbs.db # Python files *.pyc + +# Flatpak generated files +.flatpak-builder/ +repo/ diff --git a/.travis.yml b/.travis.yml index 54b7a9091..402c9538e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,6 +61,18 @@ matrix: script: "./.travis/linux-mingw/build.sh" after_success: "./.travis/linux-mingw/upload.sh" cache: ccache + - if: repo =~ ^.*\/(citra-canary|citra-nightly)$ AND tag IS present + git: + depth: false + os: linux + env: NAME="flatpak build" + sudo: required + dist: trusty + services: docker + cache: ccache + install: "./.travis/linux-flatpak/deps.sh" + script: "./.travis/linux-flatpak/build.sh" + after_script: "./.travis/linux-flatpak/finish.sh" deploy: provider: releases diff --git a/.travis/linux-flatpak/build.sh b/.travis/linux-flatpak/build.sh new file mode 100755 index 000000000..91fba01aa --- /dev/null +++ b/.travis/linux-flatpak/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash -ex +mkdir -p "$HOME/.ccache" +# Configure docker and call the script that generates application data and build scripts +docker run --env-file .travis/common/travis-ci.env --env-file .travis/linux-flatpak/travis-ci-flatpak.env -v $(pwd):/citra -v "$HOME/.ccache":/root/.ccache -v "$HOME/.ssh":/root/.ssh --privileged citraemu/build-environments:linux-flatpak /bin/bash -ex /citra/.travis/linux-flatpak/generate-data.sh diff --git a/.travis/linux-flatpak/deps.sh b/.travis/linux-flatpak/deps.sh new file mode 100755 index 000000000..b8fd4974c --- /dev/null +++ b/.travis/linux-flatpak/deps.sh @@ -0,0 +1,4 @@ +#!/bin/sh -ex + +# Download the docker image that contains flatpak build dependencies +docker pull citraemu/build-environments:linux-flatpak diff --git a/.travis/linux-flatpak/docker.sh b/.travis/linux-flatpak/docker.sh new file mode 100755 index 000000000..31e2bb777 --- /dev/null +++ b/.travis/linux-flatpak/docker.sh @@ -0,0 +1,35 @@ +#!/bin/bash -ex + +# Converts "citra-emu/citra-nightly" to "citra-nightly" +REPO_NAME=$(echo $TRAVIS_REPO_SLUG | cut -d'/' -f 2) +CITRA_SRC_DIR="/citra" +BUILD_DIR="$CITRA_SRC_DIR/build" +REPO_DIR="$CITRA_SRC_DIR/repo" +STATE_DIR="$CITRA_SRC_DIR/.flatpak-builder" +KEYS_ARCHIVE="/tmp/keys.tar" +SSH_DIR="/upload" +SSH_KEY="/tmp/ssh.key" +GPG_KEY="/tmp/gpg.key" + +# Extract keys +openssl aes-256-cbc -K $FLATPAK_ENC_K -iv $FLATPAK_ENC_IV -in "$CITRA_SRC_DIR/keys.tar.enc" -out "$KEYS_ARCHIVE" -d +tar -C /tmp -xvf $KEYS_ARCHIVE + +# Configure SSH keys +eval "$(ssh-agent -s)" +chmod -R 600 "$HOME/.ssh" +chown -R root "$HOME/.ssh" +chmod 600 "$SSH_KEY" +ssh-add "$SSH_KEY" +echo "[$FLATPAK_SSH_HOSTNAME]:$FLATPAK_SSH_PORT,[$(dig +short $FLATPAK_SSH_HOSTNAME)]:$FLATPAK_SSH_PORT $FLATPAK_SSH_PUBLIC_KEY" > ~/.ssh/known_hosts + +# Configure GPG keys +gpg2 --import "$GPG_KEY" + +# Mount our flatpak repository +mkdir -p "$REPO_DIR" +sshfs "$FLATPAK_SSH_USER@$FLATPAK_SSH_HOSTNAME:$SSH_DIR" "$REPO_DIR" -C -p "$FLATPAK_SSH_PORT" -o IdentityFile="$SSH_KEY" + +# Build the citra flatpak +flatpak-builder -v --jobs=4 --ccache --force-clean --state-dir="$STATE_DIR" --gpg-sign="$FLATPAK_GPG_PUBLIC_KEY" --repo="$REPO_DIR" "$BUILD_DIR" "/tmp/org.citra.$REPO_NAME.json" +flatpak build-update-repo "$REPO_DIR" -v --generate-static-deltas --gpg-sign="$FLATPAK_GPG_PUBLIC_KEY" diff --git a/.travis/linux-flatpak/finish.sh b/.travis/linux-flatpak/finish.sh new file mode 100755 index 000000000..c9f0c0731 --- /dev/null +++ b/.travis/linux-flatpak/finish.sh @@ -0,0 +1,9 @@ +#!/bin/bash -ex + +CITRA_SRC_DIR="/citra" +REPO_DIR="$CITRA_SRC_DIR/repo" + +# When the script finishes, unmount the repository and delete sensitive files, +# regardless of whether the build passes or fails +umount "$REPO_DIR" +rm -rf "$REPO_DIR" "/tmp/*" diff --git a/.travis/linux-flatpak/generate-data.sh b/.travis/linux-flatpak/generate-data.sh new file mode 100644 index 000000000..d8ca90aab --- /dev/null +++ b/.travis/linux-flatpak/generate-data.sh @@ -0,0 +1,142 @@ +#!/bin/bash -ex +# This script generates the appdata.xml and org.citra.$REPO_NAME.json files +# needed to define application metadata and build citra depending on what version +# of citra we're building (nightly or canary) + +# Converts "citra-emu/citra-nightly" to "citra-nightly" +REPO_NAME=$(echo $TRAVIS_REPO_SLUG | cut -d'/' -f 2) +# Converts "citra-nightly" to "Citra Nightly" +REPO_NAME_FRIENDLY=$(echo $REPO_NAME | sed -e 's/-/ /g' -e 's/\b\(.\)/\u\1/g') + +# Generate the correct appdata.xml for the version of Citra we're building +cat > /tmp/appdata.xml < + + org.citra.$REPO_NAME.desktop + $REPO_NAME_FRIENDLY + Nintendo 3DS emulator + CC0-1.0 + GPL-2.0 + +

Citra is an experimental open-source Nintendo 3DS emulator/debugger written in C++. It is written with portability in mind, with builds actively maintained for Windows, Linux and macOS.

+

Citra emulates a subset of 3DS hardware and therefore is useful for running/debugging homebrew applications, and it is also able to run many commercial games! Some of these do not run at a playable state, but we are working every day to advance the project forward. (Playable here means compatibility of at least "Okay" on our game compatibility list.)

+
+ https://citra-emu.org/ + https://citra-emu.org/donate/ + https://github.com/citra-emu/citra/issues + https://citra-emu.org/wiki/faq/ + https://citra-emu.org/wiki/home/ + https://raw.githubusercontent.com/citra-emu/citra-web/master/site/static/images/screenshots/01-Super%20Mario%203D%20Land.jpg + https://raw.githubusercontent.com/citra-emu/citra-web/master/site/static/images/screenshots/02-Mario%20Kart%207.jpg + https://raw.githubusercontent.com/citra-emu/citra-web/master/site/static/images/screenshots/28-The%20Legend%20of%20Zelda%20Ocarina%20of%20Time%203D.jpg + https://raw.githubusercontent.com/citra-emu/citra-web/master/site/static/images/screenshots/35-Pok%C3%A9mon%20ORAS.png + + Games + Emulator + +
+EOF + +# Generate the citra flatpak manifest, appending certain variables depending on +# whether we're building nightly or canary. +cat > /tmp/org.citra.$REPO_NAME.json <> /app/share/applications/citra.desktop", + "install -Dm644 ../dist/citra.svg /app/share/icons/hicolor/scalable/apps/citra.svg", + "install -Dm644 ../dist/icon.png /app/share/icons/hicolor/512x512/apps/citra.png", + "mv /app/share/mime/packages/citra.xml /app/share/mime/packages/org.citra.$REPO_NAME.xml", + "sed 's/citra/org.citra.citra-nightly/g' -i /app/share/mime/packages/org.citra.$REPO_NAME.xml", + "install -m644 --target-directory=/app/lib /usr/lib/sdk/gcc7/lib/libstdc++.so*" + ], + "sources": [ + { + "type": "git", + "url": "https://github.com/citra-emu/$REPO_NAME.git", + "branch": "$TRAVIS_BRANCH", + "disable-shallow-clone": true + }, + { + "type": "file", + "path": "/tmp/appdata.xml" + } + ] + } + ] +} +EOF + +# Call the script to build citra +/bin/bash -ex /citra/.travis/linux-flatpak/docker.sh diff --git a/.travis/linux-flatpak/travis-ci-flatpak.env b/.travis/linux-flatpak/travis-ci-flatpak.env new file mode 100644 index 000000000..0823d91c8 --- /dev/null +++ b/.travis/linux-flatpak/travis-ci-flatpak.env @@ -0,0 +1,9 @@ +# Flatpak specific environment variables +FLATPAK_ENC_IV +FLATPAK_ENC_K +FLATPAK_GPG_PUBLIC_KEY +FLATPAK_SSH_HOSTNAME +FLATPAK_SSH_LOCATION +FLATPAK_SSH_PORT +FLATPAK_SSH_PUBLIC_KEY +FLATPAK_SSH_USER diff --git a/keys.tar.enc b/keys.tar.enc new file mode 100644 index 0000000000000000000000000000000000000000..6a8c1484e5720cc05baa3892d97c41e940587b09 GIT binary patch literal 10256 zcmV+rDDT&40_hZ%{4P{{c3Cm7M>#@tvSR1D(my-gzq2HPBRH z4MGfg3*SjitnJSdWGw>T-0#^c(j+J%K#}7U1n^xiw@~8$8$KOV(B*+*2#aAOaQ3&% z*#>hIP%BD{teu?y6Zfw?htmlmDyRBg>SQm2zbZY8?ex&d{9l6gT2Y;Rz2M<^1sL1s zrte#HIX{~Jjsqs@WKSEYlGvc@dZCV%$P)SH-#K3u-a_z{Evx!;=X#j8H|6T{5+?FX zm(&r~_^NiK^#p(B0^-hv;fI*(<0bq~`g7L@;*w=jk5eB#A8Yw4sKmAzEsJ3?ge;h| zd-Vzh4JreEhc@~**pcswWQO4n;1gCtRGLw`Z<$Hq@T@HETj(E=gFb|4yVD`%!2_EW zQUX+ZfpehUWaUeSuy5^!)V;-N)`!QJrkJN>v_H& z2r}F16PRgp07up;1C(D3AD|F58^vlS`6mVCJ zj-|b0F#})1nJ7()e#)%lnXufEXd0Q8a3AUk=%VEN3~iSL&C&1sv07B-!wF`;{YcW)>lXU!_ZG1ac2*Hm<7 z{732L{3I|pxo3r5linzjjyTtcNPjJ!o~a2dsJ4p5Rn1DT?}K0l%dUfjPZkZ4e2RG# z8%^r)?L~Y%tzsk0q~2Cm$n8Z9L3ZS-PN9X12PasF_w>Jg0;w^o{KdT>#mrq-dfv#( zCSdm!istyJs%pm+2FoKK@3t>F)N&f+yAp%X`n{i7R-aNBrfo(0{r|W`EBKUThAePQ z9Mm@5K2$8-FDp&N^O8FS8bwQlUv(jSbJ$57fJ{xwqu8xAD{-z~qjYe;X9HUC3*ymo zvKeXPgBuG7GCY7wi9cFaR5Aq2bwCyD4aaqLf49eb&+E4&B1*idRAeUMgHL}=APfqh zJA#NcTN%Xck4REv>M7+g@Zubr1DOdN1Bg13p7-|~!yOmU!h#Dd>}Pw#+0`&fUip$I z%JsIWZQDEPB+Qpt79?w&OfdxVP|)u!L1{?3OhN&aW2iP?B00$6lg@1OwI7CeiQ=s` zmOK*^Dq)0p9yQKC38=<%gz1HWZhFjWXiA-*4srs1QnxS@xT zsSunp*2$cZ)Mj^rJeL;t$F)p0K=*7Y3jr=KZMk<4ux@^NK_J*CQ*~N}yK;R{4JTQY zvKKiYvK~Ehf*!$lLLy5Yu?(fwE(^w^TiXD>`=K;YO?vlCodH=jnCrNYM6?8mUQlokz`@B)bp=+<@MXbQfpX}ChO2V z$d)$Fp^+~HY()CS2_e}Lnh9E2CG|gAmw>eMyN~9%DqN*p`z5$OGR-VvalDscsg8rg zN*XWQjhs@S*9Ay7yei$Eu_ibWNeN#z3V#e-egAWV`F~aR5tCOVC%HdHZ?=j(fAnJ(QR8_bFI=20E<$nVHoV&>0IY7H zg8dK`_8p#9DY@9@#rxfh+G&*ToE(~#dwjQih^5WuNu?8 z4z=%jUBu6A>l!6VbHl!7gk%n_H2DNEJEJy~cR?OvwO|j#hxBcvS)Q%MpQ1p)kzZ+8 zj)amlsw-1+P=9Uli$?oe1dofBbtvTaRjO!dkF+IpQ?N4wVKt8PdDwg_hGrMuHvh;| z*5bDS9rwWi9_2{aiztq%vfI7*Pq`zYt(a(UEjG@R?%El5R7~wmXE}YLdIqXUuksofG0}# zf7*G8e#GMH46CN<&8WGnjxunYXPq($)Dbnzo(eWB1~7;d7LXJTiu9XPlkD7|m60up4z?4)q&T6kI80GW&FuxvQWfgnl@ z7;8Gr7aIQ<@n5*4ys;o}&tyj}mK76+y32jpLz zw%Pak?9RgZDm?v($m{xwfSdWbJbyBS%%`6SKbgRCWaw#?xPgabo1M3iastOK%#%k@ znHWzsE;i>MQ0W~r`!Nc{i<3#ZKhnd#!`E+Dln6mVI@1^&uzUYY2GqW^q@=Ef#&8OW z2YTE6oxAD>VW+7PBO7>q(=ldcO1^<{k?GAt`!0~c`1|n?Bxg?>j^6r-BMaMVb(0-ymPioEQY}I`sN<7Xtsu6S` z>64BrLZFqV?~kWIK~FPpk#+1ubHrZ zOl@-Fj19J33^_0*w3>B_w~1h5xqjCJ$rH@?s*ueUto#-fpR?KuPW-vO3Zc2S)_t{; zu*?5LCv&JHjL!r_8rW~Uh+>JW=Kr^od}jg$_}F-On@up{|8g0ekYu5J+I_X*Cz9v{C+`&G`NrF89>jf^Poup#H?Vs8rM>M zwT)9v?LsOV*!1p_0r0~XXvH!AN{)D#*NgVT22x+OiE7o^W*!E9vd1H~(bO&+S;~`{ zhQPaPZNAKE=1!35)kIn9Ty~Y7h25IEPd6#BWu$m{^B&N)DsEp;}LuTll1 z)^`XYsTOjfgsgQnp9>9g9OV~4GnHZU(jwmGa4z>0$PQ!KCKBEGz3~d`VK~8#+*B9 z%LzF+^`!KLc_Txea%X;&O0S$H8r@hJ&nsT(dDx%4w)_)hDy<~KNUAb$Ew@$}e!5kW zkf;C55)a1FiGz{jeT4Z~C+%qE>_Gb0nUl4wk~J>xFT1`svkE)FcT(^Ovj!M{jHStK6O$KidgPxo+vdNs5fgE{zIpO0GA~9JF4GYkNO|VeGCl=rMmttOVj8vo;;mP@f_C>@u^gN50)m*gp1tO_B4~a_SzxXnzmzhG%-9aD0 znd%tasRe=;(zUFEpTl|7xV^YASeTewo&Dlb*kO@F<(#;y>za%i`K1+uHKV%-4ETkViDd0x|a&< zdXmvgnL6z#6_c?cf?AT_1=tFA#ql_g0Qt8YRdDP?&8(-M`0%$kxKTZXywjrDaY`r1eL$DS$P}Q8@*kgl zpn)3tNj%ke^%9Mi-7npvIU;iv4P>}qDbH9oW!>5>t3=c9 zU}2h%JGRb(3|PEXhw?Xp>b&5P(>4uEk|BEbJulCYJ zHRHhsL~&u}(6O2^lHd=D6?rV>1=ij8=5t10`ne_~Pq|&?&=~!{9R*wiK4$Lmk2j2r zL*W!q5VJi6dA*&+-}N;qk0(-+XJ}RzEYB0*F|sE$HN#kG=(|1QCi8m?&cv&3R>e__ z|qo&Td*y z!P5xg00g32r8QjWDYnv4yVtJpAoi(NI4z4Y;R+muIq&TobE24)vBx zqw>ZPC!%Lu{jdKH7ionU>etX z%K?2W;7fHypg`<;r2)y}7Zz3TIUPkZsjXK?YNx%&#$d{1iE@Rtd+b!zKz%JfCM`eb z7vNu@mA^VOjZ8zRi4ekic#d-`1)pWp6@fb2;QxE_$GaOV=x}&7nRJ6d-J#)eV>W_7 zdx^2IaRe)30R&})WRP%h@u+SRkR5p-+Fg6*Ba?mPCRa~OFcSI4BiPn_$#ry!^z&Xe z0*)T27BPtUn3PU?{yocJb*M5}5*IX!H_PuM7R$5m3x9Z-=igtK{K2tU62pTJ-Ujm_FmV5*R2T+?q_)tpm&_@%(3eyN>` z`u$PmS>~6ziUeTfEfk__RxUq!Xe;G1{}YcqUxs2^3mviZ3)j-*gFP;Z^>o!$6saQ) zGKdqo#K9?OHHY023;v_{Yi(hzIJE&|G@xDJYQ-kbZ!nO^X>HTQ$-sWf>15A{a*X+2 z9XN1s42(ho@=bhTy%JmnqV;Qayv}xBf}5al&V!hYXZw|I0MiAzXOSpa-=2LY6Y>`G zH+4xnf!mK7`o9Of0t7!W)xaD7cco{PrJ%($iLI$$NvbOzwjqEgr}OvTNOQD?CcPWqP>-8tjUU z9;06k@j;5^n9f$0a_hk|Og*(Fn#w znA|o;FDfmg-pdQs*_p zwLJfD@cXmoFI!{;D+ow9T@}ls>hq*Yy16J>=FfoDO~`$plrB1`)Djqd@Pi%RUYP<* zw)u#TV1<;;Gp$biv_04i!tZ~w6pJZl1!0sK{_A1!AuH=ygAF$xv$z0VE4+z&_7=;M zNAw5wy+hm{{&d&S(})Vb3@c}?OF_13=LSUy&1a#+;rF;LJVdzPm=jmr3GJ<{Q&#FR zHTZ6faO1z(#w&~C=>i!p^IdtQNd_$yGl$mtu1mp$2Mf?K1@GKbpG?|wQn&R+u!bKI z(ZuSbnV%^b(~hfA9YO1PP40O5hIS*GOVBjyi0lZNbiRKa>l;(Uin-<4RVtx>;*U8-SvL<%(ebSU%Jb#K$VS} z8~_4=)CZ{S*sZMD^Ht&$z}V25)mg-P*3vpaVg>UZ+-P27NS z#q|eA)DGA${w!LnC{+EXY3#tvV1pHCDKe}!_9OX>YYt%v(OV$4?2_rA0nhkqc30gA zYIzxy&n+wKC%xCX4EYnkm0M6}#RHYCCjb1^KG}|QX7hyN#c|9^TJ(%V-p~8Dbqz@M{M9hA z+x?HSM_cLk!Awp!s&zlU%-`!H&7pUGL?J9*%-_Va6=YmC5H3s{Rd4UU=6WI96qX9E zcBD4CREaKDFlg3h6>-@1Ed^!y*M>L~=wdpjnOKQgqFW6K?Nf9wq!BYwAO^XK28GE- z;6s3!GnXT@|ECa@Bo^*E?sNtd+X^3Z@-}uj$=asP$%>m!E{(wHh0YPk9VGR(Gh#1>R^#Eu?Vo6avBO*&u2Uo$=CL8$s zO-LW=?v6kzRORzs48j`ivIA+s*SnbLXR13aBV8NPxlA#vsG%n-(=l%mHgPO)*xcY4 za!6J;8*RD}Sw43EYD87*Q^yYjS!CPMePI9$J4*}&jkb6K#k?O_4j()Ve` z*1~C9cr)$?+3?Tq;*FbYIvh5)2{_&;(;f)HTAm3hU6+lkqGmHq--$3Bp^Gp;`5sl7qYfy5b6hMH_D;4f5`aK zm$z%2oAYXITXV+gHH{=5>z1|Yp5z74k)efu0r1!v;Zr-v(Gtw=($I&Ig8I2(v@K7i z;3*G<(C!>OQZM@7N;o$GKI6m=B&Ur0>IX)c>3Xk>x8ZXr+?VUPj=FYi&#R&-c^jv1 zCfmhs8f$r&2~IodZZ5^-K~qwtX<)=gWUxX_*B(j|hWA)YtAIkiF9wSk5#{qyz6`(W zrX#$-!WV=*3XCw4RvlXka)cx1{K||O(WrDOLxm@u%W9^?z{f|@#k-_hHPTZOgPl|5 zU{4aYv<#EQnXq*Up4W7|Gax|vr?VH7&KFrl#k{Xn0(zz z1tJI~{SMW)z}{r~{-WXkVuyCI#E|3k@XfkuE(xsgs=n7cu*3*Mbf#e(Lgk@40e!c2 zb<^^vHQrd)y!kE%?)$jO&eCX0Q3rLe(oy@(SYeC1&w27TzSBT%m?OU^3X*6C{g|6A zmdR*yl*lSu5z}}m7}#gMcKtCXh~3LE0k(i;rA(}X)HD!g=vhG(t!v|W4CPV{b&rrb zrl^G}7%<=nxKDAwZVlRhP~}TWHdlT_ptD)oPkE=4|Go~GJ~{71jouCpD!*LPY5BNE z8PSSIv$3Cqh;3GmS7sr0x@lAFd{PqmQ{lxD$zg9gNbzk&u%@ME8-u~O7^^H!2zvNi zsh#uEp92&ADJuEzIE9=s1?Nt^N{W~x75(#kNKk-^5eMN+9=a^@8{pc5TJ?v}cQ>4E zYn+shicBOEvd`%26b5do84sL0yxcclM|q4&0wA#vOBvUJ(UX-B`E zI(2)ax$L8EEnCrjlxB~uj@5U*n3I1}^C_O(^Iv{ajSSc{j2SId;qfvqU}1n91;NOf zcKX*BnX|`%e37MCp*6IW>|T-Fsd7m$&G2 z(WmF08J5NNq&k+hB;*GHFjs;9IgWZ6B*zxDstSBicb(g{HrJ>Ye`m5@p404&2prhM zGWwe8ZmAoX7{LVI*RUfx@3;ifBmioq_^PF0^PfZ7f%0cxh=r#PTn z4w!6V31mDD9VMx6o8?Cl+Qg`t)g9S>>1<81hI|?Lv@_UXQbk5e*5ts;jBeZO$+;`^ z@FNuTfubDoy;W^d(U0ObO|Snw%SEQ`XE}}{lTW0GW&DF@Tpm}-#{LKRxjL7J!u-%P zR5iLWGj{G2z*V;=age5(uvk?w%;^_7OD%C_?l53tyhryU$$piiXh|_hkuhmYI`fea z7F9~Xo&3iqn#Zx?>)>NvwZ;h-Cs%KuzhsEC!V zHFyleu!|xJC*c+l1Tnz^q@Orpb~=@;y&_IKt8V;fbBHo*GTNP}zBGq5;N)i=2d#^E z5^Y}X+h{5Loo@RfG=u8Gpjj&Sy~Q0{z8EtNseYy2w|X{}OOz5h%a)>jy#$N;F0wC9 zhNoxpDq#MoS(o-p3mZJvUD3DXIj%X>%yfD!Z{9=@P5M^(@{yKg&72L*{JRws!+G-+3k#9S=?D#H6M|803f^P0pc>g69yAab)(z*W8zL;XIBqdx&0B0a3^HK5$zO0 z&QZi^o8AnYBkKTp$UqhOzpEpc8863{{ig-LoM-n)<>~B0T~IK0YQNl|}`(BJRMo z=f?)(g#Lvw0{m@^@YiK|zK0~{1%inKq_%fzoU?i``$$lMCu%Dval2QzXVH)N>+ZnE zO4})=LpgbgVH1PEM}X-OOcg*9Xdnm_*TEasP=1M0OZV<+WW>8O;<6XkBOZtd(rAl8 z3q{$uLeVP&<&a)XuLPrp04Uv0s2i6~E#xBY@sPvejdY!Kw9L;hU9H?wLEHn>;2x$l zI9JG$D(Dx`2c&?{V)kuu;%nXQV2we#$y8W*B7M2joy}Hh6mwXxl6^Db{+={3?P$>n z?voWw_bW!65rm$$s>sv2g%1HU<`w*7&3y({Y1|sr1 z;Ri#2O-bGL9pAWF9%<3Is8$Mr#dK_#q@nxA*gWF??{}Fr(MbwZLkgt@{E;X%+v0R; z$715fT=SrzUNC`mHHzGQXt5b~<}O@vn|c=;#z}qLt5(ygXmJJapy%w59T-mCYSM%G zl-UJ+mk7;$L$#OH%j5HouNLk5{|310nw0!q-_y25!B74~l6T(%7X<^R3}%kDTr?1< zrVQuGAwxzh&Hq>h)4=og2Jw%N%Ozpe0!R0iiV;v8Ik8M};1>u Date: Thu, 8 Nov 2018 00:13:02 -0500 Subject: [PATCH 095/102] CONTRIBUTING.md: migrate to the wiki --- CONTRIBUTING.md | 138 +----------------------------------------------- 1 file changed, 1 insertion(+), 137 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f965ea7d2..3e98984c4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,137 +1 @@ -# Reporting Issues - -**The issue tracker is not a support forum.** Unless you can provide precise *technical information* regarding an issue, you *should not post in it*. If you need support, first read the [FAQ](https://github.com/citra-emu/citra/wiki/FAQ) and then either visit our IRC or [Discord](https://citra-emu.org/discord/) channel, [our forum](https://community.citra-emu.org) or ask in a general emulation forum such as [/r/emulation](https://www.reddit.com/r/emulation/). If you post support questions, generic messages to the developers or vague reports without technical details, they will be closed and locked. - -If you believe you have a valid issue report, please post text or a screenshot from the log (the console window that opens alongside Citra) and build version (hex string visible in the titlebar and zip filename), as well as your hardware and software information if applicable. - -# Contributing - -Citra is a brand new project, so we have a great opportunity to keep things clean and well organized early on. As such, coding style is very important when making commits. We run clang-format on our CI to check the code. Please use it to format your code when contributing. However, it doesn't cover all the rules below. Some of them aren't very strict rules since we want to be flexible and we understand that under certain circumstances some of them can be counterproductive. Just try to follow as many of them as possible. - -# Using clang format (version 6.0) -When generating the native build script for your toolset, cmake will try to find the correct version of clang format (or will download it on windows). Before running cmake, please install clang format version 6.0 for your platform as follows: - -* Windows: do nothing; cmake will download a pre built binary for MSVC and MINGW. MSVC users can additionally install a clang format Visual Studio extension to add features like format on save. -* OSX: run `brew install clang-format`. -* Linux: use your package manager to get an appropriate binary. - -If clang format is found, then cmake will add a custom build target that can be run at any time to run clang format against *all* source files and update the formatting in them. This should be used before making a pull request so that the reviewers can spend more time reviewing the code instead of having to worry about minor style violations. On MSVC, you can run clang format by building the clang-format project in the solution. On OSX, you can either use the Makefile target `make clang-format` or by building the clang-format target in XCode. For Makefile builds, you can use the clang-format target with `make clang-format` - -### General Rules -* A lot of code was taken from other projects (e.g. Dolphin, PPSSPP, Gekko, SkyEye). In general, when editing other people's code, follow the style of the module you're in (or better yet, fix the style if it drastically differs from our guide). -* Line width is typically 100 characters. Please do not use 80-characters. -* Don't ever introduce new external dependencies into Core -* Don't use any platform specific code in Core -* Use namespaces often -* Avoid the use of C-style casts and instead prefer C++-style `static_cast` and `reinterpret_cast`. Try to avoid using `dynamic_cast`. Never use `const_cast`. - -### Naming Rules -* Functions: `PascalCase` -* Variables: `lower_case_underscored`. Prefix with `g_` if global. -* Classes: `PascalCase` -* Files and Directories: `lower_case_underscored` -* Namespaces: `PascalCase`, `_` may also be used for clarity (e.g. `ARM_InitCore`) - -### Indentation/Whitespace Style -Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead. - -### Comments -* For regular comments, use C++ style (`//`) comments, even for multi-line ones. -* For doc-comments (Doxygen comments), use `/// ` if it's a single line, else use the `/**` `*/` style featured in the example. Start the text on the second line, not the first containing `/**`. -* For items that are both defined and declared in two separate files, put the doc-comment only next to the associated declaration. (In a header file, usually.) Otherwise, put it next to the implementation. Never duplicate doc-comments in both places. - -```cpp -// Includes should be sorted lexicographically -// STD includes first -#include -#include - -// then, library includes -#include - -// finally, citra includes -#include "common/math_util.h" -#include "common/vector_math.h" - -// each major module is separated -#include "video_core/pica.h" -#include "video_core/video_core.h" - -namespace Example { - -// Namespace contents are not indented - -// Declare globals at the top -int g_foo{}; // {} can be used to initialize types as 0, false, or nullptr -char* g_some_pointer{}; // Pointer * and reference & stick to the type name, and make sure to initialize as nullptr! - -/// A colorful enum. -enum SomeEnum { - ColorRed, ///< The color of fire. - ColorGreen, ///< The color of grass. - ColorBlue, ///< Not actually the color of water. -}; - -/** - * Very important struct that does a lot of stuff. - * Note that the asterisks are indented by one space to align to the first line. - */ -struct Position { - int x{}, y{}; // Always intitialize member variables! -}; - -// Use "typename" rather than "class" here -template -void FooBar() { - const std::string some_string{ "prefer uniform initialization" }; - - int some_array[]{ - 5, - 25, - 7, - 42, - }; - - if (note == the_space_after_the_if) { - CallAfunction(); - } else { - // Use a space after the // when commenting - } - - // Place a single space after the for loop semicolons, prefer pre-increment - for (int i{}; i != 25; ++i) { - // This is how we write loops - } - - DoStuff(this, function, call, takes, up, multiple, - lines, like, this); - - if (this || condition_takes_up_multiple && - lines && like && this || everything || - alright || then) { - - // Leave a blank space before the if block body if the condition was continued across - // several lines. - } - - switch (var) { - // No indentation for case label - case 1: { - int case_var{ var + 3 }; - DoSomething(case_var); - break; - } - case 3: - DoSomething(var); - return; - - default: - // Yes, even break for the last case - break; - } - - std::vector you_can_declare, a_few, variables, like_this; -} - -} -``` +**The Contributor's Guide has moved to [the wiki](https://github.com/citra-emu/citra/wiki/Contributing).** \ No newline at end of file From 8c65433ab5a70870111b4462d54871f3d349ee7a Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sun, 4 Nov 2018 12:11:08 -0500 Subject: [PATCH 096/102] Kernel, APT: SharedFont/SharedMemoryOnSharedDevice should always use old linear heap VAddr --- src/core/hle/kernel/shared_memory.cpp | 5 ++++- src/core/hle/service/apt/apt.cpp | 15 +++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 560d3f3ac..f32651d49 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -142,7 +142,10 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi if (base_address == 0 && target_address == 0) { // Calculate the address at which to map the memory block. - target_address = linear_heap_phys_offset + target_process->GetLinearHeapAreaAddress(); + // Note: even on new firmware versions, the target address is still in the old linear heap + // region. This exception is made to keep the shared font compatibility. See + // APT:GetSharedFont for detail. + target_address = linear_heap_phys_offset + Memory::LINEAR_HEAP_VADDR; } auto vma = target_process->vm_manager.FindVMA(target_address); diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 741a288e8..44b81a0fd 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -207,10 +207,17 @@ void Module::Interface::GetSharedFont(Kernel::HLERequestContext& ctx) { // The shared font has to be relocated to the new address before being passed to the // application. - auto maybe_vaddr = Memory::PhysicalToVirtualAddress( - apt->shared_font_mem->linear_heap_phys_offset + Memory::FCRAM_PADDR); - ASSERT(maybe_vaddr); - VAddr target_address = *maybe_vaddr; + + // Note: the target address is still in the old linear heap region even on new firmware + // versions. This exception is made for shared font to resolve the following compatibility + // issue: + // The linear heap region changes depending on the kernel version marked in application's + // exheader (not the actual version the application is running on). If an application with old + // kernel version and an applet with new kernel version run at the same time, and they both use + // shared font, different linear heap region would have required shared font to relocate + // according to two different addresses at the same time, which is impossible. + VAddr target_address = + apt->shared_font_mem->linear_heap_phys_offset + Memory::LINEAR_HEAP_VADDR; if (!apt->shared_font_relocated) { BCFNT::RelocateSharedFont(apt->shared_font_mem, target_address); apt->shared_font_relocated = true; From 2654a679b3d1a6fb3c36ca00b44dce713b9a98b4 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sun, 4 Nov 2018 12:15:55 -0500 Subject: [PATCH 097/102] Memory: replace PhysicalToVirtualAddress with a more dedicated function There is no external use of PhysicalToVirtualAddress any more, so it there is no need to have a generic function that handles all physical regions. Also, the previous APT change makes it possible that linear heap has some regions mapped to old and new VAddr regions at the same time, so we need to check both region and mark cached for the mapped one. RasterizerMarkRegionCached would skip the unmapped one in its loop --- src/core/memory.cpp | 122 ++++++++++++++++++++------------------------ src/core/memory.h | 5 -- 2 files changed, 54 insertions(+), 73 deletions(-) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 697345ea7..af37ff471 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -318,6 +318,22 @@ u8* GetPhysicalPointer(PAddr address) { return target_pointer; } +/// For a rasterizer-accessible PAddr, gets a list of all possible VAddr +static std::vector PhysicalToVirtualAddressForRasterizer(PAddr addr) { + if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) { + return {addr - VRAM_PADDR + VRAM_VADDR}; + } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) { + return {addr - FCRAM_PADDR + LINEAR_HEAP_VADDR, addr - FCRAM_PADDR + NEW_LINEAR_HEAP_VADDR}; + } else { + // While the physical <-> virtual mapping is 1:1 for the regions supported by the cache, + // some games (like Pokemon Super Mystery Dungeon) will try to use textures that go beyond + // the end address of VRAM, causing the Virtual->Physical translation to fail when flushing + // parts of the texture. + LOG_ERROR(HW_Memory, "Trying to use invalid physical address for rasterizer: {:08X}", addr); + return {}; + } +} + void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached) { if (start == 0) { return; @@ -327,57 +343,46 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached) { PAddr paddr = start; for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) { - std::optional maybe_vaddr = PhysicalToVirtualAddress(paddr); - // While the physical <-> virtual mapping is 1:1 for the regions supported by the cache, - // some games (like Pokemon Super Mystery Dungeon) will try to use textures that go beyond - // the end address of VRAM, causing the Virtual->Physical translation to fail when flushing - // parts of the texture. - if (!maybe_vaddr) { - LOG_ERROR(HW_Memory, - "Trying to flush a cached region to an invalid physical address {:08X}", - paddr); - continue; - } - VAddr vaddr = *maybe_vaddr; + for (VAddr vaddr : PhysicalToVirtualAddressForRasterizer(paddr)) { + PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS]; - PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS]; - - if (cached) { - // Switch page type to cached if now cached - switch (page_type) { - case PageType::Unmapped: - // It is not necessary for a process to have this region mapped into its address - // space, for example, a system module need not have a VRAM mapping. - break; - case PageType::Memory: - page_type = PageType::RasterizerCachedMemory; - current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr; - break; - default: - UNREACHABLE(); - } - } else { - // Switch page type to uncached if now uncached - switch (page_type) { - case PageType::Unmapped: - // It is not necessary for a process to have this region mapped into its address - // space, for example, a system module need not have a VRAM mapping. - break; - case PageType::RasterizerCachedMemory: { - u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK); - if (pointer == nullptr) { - // It's possible that this function has been called while updating the pagetable - // after unmapping a VMA. In that case the underlying VMA will no longer exist, - // and we should just leave the pagetable entry blank. - page_type = PageType::Unmapped; - } else { - page_type = PageType::Memory; - current_page_table->pointers[vaddr >> PAGE_BITS] = pointer; + if (cached) { + // Switch page type to cached if now cached + switch (page_type) { + case PageType::Unmapped: + // It is not necessary for a process to have this region mapped into its address + // space, for example, a system module need not have a VRAM mapping. + break; + case PageType::Memory: + page_type = PageType::RasterizerCachedMemory; + current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr; + break; + default: + UNREACHABLE(); + } + } else { + // Switch page type to uncached if now uncached + switch (page_type) { + case PageType::Unmapped: + // It is not necessary for a process to have this region mapped into its address + // space, for example, a system module need not have a VRAM mapping. + break; + case PageType::RasterizerCachedMemory: { + u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK); + if (pointer == nullptr) { + // It's possible that this function has been called while updating the + // pagetable after unmapping a VMA. In that case the underlying VMA will no + // longer exist, and we should just leave the pagetable entry blank. + page_type = PageType::Unmapped; + } else { + page_type = PageType::Memory; + current_page_table->pointers[vaddr >> PAGE_BITS] = pointer; + } + break; + } + default: + UNREACHABLE(); } - break; - } - default: - UNREACHABLE(); } } } @@ -820,25 +825,6 @@ PAddr VirtualToPhysicalAddress(const VAddr addr) { return *paddr; } -std::optional PhysicalToVirtualAddress(const PAddr addr) { - if (addr == 0) { - return 0; - } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) { - return addr - VRAM_PADDR + VRAM_VADDR; - } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) { - return addr - FCRAM_PADDR + - Core::System::GetInstance().Kernel().GetCurrentProcess()->GetLinearHeapAreaAddress(); - } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) { - return addr - DSP_RAM_PADDR + DSP_RAM_VADDR; - } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) { - return addr - IO_AREA_PADDR + IO_AREA_VADDR; - } else if (addr >= N3DS_EXTRA_RAM_PADDR && addr < N3DS_EXTRA_RAM_PADDR_END) { - return addr - N3DS_EXTRA_RAM_PADDR + N3DS_EXTRA_RAM_VADDR; - } - - return {}; -} - u32 GetFCRAMOffset(u8* pointer) { ASSERT(pointer >= fcram.data() && pointer < fcram.data() + fcram.size()); return pointer - fcram.data(); diff --git a/src/core/memory.h b/src/core/memory.h index bad47375a..a1e4383df 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -228,11 +228,6 @@ std::optional TryVirtualToPhysicalAddress(VAddr addr); */ PAddr VirtualToPhysicalAddress(VAddr addr); -/** - * Undoes a mapping performed by VirtualToPhysicalAddress(). - */ -std::optional PhysicalToVirtualAddress(PAddr paddr); - /** * Gets a pointer to the memory region beginning at the specified physical address. */ From 98ddea4ddda566a03d04fb6d3ade4f5242005891 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Fri, 9 Nov 2018 00:14:13 -0500 Subject: [PATCH 098/102] Kernel: correct MemoryState for TLS --- src/core/hle/kernel/thread.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 5655f6f5f..7f1749a5f 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -353,10 +353,9 @@ ResultVal> KernelSystem::CreateThread(std::string name, VAddr auto& vm_manager = owner_process.vm_manager; // Map the page to the current process' address space. - // TODO(Subv): Find the correct MemoryState for this region. vm_manager.MapBackingMemory(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE, Memory::fcram.data() + *offset, Memory::PAGE_SIZE, - MemoryState::Private); + MemoryState::Locked); } // Mark the slot as used From d0edb81182ae430f5d5f1ababa1f6e593edaadb9 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Fri, 9 Nov 2018 10:40:04 -0500 Subject: [PATCH 099/102] Memory: convert PAddr for N3DS FCRAM extension --- src/core/memory.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index af37ff471..ed5a04c9a 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -322,16 +322,19 @@ u8* GetPhysicalPointer(PAddr address) { static std::vector PhysicalToVirtualAddressForRasterizer(PAddr addr) { if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) { return {addr - VRAM_PADDR + VRAM_VADDR}; - } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) { - return {addr - FCRAM_PADDR + LINEAR_HEAP_VADDR, addr - FCRAM_PADDR + NEW_LINEAR_HEAP_VADDR}; - } else { - // While the physical <-> virtual mapping is 1:1 for the regions supported by the cache, - // some games (like Pokemon Super Mystery Dungeon) will try to use textures that go beyond - // the end address of VRAM, causing the Virtual->Physical translation to fail when flushing - // parts of the texture. - LOG_ERROR(HW_Memory, "Trying to use invalid physical address for rasterizer: {:08X}", addr); - return {}; } + if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) { + return {addr - FCRAM_PADDR + LINEAR_HEAP_VADDR, addr - FCRAM_PADDR + NEW_LINEAR_HEAP_VADDR}; + } + if (addr >= FCRAM_PADDR_END && addr < FCRAM_N3DS_PADDR_END) { + return {addr - FCRAM_PADDR + NEW_LINEAR_HEAP_VADDR}; + } + // While the physical <-> virtual mapping is 1:1 for the regions supported by the cache, + // some games (like Pokemon Super Mystery Dungeon) will try to use textures that go beyond + // the end address of VRAM, causing the Virtual->Physical translation to fail when flushing + // parts of the texture. + LOG_ERROR(HW_Memory, "Trying to use invalid physical address for rasterizer: {:08X}", addr); + return {}; } void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached) { From 5179915fb48c4a7415d7effe8eb88568ed033f40 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sat, 10 Nov 2018 22:57:29 -0500 Subject: [PATCH 100/102] filesys/ncch: prevent buffer overflow on calculating SHA256 --- src/core/file_sys/ncch_container.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/file_sys/ncch_container.cpp b/src/core/file_sys/ncch_container.cpp index 4e9b2efa7..d913c8624 100644 --- a/src/core/file_sys/ncch_container.cpp +++ b/src/core/file_sys/ncch_container.cpp @@ -179,7 +179,9 @@ Loader::ResultStatus NCCHContainer::Load() { std::memcpy(input.data(), key_y_primary.data(), key_y_primary.size()); std::memcpy(input.data() + key_y_primary.size(), seed.data(), seed.size()); CryptoPP::SHA256 sha; - sha.CalculateDigest(key_y_secondary.data(), input.data(), input.size()); + std::array hash; + sha.CalculateDigest(hash.data(), input.data(), input.size()); + std::memcpy(key_y_secondary.data(), hash.data(), key_y_secondary.size()); } } From 194118011a6dcb4cc19159a80045b24336e5bd8b Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Mon, 12 Nov 2018 15:12:12 -0500 Subject: [PATCH 101/102] Memory: IO area is at most 4MB --- src/core/memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/memory.h b/src/core/memory.h index bad47375a..3c1afd7c1 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -75,7 +75,7 @@ struct PageTable { enum : PAddr { /// IO register area IO_AREA_PADDR = 0x10100000, - IO_AREA_SIZE = 0x01000000, ///< IO area size (16MB) + IO_AREA_SIZE = 0x00400000, ///< IO area size (4MB) IO_AREA_PADDR_END = IO_AREA_PADDR + IO_AREA_SIZE, /// MPCore internal memory region From 34e1250ccc2e19f8ad386947a01c14eadacd6158 Mon Sep 17 00:00:00 2001 From: Tobias Date: Tue, 13 Nov 2018 14:58:05 +0100 Subject: [PATCH 102/102] citra_qt: Add Amiibo hotkeys, notify user of loading errors (#4387) --- src/citra_qt/main.cpp | 77 +++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 21 deletions(-) diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index dc1b82136..db5c3c2ee 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -344,8 +344,9 @@ void GMainWindow::InitializeHotkeys() { hotkey_registry.RegisterHotkey("Main Window", "Start Emulation"); hotkey_registry.RegisterHotkey("Main Window", "Continue/Pause", QKeySequence(Qt::Key_F4)); hotkey_registry.RegisterHotkey("Main Window", "Restart", QKeySequence(Qt::Key_F5)); - hotkey_registry.RegisterHotkey("Main Window", "Swap Screens", QKeySequence(tr("F9"))); - hotkey_registry.RegisterHotkey("Main Window", "Toggle Screen Layout", QKeySequence(tr("F10"))); + hotkey_registry.RegisterHotkey("Main Window", "Swap Screens", QKeySequence(Qt::Key_F9)); + hotkey_registry.RegisterHotkey("Main Window", "Toggle Screen Layout", + QKeySequence(Qt::Key_F10)); hotkey_registry.RegisterHotkey("Main Window", "Fullscreen", QKeySequence::FullScreen); hotkey_registry.RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence(Qt::Key_Escape), Qt::ApplicationShortcut); @@ -359,6 +360,11 @@ void GMainWindow::InitializeHotkeys() { Qt::ApplicationShortcut); hotkey_registry.RegisterHotkey("Main Window", "Advance Frame", QKeySequence(Qt::Key_Backslash), Qt::ApplicationShortcut); + hotkey_registry.RegisterHotkey("Main Window", "Load Amiibo", QKeySequence(Qt::Key_F2), + Qt::ApplicationShortcut); + hotkey_registry.RegisterHotkey("Main Window", "Remove Amiibo", QKeySequence(Qt::Key_F3), + Qt::ApplicationShortcut); + hotkey_registry.LoadHotkeys(); connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated, @@ -420,6 +426,18 @@ void GMainWindow::InitializeHotkeys() { &QShortcut::activated, ui.action_Enable_Frame_Advancing, &QAction::trigger); connect(hotkey_registry.GetHotkey("Main Window", "Advance Frame", this), &QShortcut::activated, ui.action_Advance_Frame, &QAction::trigger); + connect(hotkey_registry.GetHotkey("Main Window", "Load Amiibo", this), &QShortcut::activated, + this, [&] { + if (ui.action_Load_Amiibo->isEnabled()) { + OnLoadAmiibo(); + } + }); + connect(hotkey_registry.GetHotkey("Main Window", "Remove Amiibo", this), &QShortcut::activated, + this, [&] { + if (ui.action_Remove_Amiibo->isEnabled()) { + OnRemoveAmiibo(); + } + }); } void GMainWindow::ShowUpdaterWidgets() { @@ -1301,33 +1319,50 @@ void GMainWindow::OnLoadAmiibo() { const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions); const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), "", file_filter); - if (!filename.isEmpty()) { - Core::System& system{Core::System::GetInstance()}; - Service::SM::ServiceManager& sm = system.ServiceManager(); - auto nfc = sm.GetService("nfc:u"); - if (nfc != nullptr) { - Service::NFC::AmiiboData amiibo_data{}; - auto nfc_file = FileUtil::IOFile(filename.toStdString(), "rb"); - std::size_t read_length = - nfc_file.ReadBytes(&amiibo_data, sizeof(Service::NFC::AmiiboData)); - if (read_length != sizeof(Service::NFC::AmiiboData)) { - LOG_ERROR(Frontend, "Amiibo file size is incorrect"); - return; - } - nfc->LoadAmiibo(amiibo_data); - ui.action_Remove_Amiibo->setEnabled(true); - } + if (filename.isEmpty()) { + return; } + + Core::System& system{Core::System::GetInstance()}; + Service::SM::ServiceManager& sm = system.ServiceManager(); + auto nfc = sm.GetService("nfc:u"); + if (nfc == nullptr) { + return; + } + + QFile nfc_file{filename}; + if (!nfc_file.open(QIODevice::ReadOnly)) { + QMessageBox::warning(this, tr("Error opening Amiibo data file"), + tr("Unable to open Amiibo file \"%1\" for reading.").arg(filename)); + return; + } + + Service::NFC::AmiiboData amiibo_data{}; + const u64 read_size = + nfc_file.read(reinterpret_cast(&amiibo_data), sizeof(Service::NFC::AmiiboData)); + if (read_size != sizeof(Service::NFC::AmiiboData)) { + QMessageBox::warning(this, tr("Error reading Amiibo data file"), + tr("Unable to fully read Amiibo data. Expected to read %1 bytes, but " + "was only able to read %2 bytes.") + .arg(sizeof(Service::NFC::AmiiboData)) + .arg(read_size)); + return; + } + + nfc->LoadAmiibo(amiibo_data); + ui.action_Remove_Amiibo->setEnabled(true); } void GMainWindow::OnRemoveAmiibo() { Core::System& system{Core::System::GetInstance()}; Service::SM::ServiceManager& sm = system.ServiceManager(); auto nfc = sm.GetService("nfc:u"); - if (nfc != nullptr) { - nfc->RemoveAmiibo(); - ui.action_Remove_Amiibo->setEnabled(false); + if (nfc == nullptr) { + return; } + + nfc->RemoveAmiibo(); + ui.action_Remove_Amiibo->setEnabled(false); } void GMainWindow::OnToggleFilterBar() {