diff options
22 files changed, 166 insertions, 164 deletions
diff --git a/src/common/telemetry.cpp b/src/common/telemetry.cpp index f53a8d193..200c6489a 100644 --- a/src/common/telemetry.cpp +++ b/src/common/telemetry.cpp | |||
| @@ -44,20 +44,6 @@ template class Field<std::string>; | |||
| 44 | template class Field<const char*>; | 44 | template class Field<const char*>; |
| 45 | template class Field<std::chrono::microseconds>; | 45 | template class Field<std::chrono::microseconds>; |
| 46 | 46 | ||
| 47 | #ifdef ARCHITECTURE_x86_64 | ||
| 48 | static const char* CpuVendorToStr(Common::CPUVendor vendor) { | ||
| 49 | switch (vendor) { | ||
| 50 | case Common::CPUVendor::INTEL: | ||
| 51 | return "Intel"; | ||
| 52 | case Common::CPUVendor::AMD: | ||
| 53 | return "Amd"; | ||
| 54 | case Common::CPUVendor::OTHER: | ||
| 55 | return "Other"; | ||
| 56 | } | ||
| 57 | UNREACHABLE(); | ||
| 58 | } | ||
| 59 | #endif | ||
| 60 | |||
| 61 | void AppendBuildInfo(FieldCollection& fc) { | 47 | void AppendBuildInfo(FieldCollection& fc) { |
| 62 | const bool is_git_dirty{std::strstr(Common::g_scm_desc, "dirty") != nullptr}; | 48 | const bool is_git_dirty{std::strstr(Common::g_scm_desc, "dirty") != nullptr}; |
| 63 | fc.AddField(FieldType::App, "Git_IsDirty", is_git_dirty); | 49 | fc.AddField(FieldType::App, "Git_IsDirty", is_git_dirty); |
| @@ -71,7 +57,6 @@ void AppendCPUInfo(FieldCollection& fc) { | |||
| 71 | #ifdef ARCHITECTURE_x86_64 | 57 | #ifdef ARCHITECTURE_x86_64 |
| 72 | fc.AddField(FieldType::UserSystem, "CPU_Model", Common::GetCPUCaps().cpu_string); | 58 | fc.AddField(FieldType::UserSystem, "CPU_Model", Common::GetCPUCaps().cpu_string); |
| 73 | fc.AddField(FieldType::UserSystem, "CPU_BrandString", Common::GetCPUCaps().brand_string); | 59 | fc.AddField(FieldType::UserSystem, "CPU_BrandString", Common::GetCPUCaps().brand_string); |
| 74 | fc.AddField(FieldType::UserSystem, "CPU_Vendor", CpuVendorToStr(Common::GetCPUCaps().vendor)); | ||
| 75 | fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AES", Common::GetCPUCaps().aes); | 60 | fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AES", Common::GetCPUCaps().aes); |
| 76 | fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX", Common::GetCPUCaps().avx); | 61 | fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX", Common::GetCPUCaps().avx); |
| 77 | fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX2", Common::GetCPUCaps().avx2); | 62 | fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX2", Common::GetCPUCaps().avx2); |
diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp index 2dfcd39c8..c9349a6b4 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp | |||
| @@ -3,8 +3,6 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include <string> | ||
| 7 | #include <thread> | ||
| 8 | #include "common/common_types.h" | 6 | #include "common/common_types.h" |
| 9 | #include "common/x64/cpu_detect.h" | 7 | #include "common/x64/cpu_detect.h" |
| 10 | 8 | ||
| @@ -51,8 +49,6 @@ namespace Common { | |||
| 51 | static CPUCaps Detect() { | 49 | static CPUCaps Detect() { |
| 52 | CPUCaps caps = {}; | 50 | CPUCaps caps = {}; |
| 53 | 51 | ||
| 54 | caps.num_cores = std::thread::hardware_concurrency(); | ||
| 55 | |||
| 56 | // Assumes the CPU supports the CPUID instruction. Those that don't would likely not support | 52 | // Assumes the CPU supports the CPUID instruction. Those that don't would likely not support |
| 57 | // yuzu at all anyway | 53 | // yuzu at all anyway |
| 58 | 54 | ||
| @@ -70,12 +66,6 @@ static CPUCaps Detect() { | |||
| 70 | __cpuid(cpu_id, 0x80000000); | 66 | __cpuid(cpu_id, 0x80000000); |
| 71 | 67 | ||
| 72 | u32 max_ex_fn = cpu_id[0]; | 68 | u32 max_ex_fn = cpu_id[0]; |
| 73 | if (!strcmp(caps.brand_string, "GenuineIntel")) | ||
| 74 | caps.vendor = CPUVendor::INTEL; | ||
| 75 | else if (!strcmp(caps.brand_string, "AuthenticAMD")) | ||
| 76 | caps.vendor = CPUVendor::AMD; | ||
| 77 | else | ||
| 78 | caps.vendor = CPUVendor::OTHER; | ||
| 79 | 69 | ||
| 80 | // Set reasonable default brand string even if brand string not available | 70 | // Set reasonable default brand string even if brand string not available |
| 81 | strcpy(caps.cpu_string, caps.brand_string); | 71 | strcpy(caps.cpu_string, caps.brand_string); |
| @@ -96,15 +86,9 @@ static CPUCaps Detect() { | |||
| 96 | caps.sse4_1 = true; | 86 | caps.sse4_1 = true; |
| 97 | if ((cpu_id[2] >> 20) & 1) | 87 | if ((cpu_id[2] >> 20) & 1) |
| 98 | caps.sse4_2 = true; | 88 | caps.sse4_2 = true; |
| 99 | if ((cpu_id[2] >> 22) & 1) | ||
| 100 | caps.movbe = true; | ||
| 101 | if ((cpu_id[2] >> 25) & 1) | 89 | if ((cpu_id[2] >> 25) & 1) |
| 102 | caps.aes = true; | 90 | caps.aes = true; |
| 103 | 91 | ||
| 104 | if ((cpu_id[3] >> 24) & 1) { | ||
| 105 | caps.fxsave_fxrstor = true; | ||
| 106 | } | ||
| 107 | |||
| 108 | // AVX support requires 3 separate checks: | 92 | // AVX support requires 3 separate checks: |
| 109 | // - Is the AVX bit set in CPUID? | 93 | // - Is the AVX bit set in CPUID? |
| 110 | // - Is the XSAVE bit set in CPUID? | 94 | // - Is the XSAVE bit set in CPUID? |
| @@ -129,8 +113,6 @@ static CPUCaps Detect() { | |||
| 129 | } | 113 | } |
| 130 | } | 114 | } |
| 131 | 115 | ||
| 132 | caps.flush_to_zero = caps.sse; | ||
| 133 | |||
| 134 | if (max_ex_fn >= 0x80000004) { | 116 | if (max_ex_fn >= 0x80000004) { |
| 135 | // Extract CPU model string | 117 | // Extract CPU model string |
| 136 | __cpuid(cpu_id, 0x80000002); | 118 | __cpuid(cpu_id, 0x80000002); |
| @@ -144,14 +126,8 @@ static CPUCaps Detect() { | |||
| 144 | if (max_ex_fn >= 0x80000001) { | 126 | if (max_ex_fn >= 0x80000001) { |
| 145 | // Check for more features | 127 | // Check for more features |
| 146 | __cpuid(cpu_id, 0x80000001); | 128 | __cpuid(cpu_id, 0x80000001); |
| 147 | if (cpu_id[2] & 1) | ||
| 148 | caps.lahf_sahf_64 = true; | ||
| 149 | if ((cpu_id[2] >> 5) & 1) | ||
| 150 | caps.lzcnt = true; | ||
| 151 | if ((cpu_id[2] >> 16) & 1) | 129 | if ((cpu_id[2] >> 16) & 1) |
| 152 | caps.fma4 = true; | 130 | caps.fma4 = true; |
| 153 | if ((cpu_id[3] >> 29) & 1) | ||
| 154 | caps.long_mode = true; | ||
| 155 | } | 131 | } |
| 156 | 132 | ||
| 157 | return caps; | 133 | return caps; |
| @@ -162,48 +138,4 @@ const CPUCaps& GetCPUCaps() { | |||
| 162 | return caps; | 138 | return caps; |
| 163 | } | 139 | } |
| 164 | 140 | ||
| 165 | std::string GetCPUCapsString() { | ||
| 166 | auto caps = GetCPUCaps(); | ||
| 167 | |||
| 168 | std::string sum(caps.cpu_string); | ||
| 169 | sum += " ("; | ||
| 170 | sum += caps.brand_string; | ||
| 171 | sum += ")"; | ||
| 172 | |||
| 173 | if (caps.sse) | ||
| 174 | sum += ", SSE"; | ||
| 175 | if (caps.sse2) { | ||
| 176 | sum += ", SSE2"; | ||
| 177 | if (!caps.flush_to_zero) | ||
| 178 | sum += " (without DAZ)"; | ||
| 179 | } | ||
| 180 | |||
| 181 | if (caps.sse3) | ||
| 182 | sum += ", SSE3"; | ||
| 183 | if (caps.ssse3) | ||
| 184 | sum += ", SSSE3"; | ||
| 185 | if (caps.sse4_1) | ||
| 186 | sum += ", SSE4.1"; | ||
| 187 | if (caps.sse4_2) | ||
| 188 | sum += ", SSE4.2"; | ||
| 189 | if (caps.avx) | ||
| 190 | sum += ", AVX"; | ||
| 191 | if (caps.avx2) | ||
| 192 | sum += ", AVX2"; | ||
| 193 | if (caps.bmi1) | ||
| 194 | sum += ", BMI1"; | ||
| 195 | if (caps.bmi2) | ||
| 196 | sum += ", BMI2"; | ||
| 197 | if (caps.fma) | ||
| 198 | sum += ", FMA"; | ||
| 199 | if (caps.aes) | ||
| 200 | sum += ", AES"; | ||
| 201 | if (caps.movbe) | ||
| 202 | sum += ", MOVBE"; | ||
| 203 | if (caps.long_mode) | ||
| 204 | sum += ", 64-bit support"; | ||
| 205 | |||
| 206 | return sum; | ||
| 207 | } | ||
| 208 | |||
| 209 | } // namespace Common | 141 | } // namespace Common |
diff --git a/src/common/x64/cpu_detect.h b/src/common/x64/cpu_detect.h index 0af3a8adb..20f2ba234 100644 --- a/src/common/x64/cpu_detect.h +++ b/src/common/x64/cpu_detect.h | |||
| @@ -4,23 +4,12 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | ||
| 8 | |||
| 9 | namespace Common { | 7 | namespace Common { |
| 10 | 8 | ||
| 11 | /// x86/x64 CPU vendors that may be detected by this module | ||
| 12 | enum class CPUVendor { | ||
| 13 | INTEL, | ||
| 14 | AMD, | ||
| 15 | OTHER, | ||
| 16 | }; | ||
| 17 | |||
| 18 | /// x86/x64 CPU capabilities that may be detected by this module | 9 | /// x86/x64 CPU capabilities that may be detected by this module |
| 19 | struct CPUCaps { | 10 | struct CPUCaps { |
| 20 | CPUVendor vendor; | ||
| 21 | char cpu_string[0x21]; | 11 | char cpu_string[0x21]; |
| 22 | char brand_string[0x41]; | 12 | char brand_string[0x41]; |
| 23 | int num_cores; | ||
| 24 | bool sse; | 13 | bool sse; |
| 25 | bool sse2; | 14 | bool sse2; |
| 26 | bool sse3; | 15 | bool sse3; |
| @@ -35,20 +24,6 @@ struct CPUCaps { | |||
| 35 | bool fma; | 24 | bool fma; |
| 36 | bool fma4; | 25 | bool fma4; |
| 37 | bool aes; | 26 | bool aes; |
| 38 | |||
| 39 | // Support for the FXSAVE and FXRSTOR instructions | ||
| 40 | bool fxsave_fxrstor; | ||
| 41 | |||
| 42 | bool movbe; | ||
| 43 | |||
| 44 | // This flag indicates that the hardware supports some mode in which denormal inputs and outputs | ||
| 45 | // are automatically set to (signed) zero. | ||
| 46 | bool flush_to_zero; | ||
| 47 | |||
| 48 | // Support for LAHF and SAHF instructions in 64-bit mode | ||
| 49 | bool lahf_sahf_64; | ||
| 50 | |||
| 51 | bool long_mode; | ||
| 52 | }; | 27 | }; |
| 53 | 28 | ||
| 54 | /** | 29 | /** |
| @@ -57,10 +32,4 @@ struct CPUCaps { | |||
| 57 | */ | 32 | */ |
| 58 | const CPUCaps& GetCPUCaps(); | 33 | const CPUCaps& GetCPUCaps(); |
| 59 | 34 | ||
| 60 | /** | ||
| 61 | * Gets a string summary of the name and supported capabilities of the host CPU | ||
| 62 | * @return String summary | ||
| 63 | */ | ||
| 64 | std::string GetCPUCapsString(); | ||
| 65 | |||
| 66 | } // namespace Common | 35 | } // namespace Common |
diff --git a/src/core/hle/kernel/physical_memory.h b/src/core/hle/kernel/physical_memory.h index 090565310..b689e8e8b 100644 --- a/src/core/hle/kernel/physical_memory.h +++ b/src/core/hle/kernel/physical_memory.h | |||
| @@ -14,6 +14,9 @@ namespace Kernel { | |||
| 14 | // - Second to ensure all host backing memory used is aligned to 256 bytes due | 14 | // - Second to ensure all host backing memory used is aligned to 256 bytes due |
| 15 | // to strict alignment restrictions on GPU memory. | 15 | // to strict alignment restrictions on GPU memory. |
| 16 | 16 | ||
| 17 | using PhysicalMemory = std::vector<u8, Common::AlignmentAllocator<u8, 256>>; | 17 | using PhysicalMemoryVector = std::vector<u8, Common::AlignmentAllocator<u8, 256>>; |
| 18 | class PhysicalMemory final : public PhysicalMemoryVector { | ||
| 19 | using PhysicalMemoryVector::PhysicalMemoryVector; | ||
| 20 | }; | ||
| 18 | 21 | ||
| 19 | } // namespace Kernel | 22 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index a9a20ef76..0b3500fce 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <cstring> | ||
| 6 | #include <iterator> | 7 | #include <iterator> |
| 7 | #include <utility> | 8 | #include <utility> |
| 8 | #include "common/alignment.h" | 9 | #include "common/alignment.h" |
| @@ -269,18 +270,9 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) { | |||
| 269 | // If necessary, expand backing vector to cover new heap extents in | 270 | // If necessary, expand backing vector to cover new heap extents in |
| 270 | // the case of allocating. Otherwise, shrink the backing memory, | 271 | // the case of allocating. Otherwise, shrink the backing memory, |
| 271 | // if a smaller heap has been requested. | 272 | // if a smaller heap has been requested. |
| 272 | const u64 old_heap_size = GetCurrentHeapSize(); | 273 | heap_memory->resize(size); |
| 273 | if (size > old_heap_size) { | 274 | heap_memory->shrink_to_fit(); |
| 274 | const u64 alloc_size = size - old_heap_size; | 275 | RefreshMemoryBlockMappings(heap_memory.get()); |
| 275 | |||
| 276 | heap_memory->insert(heap_memory->end(), alloc_size, 0); | ||
| 277 | RefreshMemoryBlockMappings(heap_memory.get()); | ||
| 278 | } else if (size < old_heap_size) { | ||
| 279 | heap_memory->resize(size); | ||
| 280 | heap_memory->shrink_to_fit(); | ||
| 281 | |||
| 282 | RefreshMemoryBlockMappings(heap_memory.get()); | ||
| 283 | } | ||
| 284 | 276 | ||
| 285 | heap_end = heap_region_base + size; | 277 | heap_end = heap_region_base + size; |
| 286 | ASSERT(GetCurrentHeapSize() == heap_memory->size()); | 278 | ASSERT(GetCurrentHeapSize() == heap_memory->size()); |
| @@ -752,24 +744,20 @@ void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryAre | |||
| 752 | // Always merge allocated memory blocks, even when they don't share the same backing block. | 744 | // Always merge allocated memory blocks, even when they don't share the same backing block. |
| 753 | if (left.type == VMAType::AllocatedMemoryBlock && | 745 | if (left.type == VMAType::AllocatedMemoryBlock && |
| 754 | (left.backing_block != right.backing_block || left.offset + left.size != right.offset)) { | 746 | (left.backing_block != right.backing_block || left.offset + left.size != right.offset)) { |
| 755 | const auto right_begin = right.backing_block->begin() + right.offset; | ||
| 756 | const auto right_end = right_begin + right.size; | ||
| 757 | 747 | ||
| 758 | // Check if we can save work. | 748 | // Check if we can save work. |
| 759 | if (left.offset == 0 && left.size == left.backing_block->size()) { | 749 | if (left.offset == 0 && left.size == left.backing_block->size()) { |
| 760 | // Fast case: left is an entire backing block. | 750 | // Fast case: left is an entire backing block. |
| 761 | left.backing_block->insert(left.backing_block->end(), right_begin, right_end); | 751 | left.backing_block->resize(left.size + right.size); |
| 752 | std::memcpy(left.backing_block->data() + left.size, | ||
| 753 | right.backing_block->data() + right.offset, right.size); | ||
| 762 | } else { | 754 | } else { |
| 763 | // Slow case: make a new memory block for left and right. | 755 | // Slow case: make a new memory block for left and right. |
| 764 | const auto left_begin = left.backing_block->begin() + left.offset; | ||
| 765 | const auto left_end = left_begin + left.size; | ||
| 766 | const auto left_size = static_cast<std::size_t>(std::distance(left_begin, left_end)); | ||
| 767 | const auto right_size = static_cast<std::size_t>(std::distance(right_begin, right_end)); | ||
| 768 | |||
| 769 | auto new_memory = std::make_shared<PhysicalMemory>(); | 756 | auto new_memory = std::make_shared<PhysicalMemory>(); |
| 770 | new_memory->reserve(left_size + right_size); | 757 | new_memory->resize(left.size + right.size); |
| 771 | new_memory->insert(new_memory->end(), left_begin, left_end); | 758 | std::memcpy(new_memory->data(), left.backing_block->data() + left.offset, left.size); |
| 772 | new_memory->insert(new_memory->end(), right_begin, right_end); | 759 | std::memcpy(new_memory->data() + left.size, right.backing_block->data() + right.offset, |
| 760 | right.size); | ||
| 773 | 761 | ||
| 774 | left.backing_block = std::move(new_memory); | 762 | left.backing_block = std::move(new_memory); |
| 775 | left.offset = 0; | 763 | left.offset = 0; |
| @@ -792,8 +780,7 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { | |||
| 792 | memory.UnmapRegion(page_table, vma.base, vma.size); | 780 | memory.UnmapRegion(page_table, vma.base, vma.size); |
| 793 | break; | 781 | break; |
| 794 | case VMAType::AllocatedMemoryBlock: | 782 | case VMAType::AllocatedMemoryBlock: |
| 795 | memory.MapMemoryRegion(page_table, vma.base, vma.size, | 783 | memory.MapMemoryRegion(page_table, vma.base, vma.size, *vma.backing_block, vma.offset); |
| 796 | vma.backing_block->data() + vma.offset); | ||
| 797 | break; | 784 | break; |
| 798 | case VMAType::BackingMemory: | 785 | case VMAType::BackingMemory: |
| 799 | memory.MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory); | 786 | memory.MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory); |
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index f1795fdd6..8908e5328 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp | |||
| @@ -335,7 +335,8 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) { | |||
| 335 | codeset_segment->addr = segment_addr; | 335 | codeset_segment->addr = segment_addr; |
| 336 | codeset_segment->size = aligned_size; | 336 | codeset_segment->size = aligned_size; |
| 337 | 337 | ||
| 338 | memcpy(&program_image[current_image_position], GetSegmentPtr(i), p->p_filesz); | 338 | std::memcpy(program_image.data() + current_image_position, GetSegmentPtr(i), |
| 339 | p->p_filesz); | ||
| 339 | current_image_position += aligned_size; | 340 | current_image_position += aligned_size; |
| 340 | } | 341 | } |
| 341 | } | 342 | } |
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp index 474b55cb1..092103abe 100644 --- a/src/core/loader/kip.cpp +++ b/src/core/loader/kip.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cstring> | ||
| 5 | #include "core/file_sys/kernel_executable.h" | 6 | #include "core/file_sys/kernel_executable.h" |
| 6 | #include "core/file_sys/program_metadata.h" | 7 | #include "core/file_sys/program_metadata.h" |
| 7 | #include "core/gdbstub/gdbstub.h" | 8 | #include "core/gdbstub/gdbstub.h" |
| @@ -76,8 +77,8 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process) { | |||
| 76 | segment.addr = offset; | 77 | segment.addr = offset; |
| 77 | segment.offset = offset; | 78 | segment.offset = offset; |
| 78 | segment.size = PageAlignSize(static_cast<u32>(data.size())); | 79 | segment.size = PageAlignSize(static_cast<u32>(data.size())); |
| 79 | program_image.resize(offset); | 80 | program_image.resize(offset + data.size()); |
| 80 | program_image.insert(program_image.end(), data.begin(), data.end()); | 81 | std::memcpy(program_image.data() + offset, data.data(), data.size()); |
| 81 | }; | 82 | }; |
| 82 | 83 | ||
| 83 | load_segment(codeset.CodeSegment(), kip->GetTextSection(), kip->GetTextOffset()); | 84 | load_segment(codeset.CodeSegment(), kip->GetTextSection(), kip->GetTextOffset()); |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index f629892ae..515c5accb 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cinttypes> | 5 | #include <cinttypes> |
| 6 | #include <cstring> | ||
| 6 | #include <vector> | 7 | #include <vector> |
| 7 | 8 | ||
| 8 | #include "common/common_funcs.h" | 9 | #include "common/common_funcs.h" |
| @@ -96,8 +97,9 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, | |||
| 96 | if (nso_header.IsSegmentCompressed(i)) { | 97 | if (nso_header.IsSegmentCompressed(i)) { |
| 97 | data = DecompressSegment(data, nso_header.segments[i]); | 98 | data = DecompressSegment(data, nso_header.segments[i]); |
| 98 | } | 99 | } |
| 99 | program_image.resize(nso_header.segments[i].location); | 100 | program_image.resize(nso_header.segments[i].location + data.size()); |
| 100 | program_image.insert(program_image.end(), data.begin(), data.end()); | 101 | std::memcpy(program_image.data() + nso_header.segments[i].location, data.data(), |
| 102 | data.size()); | ||
| 101 | codeset.segments[i].addr = nso_header.segments[i].location; | 103 | codeset.segments[i].addr = nso_header.segments[i].location; |
| 102 | codeset.segments[i].offset = nso_header.segments[i].location; | 104 | codeset.segments[i].offset = nso_header.segments[i].location; |
| 103 | codeset.segments[i].size = PageAlignSize(static_cast<u32>(data.size())); | 105 | codeset.segments[i].size = PageAlignSize(static_cast<u32>(data.size())); |
| @@ -139,12 +141,12 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, | |||
| 139 | std::vector<u8> pi_header; | 141 | std::vector<u8> pi_header; |
| 140 | pi_header.insert(pi_header.begin(), reinterpret_cast<u8*>(&nso_header), | 142 | pi_header.insert(pi_header.begin(), reinterpret_cast<u8*>(&nso_header), |
| 141 | reinterpret_cast<u8*>(&nso_header) + sizeof(NSOHeader)); | 143 | reinterpret_cast<u8*>(&nso_header) + sizeof(NSOHeader)); |
| 142 | pi_header.insert(pi_header.begin() + sizeof(NSOHeader), program_image.begin(), | 144 | pi_header.insert(pi_header.begin() + sizeof(NSOHeader), program_image.data(), |
| 143 | program_image.end()); | 145 | program_image.data() + program_image.size()); |
| 144 | 146 | ||
| 145 | pi_header = pm->PatchNSO(pi_header, file.GetName()); | 147 | pi_header = pm->PatchNSO(pi_header, file.GetName()); |
| 146 | 148 | ||
| 147 | std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.begin()); | 149 | std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.data()); |
| 148 | } | 150 | } |
| 149 | 151 | ||
| 150 | // Apply cheats if they exist and the program has a valid title ID | 152 | // Apply cheats if they exist and the program has a valid title ID |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 3c2a29d9b..f0888327f 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "common/swap.h" | 14 | #include "common/swap.h" |
| 15 | #include "core/arm/arm_interface.h" | 15 | #include "core/arm/arm_interface.h" |
| 16 | #include "core/core.h" | 16 | #include "core/core.h" |
| 17 | #include "core/hle/kernel/physical_memory.h" | ||
| 17 | #include "core/hle/kernel/process.h" | 18 | #include "core/hle/kernel/process.h" |
| 18 | #include "core/hle/kernel/vm_manager.h" | 19 | #include "core/hle/kernel/vm_manager.h" |
| 19 | #include "core/memory.h" | 20 | #include "core/memory.h" |
| @@ -38,6 +39,11 @@ struct Memory::Impl { | |||
| 38 | system.ArmInterface(3).PageTableChanged(*current_page_table, address_space_width); | 39 | system.ArmInterface(3).PageTableChanged(*current_page_table, address_space_width); |
| 39 | } | 40 | } |
| 40 | 41 | ||
| 42 | void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 43 | Kernel::PhysicalMemory& memory, VAddr offset) { | ||
| 44 | MapMemoryRegion(page_table, base, size, memory.data() + offset); | ||
| 45 | } | ||
| 46 | |||
| 41 | void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) { | 47 | void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) { |
| 42 | ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); | 48 | ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); |
| 43 | ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); | 49 | ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); |
| @@ -601,6 +607,11 @@ void Memory::SetCurrentPageTable(Kernel::Process& process) { | |||
| 601 | impl->SetCurrentPageTable(process); | 607 | impl->SetCurrentPageTable(process); |
| 602 | } | 608 | } |
| 603 | 609 | ||
| 610 | void Memory::MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 611 | Kernel::PhysicalMemory& memory, VAddr offset) { | ||
| 612 | impl->MapMemoryRegion(page_table, base, size, memory, offset); | ||
| 613 | } | ||
| 614 | |||
| 604 | void Memory::MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) { | 615 | void Memory::MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) { |
| 605 | impl->MapMemoryRegion(page_table, base, size, target); | 616 | impl->MapMemoryRegion(page_table, base, size, target); |
| 606 | } | 617 | } |
diff --git a/src/core/memory.h b/src/core/memory.h index 1428a6d60..8913a9da4 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -19,8 +19,9 @@ class System; | |||
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | namespace Kernel { | 21 | namespace Kernel { |
| 22 | class PhysicalMemory; | ||
| 22 | class Process; | 23 | class Process; |
| 23 | } | 24 | } // namespace Kernel |
| 24 | 25 | ||
| 25 | namespace Memory { | 26 | namespace Memory { |
| 26 | 27 | ||
| @@ -66,6 +67,19 @@ public: | |||
| 66 | void SetCurrentPageTable(Kernel::Process& process); | 67 | void SetCurrentPageTable(Kernel::Process& process); |
| 67 | 68 | ||
| 68 | /** | 69 | /** |
| 70 | * Maps an physical buffer onto a region of the emulated process address space. | ||
| 71 | * | ||
| 72 | * @param page_table The page table of the emulated process. | ||
| 73 | * @param base The address to start mapping at. Must be page-aligned. | ||
| 74 | * @param size The amount of bytes to map. Must be page-aligned. | ||
| 75 | * @param memory Physical buffer with the memory backing the mapping. Must be of length | ||
| 76 | * at least `size + offset`. | ||
| 77 | * @param offset The offset within the physical memory. Must be page-aligned. | ||
| 78 | */ | ||
| 79 | void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, | ||
| 80 | Kernel::PhysicalMemory& memory, VAddr offset); | ||
| 81 | |||
| 82 | /** | ||
| 69 | * Maps an allocated buffer onto a region of the emulated process address space. | 83 | * Maps an allocated buffer onto a region of the emulated process address space. |
| 70 | * | 84 | * |
| 71 | * @param page_table The page table of the emulated process. | 85 | * @param page_table The page table of the emulated process. |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 16f95b77d..ee79260fc 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -1018,7 +1018,14 @@ public: | |||
| 1018 | } | 1018 | } |
| 1019 | } instanced_arrays; | 1019 | } instanced_arrays; |
| 1020 | 1020 | ||
| 1021 | INSERT_UNION_PADDING_WORDS(0x6); | 1021 | INSERT_UNION_PADDING_WORDS(0x4); |
| 1022 | |||
| 1023 | union { | ||
| 1024 | BitField<0, 1, u32> enable; | ||
| 1025 | BitField<4, 8, u32> unk4; | ||
| 1026 | } vp_point_size; | ||
| 1027 | |||
| 1028 | INSERT_UNION_PADDING_WORDS(1); | ||
| 1022 | 1029 | ||
| 1023 | Cull cull; | 1030 | Cull cull; |
| 1024 | 1031 | ||
| @@ -1503,6 +1510,7 @@ ASSERT_REG_POSITION(primitive_restart, 0x591); | |||
| 1503 | ASSERT_REG_POSITION(index_array, 0x5F2); | 1510 | ASSERT_REG_POSITION(index_array, 0x5F2); |
| 1504 | ASSERT_REG_POSITION(polygon_offset_clamp, 0x61F); | 1511 | ASSERT_REG_POSITION(polygon_offset_clamp, 0x61F); |
| 1505 | ASSERT_REG_POSITION(instanced_arrays, 0x620); | 1512 | ASSERT_REG_POSITION(instanced_arrays, 0x620); |
| 1513 | ASSERT_REG_POSITION(vp_point_size, 0x644); | ||
| 1506 | ASSERT_REG_POSITION(cull, 0x646); | 1514 | ASSERT_REG_POSITION(cull, 0x646); |
| 1507 | ASSERT_REG_POSITION(pixel_center_integer, 0x649); | 1515 | ASSERT_REG_POSITION(pixel_center_integer, 0x649); |
| 1508 | ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B); | 1516 | ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B); |
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 57b57c647..6f98bd827 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -215,6 +215,18 @@ enum class F2fRoundingOp : u64 { | |||
| 215 | Trunc = 11, | 215 | Trunc = 11, |
| 216 | }; | 216 | }; |
| 217 | 217 | ||
| 218 | enum class AtomicOp : u64 { | ||
| 219 | Add = 0, | ||
| 220 | Min = 1, | ||
| 221 | Max = 2, | ||
| 222 | Inc = 3, | ||
| 223 | Dec = 4, | ||
| 224 | And = 5, | ||
| 225 | Or = 6, | ||
| 226 | Xor = 7, | ||
| 227 | Exch = 8, | ||
| 228 | }; | ||
| 229 | |||
| 218 | enum class UniformType : u64 { | 230 | enum class UniformType : u64 { |
| 219 | UnsignedByte = 0, | 231 | UnsignedByte = 0, |
| 220 | SignedByte = 1, | 232 | SignedByte = 1, |
| @@ -236,6 +248,13 @@ enum class StoreType : u64 { | |||
| 236 | Bits128 = 6, | 248 | Bits128 = 6, |
| 237 | }; | 249 | }; |
| 238 | 250 | ||
| 251 | enum class AtomicType : u64 { | ||
| 252 | U32 = 0, | ||
| 253 | S32 = 1, | ||
| 254 | U64 = 2, | ||
| 255 | S64 = 3, | ||
| 256 | }; | ||
| 257 | |||
| 239 | enum class IMinMaxExchange : u64 { | 258 | enum class IMinMaxExchange : u64 { |
| 240 | None = 0, | 259 | None = 0, |
| 241 | XLo = 1, | 260 | XLo = 1, |
| @@ -939,6 +958,16 @@ union Instruction { | |||
| 939 | } stg; | 958 | } stg; |
| 940 | 959 | ||
| 941 | union { | 960 | union { |
| 961 | BitField<52, 4, AtomicOp> operation; | ||
| 962 | BitField<28, 2, AtomicType> type; | ||
| 963 | BitField<30, 22, s64> offset; | ||
| 964 | |||
| 965 | s32 GetImmediateOffset() const { | ||
| 966 | return static_cast<s32>(offset << 2); | ||
| 967 | } | ||
| 968 | } atoms; | ||
| 969 | |||
| 970 | union { | ||
| 942 | BitField<32, 1, PhysicalAttributeDirection> direction; | 971 | BitField<32, 1, PhysicalAttributeDirection> direction; |
| 943 | BitField<47, 3, AttributeSize> size; | 972 | BitField<47, 3, AttributeSize> size; |
| 944 | BitField<20, 11, u64> address; | 973 | BitField<20, 11, u64> address; |
| @@ -1659,9 +1688,10 @@ public: | |||
| 1659 | ST_A, | 1688 | ST_A, |
| 1660 | ST_L, | 1689 | ST_L, |
| 1661 | ST_S, | 1690 | ST_S, |
| 1662 | ST, // Store in generic memory | 1691 | ST, // Store in generic memory |
| 1663 | STG, // Store in global memory | 1692 | STG, // Store in global memory |
| 1664 | AL2P, // Transforms attribute memory into physical memory | 1693 | ATOMS, // Atomic operation on shared memory |
| 1694 | AL2P, // Transforms attribute memory into physical memory | ||
| 1665 | TEX, | 1695 | TEX, |
| 1666 | TEX_B, // Texture Load Bindless | 1696 | TEX_B, // Texture Load Bindless |
| 1667 | TXQ, // Texture Query | 1697 | TXQ, // Texture Query |
| @@ -1964,6 +1994,7 @@ private: | |||
| 1964 | INST("1110111101010---", Id::ST_L, Type::Memory, "ST_L"), | 1994 | INST("1110111101010---", Id::ST_L, Type::Memory, "ST_L"), |
| 1965 | INST("101-------------", Id::ST, Type::Memory, "ST"), | 1995 | INST("101-------------", Id::ST, Type::Memory, "ST"), |
| 1966 | INST("1110111011011---", Id::STG, Type::Memory, "STG"), | 1996 | INST("1110111011011---", Id::STG, Type::Memory, "STG"), |
| 1997 | INST("11101100--------", Id::ATOMS, Type::Memory, "ATOMS"), | ||
| 1967 | INST("1110111110100---", Id::AL2P, Type::Memory, "AL2P"), | 1998 | INST("1110111110100---", Id::AL2P, Type::Memory, "AL2P"), |
| 1968 | INST("110000----111---", Id::TEX, Type::Texture, "TEX"), | 1999 | INST("110000----111---", Id::TEX, Type::Texture, "TEX"), |
| 1969 | INST("1101111010111---", Id::TEX_B, Type::Texture, "TEX_B"), | 2000 | INST("1101111010111---", Id::TEX_B, Type::Texture, "TEX_B"), |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 672051102..c428f06e4 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -1272,6 +1272,7 @@ void RasterizerOpenGL::SyncPointState() { | |||
| 1272 | const auto& regs = system.GPU().Maxwell3D().regs; | 1272 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 1273 | // Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid | 1273 | // Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid |
| 1274 | // in OpenGL). | 1274 | // in OpenGL). |
| 1275 | state.point.program_control = regs.vp_point_size.enable != 0; | ||
| 1275 | state.point.size = std::max(1.0f, regs.point_size); | 1276 | state.point.size = std::max(1.0f, regs.point_size); |
| 1276 | } | 1277 | } |
| 1277 | 1278 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index e9ceca768..2996aaf08 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -1856,6 +1856,16 @@ private: | |||
| 1856 | Type::Uint}; | 1856 | Type::Uint}; |
| 1857 | } | 1857 | } |
| 1858 | 1858 | ||
| 1859 | template <const std::string_view& opname, Type type> | ||
| 1860 | Expression Atomic(Operation operation) { | ||
| 1861 | ASSERT(stage == ShaderType::Compute); | ||
| 1862 | auto& smem = std::get<SmemNode>(*operation[0]); | ||
| 1863 | |||
| 1864 | return {fmt::format("atomic{}(smem[{} >> 2], {})", opname, Visit(smem.GetAddress()).AsInt(), | ||
| 1865 | Visit(operation[1]).As(type)), | ||
| 1866 | type}; | ||
| 1867 | } | ||
| 1868 | |||
| 1859 | Expression Branch(Operation operation) { | 1869 | Expression Branch(Operation operation) { |
| 1860 | const auto target = std::get_if<ImmediateNode>(&*operation[0]); | 1870 | const auto target = std::get_if<ImmediateNode>(&*operation[0]); |
| 1861 | UNIMPLEMENTED_IF(!target); | 1871 | UNIMPLEMENTED_IF(!target); |
| @@ -2194,6 +2204,8 @@ private: | |||
| 2194 | &GLSLDecompiler::AtomicImage<Func::Xor>, | 2204 | &GLSLDecompiler::AtomicImage<Func::Xor>, |
| 2195 | &GLSLDecompiler::AtomicImage<Func::Exchange>, | 2205 | &GLSLDecompiler::AtomicImage<Func::Exchange>, |
| 2196 | 2206 | ||
| 2207 | &GLSLDecompiler::Atomic<Func::Add, Type::Uint>, | ||
| 2208 | |||
| 2197 | &GLSLDecompiler::Branch, | 2209 | &GLSLDecompiler::Branch, |
| 2198 | &GLSLDecompiler::BranchIndirect, | 2210 | &GLSLDecompiler::BranchIndirect, |
| 2199 | &GLSLDecompiler::PushFlowStack, | 2211 | &GLSLDecompiler::PushFlowStack, |
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index df2e2395a..cc185e9e1 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -127,6 +127,7 @@ void OpenGLState::ApplyClipDistances() { | |||
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | void OpenGLState::ApplyPointSize() { | 129 | void OpenGLState::ApplyPointSize() { |
| 130 | Enable(GL_PROGRAM_POINT_SIZE, cur_state.point.program_control, point.program_control); | ||
| 130 | if (UpdateValue(cur_state.point.size, point.size)) { | 131 | if (UpdateValue(cur_state.point.size, point.size)) { |
| 131 | glPointSize(point.size); | 132 | glPointSize(point.size); |
| 132 | } | 133 | } |
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index fb180f302..678e5cd89 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -131,7 +131,8 @@ public: | |||
| 131 | std::array<Viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports; | 131 | std::array<Viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports; |
| 132 | 132 | ||
| 133 | struct { | 133 | struct { |
| 134 | float size = 1.0f; // GL_POINT_SIZE | 134 | bool program_control = false; // GL_PROGRAM_POINT_SIZE |
| 135 | GLfloat size = 1.0f; // GL_POINT_SIZE | ||
| 135 | } point; | 136 | } point; |
| 136 | 137 | ||
| 137 | struct { | 138 | struct { |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index b790b0ef4..e95eb069e 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -44,7 +44,7 @@ struct FormatTuple { | |||
| 44 | 44 | ||
| 45 | constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{ | 45 | constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{ |
| 46 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // ABGR8U | 46 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // ABGR8U |
| 47 | {GL_RGBA8, GL_RGBA, GL_BYTE, false}, // ABGR8S | 47 | {GL_RGBA8_SNORM, GL_RGBA, GL_BYTE, false}, // ABGR8S |
| 48 | {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, false}, // ABGR8UI | 48 | {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, false}, // ABGR8UI |
| 49 | {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false}, // B5G6R5U | 49 | {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false}, // B5G6R5U |
| 50 | {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false}, // A2B10G10R10U | 50 | {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false}, // A2B10G10R10U |
| @@ -83,9 +83,9 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format | |||
| 83 | {GL_RGB32F, GL_RGB, GL_FLOAT, false}, // RGB32F | 83 | {GL_RGB32F, GL_RGB, GL_FLOAT, false}, // RGB32F |
| 84 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // RGBA8_SRGB | 84 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // RGBA8_SRGB |
| 85 | {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, false}, // RG8U | 85 | {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, false}, // RG8U |
| 86 | {GL_RG8, GL_RG, GL_BYTE, false}, // RG8S | 86 | {GL_RG8_SNORM, GL_RG, GL_BYTE, false}, // RG8S |
| 87 | {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, false}, // RG32UI | 87 | {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, false}, // RG32UI |
| 88 | {GL_RGB16F, GL_RGBA16, GL_HALF_FLOAT, false}, // RGBX16F | 88 | {GL_RGB16F, GL_RGBA, GL_HALF_FLOAT, false}, // RGBX16F |
| 89 | {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, false}, // R32UI | 89 | {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, false}, // R32UI |
| 90 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_8X8 | 90 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_8X8 |
| 91 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_8X5 | 91 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false}, // ASTC_2D_8X5 |
| @@ -253,14 +253,12 @@ void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) { | |||
| 253 | glPixelStorei(GL_PACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level))); | 253 | glPixelStorei(GL_PACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level))); |
| 254 | glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); | 254 | glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level))); |
| 255 | const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level); | 255 | const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level); |
| 256 | u8* const mip_data = staging_buffer.data() + mip_offset; | ||
| 257 | const GLsizei size = static_cast<GLsizei>(params.GetHostMipmapSize(level)); | ||
| 256 | if (is_compressed) { | 258 | if (is_compressed) { |
| 257 | glGetCompressedTextureImage(texture.handle, level, | 259 | glGetCompressedTextureImage(texture.handle, level, size, mip_data); |
| 258 | static_cast<GLsizei>(params.GetHostMipmapSize(level)), | ||
| 259 | staging_buffer.data() + mip_offset); | ||
| 260 | } else { | 260 | } else { |
| 261 | glGetTextureImage(texture.handle, level, format, type, | 261 | glGetTextureImage(texture.handle, level, format, type, size, mip_data); |
| 262 | static_cast<GLsizei>(params.GetHostMipmapSize(level)), | ||
| 263 | staging_buffer.data() + mip_offset); | ||
| 264 | } | 262 | } |
| 265 | } | 263 | } |
| 266 | } | 264 | } |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 8fe852ce8..0cf97cafa 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -1796,6 +1796,11 @@ private: | |||
| 1796 | return {}; | 1796 | return {}; |
| 1797 | } | 1797 | } |
| 1798 | 1798 | ||
| 1799 | Expression UAtomicAdd(Operation) { | ||
| 1800 | UNIMPLEMENTED(); | ||
| 1801 | return {}; | ||
| 1802 | } | ||
| 1803 | |||
| 1799 | Expression Branch(Operation operation) { | 1804 | Expression Branch(Operation operation) { |
| 1800 | const auto& target = std::get<ImmediateNode>(*operation[0]); | 1805 | const auto& target = std::get<ImmediateNode>(*operation[0]); |
| 1801 | OpStore(jmp_to, Constant(t_uint, target.GetValue())); | 1806 | OpStore(jmp_to, Constant(t_uint, target.GetValue())); |
| @@ -2373,6 +2378,8 @@ private: | |||
| 2373 | &SPIRVDecompiler::AtomicImageXor, | 2378 | &SPIRVDecompiler::AtomicImageXor, |
| 2374 | &SPIRVDecompiler::AtomicImageExchange, | 2379 | &SPIRVDecompiler::AtomicImageExchange, |
| 2375 | 2380 | ||
| 2381 | &SPIRVDecompiler::UAtomicAdd, | ||
| 2382 | |||
| 2376 | &SPIRVDecompiler::Branch, | 2383 | &SPIRVDecompiler::Branch, |
| 2377 | &SPIRVDecompiler::BranchIndirect, | 2384 | &SPIRVDecompiler::BranchIndirect, |
| 2378 | &SPIRVDecompiler::PushFlowStack, | 2385 | &SPIRVDecompiler::PushFlowStack, |
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp index 8cc84e935..7591a715f 100644 --- a/src/video_core/shader/decode/memory.cpp +++ b/src/video_core/shader/decode/memory.cpp | |||
| @@ -16,6 +16,8 @@ | |||
| 16 | 16 | ||
| 17 | namespace VideoCommon::Shader { | 17 | namespace VideoCommon::Shader { |
| 18 | 18 | ||
| 19 | using Tegra::Shader::AtomicOp; | ||
| 20 | using Tegra::Shader::AtomicType; | ||
| 19 | using Tegra::Shader::Attribute; | 21 | using Tegra::Shader::Attribute; |
| 20 | using Tegra::Shader::Instruction; | 22 | using Tegra::Shader::Instruction; |
| 21 | using Tegra::Shader::OpCode; | 23 | using Tegra::Shader::OpCode; |
| @@ -333,6 +335,23 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 333 | } | 335 | } |
| 334 | break; | 336 | break; |
| 335 | } | 337 | } |
| 338 | case OpCode::Id::ATOMS: { | ||
| 339 | UNIMPLEMENTED_IF_MSG(instr.atoms.operation != AtomicOp::Add, "operation={}", | ||
| 340 | static_cast<int>(instr.atoms.operation.Value())); | ||
| 341 | UNIMPLEMENTED_IF_MSG(instr.atoms.type != AtomicType::U32, "type={}", | ||
| 342 | static_cast<int>(instr.atoms.type.Value())); | ||
| 343 | |||
| 344 | const s32 offset = instr.atoms.GetImmediateOffset(); | ||
| 345 | Node address = GetRegister(instr.gpr8); | ||
| 346 | address = Operation(OperationCode::IAdd, std::move(address), Immediate(offset)); | ||
| 347 | |||
| 348 | Node memory = GetSharedMemory(std::move(address)); | ||
| 349 | Node data = GetRegister(instr.gpr20); | ||
| 350 | |||
| 351 | Node value = Operation(OperationCode::UAtomicAdd, std::move(memory), std::move(data)); | ||
| 352 | SetRegister(bb, instr.gpr0, std::move(value)); | ||
| 353 | break; | ||
| 354 | } | ||
| 336 | case OpCode::Id::AL2P: { | 355 | case OpCode::Id::AL2P: { |
| 337 | // Ignore al2p.direction since we don't care about it. | 356 | // Ignore al2p.direction since we don't care about it. |
| 338 | 357 | ||
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h index 4e155542a..075c7d07c 100644 --- a/src/video_core/shader/node.h +++ b/src/video_core/shader/node.h | |||
| @@ -162,6 +162,8 @@ enum class OperationCode { | |||
| 162 | AtomicImageXor, /// (MetaImage, int[N] coords) -> void | 162 | AtomicImageXor, /// (MetaImage, int[N] coords) -> void |
| 163 | AtomicImageExchange, /// (MetaImage, int[N] coords) -> void | 163 | AtomicImageExchange, /// (MetaImage, int[N] coords) -> void |
| 164 | 164 | ||
| 165 | UAtomicAdd, /// (smem, uint) -> uint | ||
| 166 | |||
| 165 | Branch, /// (uint branch_target) -> void | 167 | Branch, /// (uint branch_target) -> void |
| 166 | BranchIndirect, /// (uint branch_target) -> void | 168 | BranchIndirect, /// (uint branch_target) -> void |
| 167 | PushFlowStack, /// (uint branch_target) -> void | 169 | PushFlowStack, /// (uint branch_target) -> void |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index b21fbf826..b5dd3e0d6 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -526,19 +526,30 @@ void GMainWindow::InitializeHotkeys() { | |||
| 526 | 526 | ||
| 527 | const QString main_window = QStringLiteral("Main Window"); | 527 | const QString main_window = QStringLiteral("Main Window"); |
| 528 | const QString load_file = QStringLiteral("Load File"); | 528 | const QString load_file = QStringLiteral("Load File"); |
| 529 | const QString load_amiibo = QStringLiteral("Load Amiibo"); | ||
| 529 | const QString exit_yuzu = QStringLiteral("Exit yuzu"); | 530 | const QString exit_yuzu = QStringLiteral("Exit yuzu"); |
| 531 | const QString restart_emulation = QStringLiteral("Restart Emulation"); | ||
| 530 | const QString stop_emulation = QStringLiteral("Stop Emulation"); | 532 | const QString stop_emulation = QStringLiteral("Stop Emulation"); |
| 531 | const QString toggle_filter_bar = QStringLiteral("Toggle Filter Bar"); | 533 | const QString toggle_filter_bar = QStringLiteral("Toggle Filter Bar"); |
| 532 | const QString toggle_status_bar = QStringLiteral("Toggle Status Bar"); | 534 | const QString toggle_status_bar = QStringLiteral("Toggle Status Bar"); |
| 533 | const QString fullscreen = QStringLiteral("Fullscreen"); | 535 | const QString fullscreen = QStringLiteral("Fullscreen"); |
| 536 | const QString capture_screenshot = QStringLiteral("Capture Screenshot"); | ||
| 534 | 537 | ||
| 535 | ui.action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file)); | 538 | ui.action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file)); |
| 536 | ui.action_Load_File->setShortcutContext( | 539 | ui.action_Load_File->setShortcutContext( |
| 537 | hotkey_registry.GetShortcutContext(main_window, load_file)); | 540 | hotkey_registry.GetShortcutContext(main_window, load_file)); |
| 538 | 541 | ||
| 542 | ui.action_Load_Amiibo->setShortcut(hotkey_registry.GetKeySequence(main_window, load_amiibo)); | ||
| 543 | ui.action_Load_Amiibo->setShortcutContext( | ||
| 544 | hotkey_registry.GetShortcutContext(main_window, load_amiibo)); | ||
| 545 | |||
| 539 | ui.action_Exit->setShortcut(hotkey_registry.GetKeySequence(main_window, exit_yuzu)); | 546 | ui.action_Exit->setShortcut(hotkey_registry.GetKeySequence(main_window, exit_yuzu)); |
| 540 | ui.action_Exit->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, exit_yuzu)); | 547 | ui.action_Exit->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, exit_yuzu)); |
| 541 | 548 | ||
| 549 | ui.action_Restart->setShortcut(hotkey_registry.GetKeySequence(main_window, restart_emulation)); | ||
| 550 | ui.action_Restart->setShortcutContext( | ||
| 551 | hotkey_registry.GetShortcutContext(main_window, restart_emulation)); | ||
| 552 | |||
| 542 | ui.action_Stop->setShortcut(hotkey_registry.GetKeySequence(main_window, stop_emulation)); | 553 | ui.action_Stop->setShortcut(hotkey_registry.GetKeySequence(main_window, stop_emulation)); |
| 543 | ui.action_Stop->setShortcutContext( | 554 | ui.action_Stop->setShortcutContext( |
| 544 | hotkey_registry.GetShortcutContext(main_window, stop_emulation)); | 555 | hotkey_registry.GetShortcutContext(main_window, stop_emulation)); |
| @@ -553,6 +564,11 @@ void GMainWindow::InitializeHotkeys() { | |||
| 553 | ui.action_Show_Status_Bar->setShortcutContext( | 564 | ui.action_Show_Status_Bar->setShortcutContext( |
| 554 | hotkey_registry.GetShortcutContext(main_window, toggle_status_bar)); | 565 | hotkey_registry.GetShortcutContext(main_window, toggle_status_bar)); |
| 555 | 566 | ||
| 567 | ui.action_Capture_Screenshot->setShortcut( | ||
| 568 | hotkey_registry.GetKeySequence(main_window, capture_screenshot)); | ||
| 569 | ui.action_Capture_Screenshot->setShortcutContext( | ||
| 570 | hotkey_registry.GetShortcutContext(main_window, capture_screenshot)); | ||
| 571 | |||
| 556 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this), | 572 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this), |
| 557 | &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile); | 573 | &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile); |
| 558 | connect( | 574 | connect( |
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index 21f422500..a2c9e4547 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | </property> | 15 | </property> |
| 16 | <property name="windowIcon"> | 16 | <property name="windowIcon"> |
| 17 | <iconset> | 17 | <iconset> |
| 18 | <normaloff>src/pcafe/res/icon3_64x64.ico</normaloff>src/pcafe/res/icon3_64x64.ico</iconset> | 18 | <normaloff>../dist/yuzu.ico</normaloff>../dist/yuzu.ico</iconset> |
| 19 | </property> | 19 | </property> |
| 20 | <property name="tabShape"> | 20 | <property name="tabShape"> |
| 21 | <enum>QTabWidget::Rounded</enum> | 21 | <enum>QTabWidget::Rounded</enum> |
| @@ -98,6 +98,7 @@ | |||
| 98 | <addaction name="action_Display_Dock_Widget_Headers"/> | 98 | <addaction name="action_Display_Dock_Widget_Headers"/> |
| 99 | <addaction name="action_Show_Filter_Bar"/> | 99 | <addaction name="action_Show_Filter_Bar"/> |
| 100 | <addaction name="action_Show_Status_Bar"/> | 100 | <addaction name="action_Show_Status_Bar"/> |
| 101 | <addaction name="separator"/> | ||
| 101 | <addaction name="menu_View_Debugging"/> | 102 | <addaction name="menu_View_Debugging"/> |
| 102 | </widget> | 103 | </widget> |
| 103 | <widget class="QMenu" name="menu_Tools"> | 104 | <widget class="QMenu" name="menu_Tools"> |