diff options
Diffstat (limited to 'src')
28 files changed, 571 insertions, 216 deletions
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 16d528994..59da33f30 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -22,10 +22,16 @@ public: | |||
| 22 | std::array<u64, 31> cpu_registers; | 22 | std::array<u64, 31> cpu_registers; |
| 23 | u64 sp; | 23 | u64 sp; |
| 24 | u64 pc; | 24 | u64 pc; |
| 25 | u64 pstate; | 25 | u32 pstate; |
| 26 | std::array<u8, 4> padding; | ||
| 26 | std::array<u128, 32> vector_registers; | 27 | std::array<u128, 32> vector_registers; |
| 27 | u64 fpcr; | 28 | u32 fpcr; |
| 29 | u32 fpsr; | ||
| 30 | u64 tpidr; | ||
| 28 | }; | 31 | }; |
| 32 | // Internally within the kernel, it expects the AArch64 version of the | ||
| 33 | // thread context to be 800 bytes in size. | ||
| 34 | static_assert(sizeof(ThreadContext) == 0x320); | ||
| 29 | 35 | ||
| 30 | /// Runs the CPU until an event happens | 36 | /// Runs the CPU until an event happens |
| 31 | virtual void Run() = 0; | 37 | virtual void Run() = 0; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 8cad070b4..05cc84458 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp | |||
| @@ -130,7 +130,7 @@ public: | |||
| 130 | 130 | ||
| 131 | std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const { | 131 | std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const { |
| 132 | auto& current_process = Core::CurrentProcess(); | 132 | auto& current_process = Core::CurrentProcess(); |
| 133 | auto** const page_table = current_process->vm_manager.page_table.pointers.data(); | 133 | auto** const page_table = current_process->VMManager().page_table.pointers.data(); |
| 134 | 134 | ||
| 135 | Dynarmic::A64::UserConfig config; | 135 | Dynarmic::A64::UserConfig config; |
| 136 | 136 | ||
| @@ -139,7 +139,7 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const { | |||
| 139 | 139 | ||
| 140 | // Memory | 140 | // Memory |
| 141 | config.page_table = reinterpret_cast<void**>(page_table); | 141 | config.page_table = reinterpret_cast<void**>(page_table); |
| 142 | config.page_table_address_space_bits = current_process->vm_manager.GetAddressSpaceWidth(); | 142 | config.page_table_address_space_bits = current_process->VMManager().GetAddressSpaceWidth(); |
| 143 | config.silently_mirror_page_table = false; | 143 | config.silently_mirror_page_table = false; |
| 144 | 144 | ||
| 145 | // Multi-process state | 145 | // Multi-process state |
| @@ -247,15 +247,19 @@ void ARM_Dynarmic::SaveContext(ThreadContext& ctx) { | |||
| 247 | ctx.pstate = jit->GetPstate(); | 247 | ctx.pstate = jit->GetPstate(); |
| 248 | ctx.vector_registers = jit->GetVectors(); | 248 | ctx.vector_registers = jit->GetVectors(); |
| 249 | ctx.fpcr = jit->GetFpcr(); | 249 | ctx.fpcr = jit->GetFpcr(); |
| 250 | ctx.fpsr = jit->GetFpsr(); | ||
| 251 | ctx.tpidr = cb->tpidr_el0; | ||
| 250 | } | 252 | } |
| 251 | 253 | ||
| 252 | void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { | 254 | void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { |
| 253 | jit->SetRegisters(ctx.cpu_registers); | 255 | jit->SetRegisters(ctx.cpu_registers); |
| 254 | jit->SetSP(ctx.sp); | 256 | jit->SetSP(ctx.sp); |
| 255 | jit->SetPC(ctx.pc); | 257 | jit->SetPC(ctx.pc); |
| 256 | jit->SetPstate(static_cast<u32>(ctx.pstate)); | 258 | jit->SetPstate(ctx.pstate); |
| 257 | jit->SetVectors(ctx.vector_registers); | 259 | jit->SetVectors(ctx.vector_registers); |
| 258 | jit->SetFpcr(static_cast<u32>(ctx.fpcr)); | 260 | jit->SetFpcr(ctx.fpcr); |
| 261 | jit->SetFpsr(ctx.fpsr); | ||
| 262 | SetTPIDR_EL0(ctx.tpidr); | ||
| 259 | } | 263 | } |
| 260 | 264 | ||
| 261 | void ARM_Dynarmic::PrepareReschedule() { | 265 | void ARM_Dynarmic::PrepareReschedule() { |
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index 3d1a3685e..d027a8d59 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp | |||
| @@ -34,7 +34,7 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() { | |||
| 34 | if (!updatable) | 34 | if (!updatable) |
| 35 | return MakeResult<VirtualFile>(file); | 35 | return MakeResult<VirtualFile>(file); |
| 36 | 36 | ||
| 37 | const PatchManager patch_manager(Core::CurrentProcess()->program_id); | 37 | const PatchManager patch_manager(Core::CurrentProcess()->GetTitleID()); |
| 38 | return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset)); | 38 | return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset)); |
| 39 | } | 39 | } |
| 40 | 40 | ||
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 9b2c51bbd..47f2ab9e0 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp | |||
| @@ -81,7 +81,7 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ | |||
| 81 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should | 81 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should |
| 82 | // be interpreted as the title id of the current process. | 82 | // be interpreted as the title id of the current process. |
| 83 | if (type == SaveDataType::SaveData && title_id == 0) | 83 | if (type == SaveDataType::SaveData && title_id == 0) |
| 84 | title_id = Core::CurrentProcess()->program_id; | 84 | title_id = Core::CurrentProcess()->GetTitleID(); |
| 85 | 85 | ||
| 86 | std::string out; | 86 | std::string out; |
| 87 | 87 | ||
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index d8c7b3492..5bc947010 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp | |||
| @@ -250,7 +250,7 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr) | |||
| 250 | } else if (id == PC_REGISTER) { | 250 | } else if (id == PC_REGISTER) { |
| 251 | thread->context.pc = val; | 251 | thread->context.pc = val; |
| 252 | } else if (id == PSTATE_REGISTER) { | 252 | } else if (id == PSTATE_REGISTER) { |
| 253 | thread->context.pstate = val; | 253 | thread->context.pstate = static_cast<u32>(val); |
| 254 | } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) { | 254 | } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) { |
| 255 | thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val; | 255 | thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val; |
| 256 | } | 256 | } |
| @@ -587,7 +587,7 @@ static void HandleQuery() { | |||
| 587 | strlen("Xfer:features:read:target.xml:")) == 0) { | 587 | strlen("Xfer:features:read:target.xml:")) == 0) { |
| 588 | SendReply(target_xml); | 588 | SendReply(target_xml); |
| 589 | } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { | 589 | } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { |
| 590 | const VAddr base_address = Core::CurrentProcess()->vm_manager.GetCodeRegionBaseAddress(); | 590 | const VAddr base_address = Core::CurrentProcess()->VMManager().GetCodeRegionBaseAddress(); |
| 591 | std::string buffer = fmt::format("TextSeg={:0x}", base_address); | 591 | std::string buffer = fmt::format("TextSeg={:0x}", base_address); |
| 592 | SendReply(buffer.c_str()); | 592 | SendReply(buffer.c_str()); |
| 593 | } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { | 593 | } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { |
| @@ -909,7 +909,7 @@ static void ReadMemory() { | |||
| 909 | SendReply("E01"); | 909 | SendReply("E01"); |
| 910 | } | 910 | } |
| 911 | 911 | ||
| 912 | const auto& vm_manager = Core::CurrentProcess()->vm_manager; | 912 | const auto& vm_manager = Core::CurrentProcess()->VMManager(); |
| 913 | if (addr < vm_manager.GetCodeRegionBaseAddress() || | 913 | if (addr < vm_manager.GetCodeRegionBaseAddress() || |
| 914 | addr >= vm_manager.GetMapRegionEndAddress()) { | 914 | addr >= vm_manager.GetMapRegionEndAddress()) { |
| 915 | return SendReply("E00"); | 915 | return SendReply("E00"); |
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index 8c2be2681..e5fa67ae8 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h | |||
| @@ -31,6 +31,7 @@ enum { | |||
| 31 | TooLarge = 119, | 31 | TooLarge = 119, |
| 32 | InvalidEnumValue = 120, | 32 | InvalidEnumValue = 120, |
| 33 | NoSuchEntry = 121, | 33 | NoSuchEntry = 121, |
| 34 | AlreadyRegistered = 122, | ||
| 34 | InvalidState = 125, | 35 | InvalidState = 125, |
| 35 | ResourceLimitExceeded = 132, | 36 | ResourceLimitExceeded = 132, |
| 36 | }; | 37 | }; |
| @@ -58,6 +59,7 @@ constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, | |||
| 58 | constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); | 59 | constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); |
| 59 | constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); | 60 | constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); |
| 60 | constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); | 61 | constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); |
| 62 | constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::Kernel, ErrCodes::AlreadyRegistered); | ||
| 61 | constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); | 63 | constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); |
| 62 | constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel, | 64 | constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel, |
| 63 | ErrCodes::InvalidThreadPriority); | 65 | ErrCodes::InvalidThreadPriority); |
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index a8e3098ca..dc9fc8470 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -47,6 +47,7 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { | |||
| 47 | 47 | ||
| 48 | void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { | 48 | void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { |
| 49 | program_id = metadata.GetTitleID(); | 49 | program_id = metadata.GetTitleID(); |
| 50 | is_64bit_process = metadata.Is64BitProgram(); | ||
| 50 | vm_manager.Reset(metadata.GetAddressSpaceType()); | 51 | vm_manager.Reset(metadata.GetAddressSpaceType()); |
| 51 | } | 52 | } |
| 52 | 53 | ||
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index adb03c228..590e0c73d 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -135,6 +135,16 @@ public: | |||
| 135 | return HANDLE_TYPE; | 135 | return HANDLE_TYPE; |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | /// Gets a reference to the process' memory manager. | ||
| 139 | Kernel::VMManager& VMManager() { | ||
| 140 | return vm_manager; | ||
| 141 | } | ||
| 142 | |||
| 143 | /// Gets a const reference to the process' memory manager. | ||
| 144 | const Kernel::VMManager& VMManager() const { | ||
| 145 | return vm_manager; | ||
| 146 | } | ||
| 147 | |||
| 138 | /// Gets the current status of the process | 148 | /// Gets the current status of the process |
| 139 | ProcessStatus GetStatus() const { | 149 | ProcessStatus GetStatus() const { |
| 140 | return status; | 150 | return status; |
| @@ -145,6 +155,45 @@ public: | |||
| 145 | return process_id; | 155 | return process_id; |
| 146 | } | 156 | } |
| 147 | 157 | ||
| 158 | /// Gets the title ID corresponding to this process. | ||
| 159 | u64 GetTitleID() const { | ||
| 160 | return program_id; | ||
| 161 | } | ||
| 162 | |||
| 163 | /// Gets the resource limit descriptor for this process | ||
| 164 | ResourceLimit& GetResourceLimit() { | ||
| 165 | return *resource_limit; | ||
| 166 | } | ||
| 167 | |||
| 168 | /// Gets the resource limit descriptor for this process | ||
| 169 | const ResourceLimit& GetResourceLimit() const { | ||
| 170 | return *resource_limit; | ||
| 171 | } | ||
| 172 | |||
| 173 | /// Gets the default CPU ID for this process | ||
| 174 | u8 GetDefaultProcessorID() const { | ||
| 175 | return ideal_processor; | ||
| 176 | } | ||
| 177 | |||
| 178 | /// Gets the bitmask of allowed CPUs that this process' threads can run on. | ||
| 179 | u32 GetAllowedProcessorMask() const { | ||
| 180 | return allowed_processor_mask; | ||
| 181 | } | ||
| 182 | |||
| 183 | /// Gets the bitmask of allowed thread priorities. | ||
| 184 | u32 GetAllowedThreadPriorityMask() const { | ||
| 185 | return allowed_thread_priority_mask; | ||
| 186 | } | ||
| 187 | |||
| 188 | u32 IsVirtualMemoryEnabled() const { | ||
| 189 | return is_virtual_address_memory_enabled; | ||
| 190 | } | ||
| 191 | |||
| 192 | /// Whether this process is an AArch64 or AArch32 process. | ||
| 193 | bool Is64BitProcess() const { | ||
| 194 | return is_64bit_process; | ||
| 195 | } | ||
| 196 | |||
| 148 | /** | 197 | /** |
| 149 | * Loads process-specifics configuration info with metadata provided | 198 | * Loads process-specifics configuration info with metadata provided |
| 150 | * by an executable. | 199 | * by an executable. |
| @@ -153,30 +202,6 @@ public: | |||
| 153 | */ | 202 | */ |
| 154 | void LoadFromMetadata(const FileSys::ProgramMetadata& metadata); | 203 | void LoadFromMetadata(const FileSys::ProgramMetadata& metadata); |
| 155 | 204 | ||
| 156 | /// Title ID corresponding to the process | ||
| 157 | u64 program_id; | ||
| 158 | |||
| 159 | /// Resource limit descriptor for this process | ||
| 160 | SharedPtr<ResourceLimit> resource_limit; | ||
| 161 | |||
| 162 | /// The process may only call SVCs which have the corresponding bit set. | ||
| 163 | std::bitset<0x80> svc_access_mask; | ||
| 164 | /// Maximum size of the handle table for the process. | ||
| 165 | unsigned int handle_table_size = 0x200; | ||
| 166 | /// Special memory ranges mapped into this processes address space. This is used to give | ||
| 167 | /// processes access to specific I/O regions and device memory. | ||
| 168 | boost::container::static_vector<AddressMapping, 8> address_mappings; | ||
| 169 | ProcessFlags flags; | ||
| 170 | /// Kernel compatibility version for this process | ||
| 171 | u16 kernel_version = 0; | ||
| 172 | /// The default CPU for this process, threads are scheduled on this cpu by default. | ||
| 173 | u8 ideal_processor = 0; | ||
| 174 | /// Bitmask of allowed CPUs that this process' threads can run on. TODO(Subv): Actually parse | ||
| 175 | /// this value from the process header. | ||
| 176 | u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK; | ||
| 177 | u32 allowed_thread_priority_mask = 0xFFFFFFFF; | ||
| 178 | u32 is_virtual_address_memory_enabled = 0; | ||
| 179 | |||
| 180 | /** | 205 | /** |
| 181 | * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them | 206 | * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them |
| 182 | * to this process. | 207 | * to this process. |
| @@ -212,18 +237,43 @@ public: | |||
| 212 | 237 | ||
| 213 | ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); | 238 | ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); |
| 214 | 239 | ||
| 215 | VMManager vm_manager; | ||
| 216 | |||
| 217 | private: | 240 | private: |
| 218 | explicit Process(KernelCore& kernel); | 241 | explicit Process(KernelCore& kernel); |
| 219 | ~Process() override; | 242 | ~Process() override; |
| 220 | 243 | ||
| 244 | /// Memory manager for this process. | ||
| 245 | Kernel::VMManager vm_manager; | ||
| 246 | |||
| 221 | /// Current status of the process | 247 | /// Current status of the process |
| 222 | ProcessStatus status; | 248 | ProcessStatus status; |
| 223 | 249 | ||
| 224 | /// The ID of this process | 250 | /// The ID of this process |
| 225 | u32 process_id = 0; | 251 | u32 process_id = 0; |
| 226 | 252 | ||
| 253 | /// Title ID corresponding to the process | ||
| 254 | u64 program_id; | ||
| 255 | |||
| 256 | /// Resource limit descriptor for this process | ||
| 257 | SharedPtr<ResourceLimit> resource_limit; | ||
| 258 | |||
| 259 | /// The process may only call SVCs which have the corresponding bit set. | ||
| 260 | std::bitset<0x80> svc_access_mask; | ||
| 261 | /// Maximum size of the handle table for the process. | ||
| 262 | u32 handle_table_size = 0x200; | ||
| 263 | /// Special memory ranges mapped into this processes address space. This is used to give | ||
| 264 | /// processes access to specific I/O regions and device memory. | ||
| 265 | boost::container::static_vector<AddressMapping, 8> address_mappings; | ||
| 266 | ProcessFlags flags; | ||
| 267 | /// Kernel compatibility version for this process | ||
| 268 | u16 kernel_version = 0; | ||
| 269 | /// The default CPU for this process, threads are scheduled on this cpu by default. | ||
| 270 | u8 ideal_processor = 0; | ||
| 271 | /// Bitmask of allowed CPUs that this process' threads can run on. TODO(Subv): Actually parse | ||
| 272 | /// this value from the process header. | ||
| 273 | u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK; | ||
| 274 | u32 allowed_thread_priority_mask = 0xFFFFFFFF; | ||
| 275 | u32 is_virtual_address_memory_enabled = 0; | ||
| 276 | |||
| 227 | // Memory used to back the allocations in the regular heap. A single vector is used to cover | 277 | // Memory used to back the allocations in the regular heap. A single vector is used to cover |
| 228 | // the entire virtual address space extents that bound the allocations, including any holes. | 278 | // the entire virtual address space extents that bound the allocations, including any holes. |
| 229 | // This makes deallocation and reallocation of holes fast and keeps process memory contiguous | 279 | // This makes deallocation and reallocation of holes fast and keeps process memory contiguous |
| @@ -242,6 +292,11 @@ private: | |||
| 242 | /// This vector will grow as more pages are allocated for new threads. | 292 | /// This vector will grow as more pages are allocated for new threads. |
| 243 | std::vector<std::bitset<8>> tls_slots; | 293 | std::vector<std::bitset<8>> tls_slots; |
| 244 | 294 | ||
| 295 | /// Whether or not this process is AArch64, or AArch32. | ||
| 296 | /// By default, we currently assume this is true, unless otherwise | ||
| 297 | /// specified by metadata provided to the process during loading. | ||
| 298 | bool is_64bit_process = true; | ||
| 299 | |||
| 245 | std::string name; | 300 | std::string name; |
| 246 | }; | 301 | }; |
| 247 | 302 | ||
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 9faf903cf..1e82cfffb 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp | |||
| @@ -88,7 +88,7 @@ void Scheduler::SwitchContext(Thread* new_thread) { | |||
| 88 | 88 | ||
| 89 | if (previous_process != current_thread->owner_process) { | 89 | if (previous_process != current_thread->owner_process) { |
| 90 | Core::CurrentProcess() = current_thread->owner_process; | 90 | Core::CurrentProcess() = current_thread->owner_process; |
| 91 | SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table); | 91 | SetCurrentPageTable(&Core::CurrentProcess()->VMManager().page_table); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | cpu_core.LoadContext(new_thread->context); | 94 | cpu_core.LoadContext(new_thread->context); |
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 9b78c8cb5..d061e6155 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -35,11 +35,11 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, SharedPtr<Proce | |||
| 35 | 35 | ||
| 36 | // Refresh the address mappings for the current process. | 36 | // Refresh the address mappings for the current process. |
| 37 | if (Core::CurrentProcess() != nullptr) { | 37 | if (Core::CurrentProcess() != nullptr) { |
| 38 | Core::CurrentProcess()->vm_manager.RefreshMemoryBlockMappings( | 38 | Core::CurrentProcess()->VMManager().RefreshMemoryBlockMappings( |
| 39 | shared_memory->backing_block.get()); | 39 | shared_memory->backing_block.get()); |
| 40 | } | 40 | } |
| 41 | } else { | 41 | } else { |
| 42 | auto& vm_manager = shared_memory->owner_process->vm_manager; | 42 | auto& vm_manager = shared_memory->owner_process->VMManager(); |
| 43 | 43 | ||
| 44 | // The memory is already available and mapped in the owner process. | 44 | // The memory is already available and mapped in the owner process. |
| 45 | auto vma = vm_manager.FindVMA(address); | 45 | auto vma = vm_manager.FindVMA(address); |
| @@ -73,7 +73,7 @@ SharedPtr<SharedMemory> SharedMemory::CreateForApplet( | |||
| 73 | shared_memory->backing_block = std::move(heap_block); | 73 | shared_memory->backing_block = std::move(heap_block); |
| 74 | shared_memory->backing_block_offset = offset; | 74 | shared_memory->backing_block_offset = offset; |
| 75 | shared_memory->base_address = | 75 | shared_memory->base_address = |
| 76 | kernel.CurrentProcess()->vm_manager.GetHeapRegionBaseAddress() + offset; | 76 | kernel.CurrentProcess()->VMManager().GetHeapRegionBaseAddress() + offset; |
| 77 | 77 | ||
| 78 | return shared_memory; | 78 | return shared_memory; |
| 79 | } | 79 | } |
| @@ -107,7 +107,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 107 | VAddr target_address = address; | 107 | VAddr target_address = address; |
| 108 | 108 | ||
| 109 | // Map the memory block into the target process | 109 | // Map the memory block into the target process |
| 110 | auto result = target_process->vm_manager.MapMemoryBlock( | 110 | auto result = target_process->VMManager().MapMemoryBlock( |
| 111 | target_address, backing_block, backing_block_offset, size, MemoryState::Shared); | 111 | target_address, backing_block, backing_block_offset, size, MemoryState::Shared); |
| 112 | if (result.Failed()) { | 112 | if (result.Failed()) { |
| 113 | LOG_ERROR( | 113 | LOG_ERROR( |
| @@ -117,14 +117,14 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 117 | return result.Code(); | 117 | return result.Code(); |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | return target_process->vm_manager.ReprotectRange(target_address, size, | 120 | return target_process->VMManager().ReprotectRange(target_address, size, |
| 121 | ConvertPermissions(permissions)); | 121 | ConvertPermissions(permissions)); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { | 124 | ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { |
| 125 | // TODO(Subv): Verify what happens if the application tries to unmap an address that is not | 125 | // TODO(Subv): Verify what happens if the application tries to unmap an address that is not |
| 126 | // mapped to a SharedMemory. | 126 | // mapped to a SharedMemory. |
| 127 | return target_process->vm_manager.UnmapRange(address, size); | 127 | return target_process->VMManager().UnmapRange(address, size); |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { | 130 | VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 44bbaf0c8..1cdaa740a 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -51,7 +51,7 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { | |||
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | auto& process = *Core::CurrentProcess(); | 53 | auto& process = *Core::CurrentProcess(); |
| 54 | const VAddr heap_base = process.vm_manager.GetHeapRegionBaseAddress(); | 54 | const VAddr heap_base = process.VMManager().GetHeapRegionBaseAddress(); |
| 55 | CASCADE_RESULT(*heap_addr, | 55 | CASCADE_RESULT(*heap_addr, |
| 56 | process.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite)); | 56 | process.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite)); |
| 57 | return RESULT_SUCCESS; | 57 | return RESULT_SUCCESS; |
| @@ -327,14 +327,14 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 327 | info_sub_id, handle); | 327 | info_sub_id, handle); |
| 328 | 328 | ||
| 329 | const auto& current_process = Core::CurrentProcess(); | 329 | const auto& current_process = Core::CurrentProcess(); |
| 330 | const auto& vm_manager = current_process->vm_manager; | 330 | const auto& vm_manager = current_process->VMManager(); |
| 331 | 331 | ||
| 332 | switch (static_cast<GetInfoType>(info_id)) { | 332 | switch (static_cast<GetInfoType>(info_id)) { |
| 333 | case GetInfoType::AllowedCpuIdBitmask: | 333 | case GetInfoType::AllowedCpuIdBitmask: |
| 334 | *result = current_process->allowed_processor_mask; | 334 | *result = current_process->GetAllowedProcessorMask(); |
| 335 | break; | 335 | break; |
| 336 | case GetInfoType::AllowedThreadPrioBitmask: | 336 | case GetInfoType::AllowedThreadPrioBitmask: |
| 337 | *result = current_process->allowed_thread_priority_mask; | 337 | *result = current_process->GetAllowedThreadPriorityMask(); |
| 338 | break; | 338 | break; |
| 339 | case GetInfoType::MapRegionBaseAddr: | 339 | case GetInfoType::MapRegionBaseAddr: |
| 340 | *result = vm_manager.GetMapRegionBaseAddress(); | 340 | *result = vm_manager.GetMapRegionBaseAddress(); |
| @@ -386,10 +386,10 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 386 | *result = vm_manager.GetNewMapRegionSize(); | 386 | *result = vm_manager.GetNewMapRegionSize(); |
| 387 | break; | 387 | break; |
| 388 | case GetInfoType::IsVirtualAddressMemoryEnabled: | 388 | case GetInfoType::IsVirtualAddressMemoryEnabled: |
| 389 | *result = current_process->is_virtual_address_memory_enabled; | 389 | *result = current_process->IsVirtualMemoryEnabled(); |
| 390 | break; | 390 | break; |
| 391 | case GetInfoType::TitleId: | 391 | case GetInfoType::TitleId: |
| 392 | *result = current_process->program_id; | 392 | *result = current_process->GetTitleID(); |
| 393 | break; | 393 | break; |
| 394 | case GetInfoType::PrivilegedProcessId: | 394 | case GetInfoType::PrivilegedProcessId: |
| 395 | LOG_WARNING(Kernel_SVC, | 395 | LOG_WARNING(Kernel_SVC, |
| @@ -415,8 +415,36 @@ static ResultCode SetThreadActivity(Handle handle, u32 unknown) { | |||
| 415 | } | 415 | } |
| 416 | 416 | ||
| 417 | /// Gets the thread context | 417 | /// Gets the thread context |
| 418 | static ResultCode GetThreadContext(Handle handle, VAddr addr) { | 418 | static ResultCode GetThreadContext(VAddr thread_context, Handle handle) { |
| 419 | LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, addr=0x{:X}", handle, addr); | 419 | LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); |
| 420 | |||
| 421 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 422 | const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle); | ||
| 423 | if (!thread) { | ||
| 424 | return ERR_INVALID_HANDLE; | ||
| 425 | } | ||
| 426 | |||
| 427 | const auto current_process = Core::CurrentProcess(); | ||
| 428 | if (thread->owner_process != current_process) { | ||
| 429 | return ERR_INVALID_HANDLE; | ||
| 430 | } | ||
| 431 | |||
| 432 | if (thread == GetCurrentThread()) { | ||
| 433 | return ERR_ALREADY_REGISTERED; | ||
| 434 | } | ||
| 435 | |||
| 436 | Core::ARM_Interface::ThreadContext ctx = thread->context; | ||
| 437 | // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. | ||
| 438 | ctx.pstate &= 0xFF0FFE20; | ||
| 439 | |||
| 440 | // If 64-bit, we can just write the context registers directly and we're good. | ||
| 441 | // However, if 32-bit, we have to ensure some registers are zeroed out. | ||
| 442 | if (!current_process->Is64BitProcess()) { | ||
| 443 | std::fill(ctx.cpu_registers.begin() + 15, ctx.cpu_registers.end(), 0); | ||
| 444 | std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{}); | ||
| 445 | } | ||
| 446 | |||
| 447 | Memory::WriteBlock(thread_context, &ctx, sizeof(ctx)); | ||
| 420 | return RESULT_SUCCESS; | 448 | return RESULT_SUCCESS; |
| 421 | } | 449 | } |
| 422 | 450 | ||
| @@ -444,8 +472,8 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { | |||
| 444 | 472 | ||
| 445 | // Note: The kernel uses the current process's resource limit instead of | 473 | // Note: The kernel uses the current process's resource limit instead of |
| 446 | // the one from the thread owner's resource limit. | 474 | // the one from the thread owner's resource limit. |
| 447 | SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; | 475 | const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit(); |
| 448 | if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) { | 476 | if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) { |
| 449 | return ERR_NOT_AUTHORIZED; | 477 | return ERR_NOT_AUTHORIZED; |
| 450 | } | 478 | } |
| 451 | 479 | ||
| @@ -519,9 +547,9 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i | |||
| 519 | if (!process) { | 547 | if (!process) { |
| 520 | return ERR_INVALID_HANDLE; | 548 | return ERR_INVALID_HANDLE; |
| 521 | } | 549 | } |
| 522 | auto vma = process->vm_manager.FindVMA(addr); | 550 | auto vma = process->VMManager().FindVMA(addr); |
| 523 | memory_info->attributes = 0; | 551 | memory_info->attributes = 0; |
| 524 | if (vma == Core::CurrentProcess()->vm_manager.vma_map.end()) { | 552 | if (vma == Core::CurrentProcess()->VMManager().vma_map.end()) { |
| 525 | memory_info->base_address = 0; | 553 | memory_info->base_address = 0; |
| 526 | memory_info->permission = static_cast<u32>(VMAPermission::None); | 554 | memory_info->permission = static_cast<u32>(VMAPermission::None); |
| 527 | memory_info->size = 0; | 555 | memory_info->size = 0; |
| @@ -568,14 +596,14 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V | |||
| 568 | return ERR_INVALID_THREAD_PRIORITY; | 596 | return ERR_INVALID_THREAD_PRIORITY; |
| 569 | } | 597 | } |
| 570 | 598 | ||
| 571 | SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; | 599 | const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit(); |
| 572 | if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) { | 600 | if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) { |
| 573 | return ERR_NOT_AUTHORIZED; | 601 | return ERR_NOT_AUTHORIZED; |
| 574 | } | 602 | } |
| 575 | 603 | ||
| 576 | if (processor_id == THREADPROCESSORID_DEFAULT) { | 604 | if (processor_id == THREADPROCESSORID_DEFAULT) { |
| 577 | // Set the target CPU to the one specified in the process' exheader. | 605 | // Set the target CPU to the one specified in the process' exheader. |
| 578 | processor_id = Core::CurrentProcess()->ideal_processor; | 606 | processor_id = Core::CurrentProcess()->GetDefaultProcessorID(); |
| 579 | ASSERT(processor_id != THREADPROCESSORID_DEFAULT); | 607 | ASSERT(processor_id != THREADPROCESSORID_DEFAULT); |
| 580 | } | 608 | } |
| 581 | 609 | ||
| @@ -902,10 +930,10 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { | |||
| 902 | } | 930 | } |
| 903 | 931 | ||
| 904 | if (core == static_cast<u32>(THREADPROCESSORID_DEFAULT)) { | 932 | if (core == static_cast<u32>(THREADPROCESSORID_DEFAULT)) { |
| 905 | ASSERT(thread->owner_process->ideal_processor != | 933 | ASSERT(thread->owner_process->GetDefaultProcessorID() != |
| 906 | static_cast<u8>(THREADPROCESSORID_DEFAULT)); | 934 | static_cast<u8>(THREADPROCESSORID_DEFAULT)); |
| 907 | // Set the target CPU to the one specified in the process' exheader. | 935 | // Set the target CPU to the one specified in the process' exheader. |
| 908 | core = thread->owner_process->ideal_processor; | 936 | core = thread->owner_process->GetDefaultProcessorID(); |
| 909 | mask = 1ull << core; | 937 | mask = 1ull << core; |
| 910 | } | 938 | } |
| 911 | 939 | ||
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index fea9ba5ea..22712e64f 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -64,6 +64,11 @@ void SvcWrap() { | |||
| 64 | FuncReturn(func(Param(0), (s32)Param(1)).raw); | 64 | FuncReturn(func(Param(0), (s32)Param(1)).raw); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | template <ResultCode func(u64, u32)> | ||
| 68 | void SvcWrap() { | ||
| 69 | FuncReturn(func(Param(0), static_cast<u32>(Param(1))).raw); | ||
| 70 | } | ||
| 71 | |||
| 67 | template <ResultCode func(u64*, u64)> | 72 | template <ResultCode func(u64*, u64)> |
| 68 | void SvcWrap() { | 73 | void SvcWrap() { |
| 69 | u64 param_1 = 0; | 74 | u64 param_1 = 0; |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 064ed908d..b5c16cfbb 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -259,10 +259,10 @@ void Thread::BoostPriority(u32 priority) { | |||
| 259 | SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, | 259 | SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, |
| 260 | Process& owner_process) { | 260 | Process& owner_process) { |
| 261 | // Setup page table so we can write to memory | 261 | // Setup page table so we can write to memory |
| 262 | SetCurrentPageTable(&owner_process.vm_manager.page_table); | 262 | SetCurrentPageTable(&owner_process.VMManager().page_table); |
| 263 | 263 | ||
| 264 | // Initialize new "main" thread | 264 | // Initialize new "main" thread |
| 265 | const VAddr stack_top = owner_process.vm_manager.GetTLSIORegionEndAddress(); | 265 | const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress(); |
| 266 | auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0, | 266 | auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0, |
| 267 | stack_top, &owner_process); | 267 | stack_top, &owner_process); |
| 268 | 268 | ||
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 2212b2cdd..2f15ac2a6 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp | |||
| @@ -51,7 +51,7 @@ enum class FatalType : u32 { | |||
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) { | 53 | static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) { |
| 54 | const auto title_id = Core::CurrentProcess()->program_id; | 54 | const auto title_id = Core::CurrentProcess()->GetTitleID(); |
| 55 | std::string crash_report = | 55 | std::string crash_report = |
| 56 | fmt::format("Yuzu {}-{} crash report\n" | 56 | fmt::format("Yuzu {}-{} crash report\n" |
| 57 | "Title ID: {:016x}\n" | 57 | "Title ID: {:016x}\n" |
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 1069d103f..4b2f758a8 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp | |||
| @@ -317,9 +317,9 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { | |||
| 317 | 317 | ||
| 318 | void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { | 318 | void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { |
| 319 | // Map backing memory for the font data | 319 | // Map backing memory for the font data |
| 320 | Core::CurrentProcess()->vm_manager.MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, | 320 | Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, |
| 321 | SHARED_FONT_MEM_SIZE, | 321 | SHARED_FONT_MEM_SIZE, |
| 322 | Kernel::MemoryState::Shared); | 322 | Kernel::MemoryState::Shared); |
| 323 | 323 | ||
| 324 | // Create shared font memory object | 324 | // Create shared font memory object |
| 325 | auto& kernel = Core::System::GetInstance().Kernel(); | 325 | auto& kernel = Core::System::GetInstance().Kernel(); |
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 2ee60f1ec..bbc02abcc 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -612,7 +612,7 @@ public: | |||
| 612 | {3000, nullptr, "ListDisplayModes"}, | 612 | {3000, nullptr, "ListDisplayModes"}, |
| 613 | {3001, nullptr, "ListDisplayRgbRanges"}, | 613 | {3001, nullptr, "ListDisplayRgbRanges"}, |
| 614 | {3002, nullptr, "ListDisplayContentTypes"}, | 614 | {3002, nullptr, "ListDisplayContentTypes"}, |
| 615 | {3200, nullptr, "GetDisplayMode"}, | 615 | {3200, &ISystemDisplayService::GetDisplayMode, "GetDisplayMode"}, |
| 616 | {3201, nullptr, "SetDisplayMode"}, | 616 | {3201, nullptr, "SetDisplayMode"}, |
| 617 | {3202, nullptr, "GetDisplayUnderscan"}, | 617 | {3202, nullptr, "GetDisplayUnderscan"}, |
| 618 | {3203, nullptr, "SetDisplayUnderscan"}, | 618 | {3203, nullptr, "SetDisplayUnderscan"}, |
| @@ -663,6 +663,24 @@ private: | |||
| 663 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, | 663 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, |
| 664 | visibility); | 664 | visibility); |
| 665 | } | 665 | } |
| 666 | |||
| 667 | void GetDisplayMode(Kernel::HLERequestContext& ctx) { | ||
| 668 | IPC::ResponseBuilder rb{ctx, 6}; | ||
| 669 | rb.Push(RESULT_SUCCESS); | ||
| 670 | |||
| 671 | if (Settings::values.use_docked_mode) { | ||
| 672 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); | ||
| 673 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); | ||
| 674 | } else { | ||
| 675 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); | ||
| 676 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); | ||
| 677 | } | ||
| 678 | |||
| 679 | rb.PushRaw<float>(60.0f); | ||
| 680 | rb.Push<u32>(0); | ||
| 681 | |||
| 682 | LOG_DEBUG(Service_VI, "called"); | ||
| 683 | } | ||
| 666 | }; | 684 | }; |
| 667 | 685 | ||
| 668 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { | 686 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { |
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 1b198cc5c..c1824b9c3 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -132,7 +132,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) | |||
| 132 | process.LoadFromMetadata(metadata); | 132 | process.LoadFromMetadata(metadata); |
| 133 | 133 | ||
| 134 | // Load NSO modules | 134 | // Load NSO modules |
| 135 | const VAddr base_address = process.vm_manager.GetCodeRegionBaseAddress(); | 135 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); |
| 136 | VAddr next_load_addr = base_address; | 136 | VAddr next_load_addr = base_address; |
| 137 | for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", | 137 | for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", |
| 138 | "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { | 138 | "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { |
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 5712a2a11..e67b49fc9 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp | |||
| @@ -395,7 +395,7 @@ ResultStatus AppLoader_ELF::Load(Kernel::Process& process) { | |||
| 395 | if (buffer.size() != file->GetSize()) | 395 | if (buffer.size() != file->GetSize()) |
| 396 | return ResultStatus::ErrorIncorrectELFFileSize; | 396 | return ResultStatus::ErrorIncorrectELFFileSize; |
| 397 | 397 | ||
| 398 | const VAddr base_address = process.vm_manager.GetCodeRegionBaseAddress(); | 398 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); |
| 399 | ElfReader elf_reader(&buffer[0]); | 399 | ElfReader elf_reader(&buffer[0]); |
| 400 | SharedPtr<CodeSet> codeset = elf_reader.LoadInto(base_address); | 400 | SharedPtr<CodeSet> codeset = elf_reader.LoadInto(base_address); |
| 401 | codeset->name = file->GetName(); | 401 | codeset->name = file->GetName(); |
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 8ad973c3a..c10f826a4 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -181,7 +181,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { | |||
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | // Load NRO | 183 | // Load NRO |
| 184 | const VAddr base_address = process.vm_manager.GetCodeRegionBaseAddress(); | 184 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); |
| 185 | 185 | ||
| 186 | if (!LoadNro(file, base_address)) { | 186 | if (!LoadNro(file, base_address)) { |
| 187 | return ResultStatus::ErrorLoadingNRO; | 187 | return ResultStatus::ErrorLoadingNRO; |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 6fe3e17a7..cbe2a3e53 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -159,7 +159,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::Process& process) { | |||
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | // Load module | 161 | // Load module |
| 162 | const VAddr base_address = process.vm_manager.GetCodeRegionBaseAddress(); | 162 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); |
| 163 | LoadModule(file, base_address); | 163 | LoadModule(file, base_address); |
| 164 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); | 164 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); |
| 165 | 165 | ||
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 6430daad4..014298ed6 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -119,7 +119,7 @@ void RemoveDebugHook(PageTable& page_table, VAddr base, u64 size, MemoryHookPoin | |||
| 119 | static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) { | 119 | static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) { |
| 120 | u8* direct_pointer = nullptr; | 120 | u8* direct_pointer = nullptr; |
| 121 | 121 | ||
| 122 | auto& vm_manager = process.vm_manager; | 122 | auto& vm_manager = process.VMManager(); |
| 123 | 123 | ||
| 124 | auto it = vm_manager.FindVMA(vaddr); | 124 | auto it = vm_manager.FindVMA(vaddr); |
| 125 | ASSERT(it != vm_manager.vma_map.end()); | 125 | ASSERT(it != vm_manager.vma_map.end()); |
| @@ -214,7 +214,7 @@ void Write(const VAddr vaddr, const T data) { | |||
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { | 216 | bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { |
| 217 | auto& page_table = process.vm_manager.page_table; | 217 | const auto& page_table = process.VMManager().page_table; |
| 218 | 218 | ||
| 219 | const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS]; | 219 | const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS]; |
| 220 | if (page_pointer) | 220 | if (page_pointer) |
| @@ -363,7 +363,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) { | |||
| 363 | } | 363 | } |
| 364 | }; | 364 | }; |
| 365 | 365 | ||
| 366 | const auto& vm_manager = Core::CurrentProcess()->vm_manager; | 366 | const auto& vm_manager = Core::CurrentProcess()->VMManager(); |
| 367 | 367 | ||
| 368 | CheckRegion(vm_manager.GetCodeRegionBaseAddress(), vm_manager.GetCodeRegionEndAddress()); | 368 | CheckRegion(vm_manager.GetCodeRegionBaseAddress(), vm_manager.GetCodeRegionEndAddress()); |
| 369 | CheckRegion(vm_manager.GetHeapRegionBaseAddress(), vm_manager.GetHeapRegionEndAddress()); | 369 | CheckRegion(vm_manager.GetHeapRegionBaseAddress(), vm_manager.GetHeapRegionEndAddress()); |
| @@ -387,7 +387,7 @@ u64 Read64(const VAddr addr) { | |||
| 387 | 387 | ||
| 388 | void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, | 388 | void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, |
| 389 | const std::size_t size) { | 389 | const std::size_t size) { |
| 390 | auto& page_table = process.vm_manager.page_table; | 390 | const auto& page_table = process.VMManager().page_table; |
| 391 | 391 | ||
| 392 | std::size_t remaining_size = size; | 392 | std::size_t remaining_size = size; |
| 393 | std::size_t page_index = src_addr >> PAGE_BITS; | 393 | std::size_t page_index = src_addr >> PAGE_BITS; |
| @@ -452,7 +452,7 @@ void Write64(const VAddr addr, const u64 data) { | |||
| 452 | 452 | ||
| 453 | void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, | 453 | void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, |
| 454 | const std::size_t size) { | 454 | const std::size_t size) { |
| 455 | auto& page_table = process.vm_manager.page_table; | 455 | const auto& page_table = process.VMManager().page_table; |
| 456 | std::size_t remaining_size = size; | 456 | std::size_t remaining_size = size; |
| 457 | std::size_t page_index = dest_addr >> PAGE_BITS; | 457 | std::size_t page_index = dest_addr >> PAGE_BITS; |
| 458 | std::size_t page_offset = dest_addr & PAGE_MASK; | 458 | std::size_t page_offset = dest_addr & PAGE_MASK; |
| @@ -498,7 +498,7 @@ void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t | |||
| 498 | } | 498 | } |
| 499 | 499 | ||
| 500 | void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { | 500 | void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { |
| 501 | auto& page_table = process.vm_manager.page_table; | 501 | const auto& page_table = process.VMManager().page_table; |
| 502 | std::size_t remaining_size = size; | 502 | std::size_t remaining_size = size; |
| 503 | std::size_t page_index = dest_addr >> PAGE_BITS; | 503 | std::size_t page_index = dest_addr >> PAGE_BITS; |
| 504 | std::size_t page_offset = dest_addr & PAGE_MASK; | 504 | std::size_t page_offset = dest_addr & PAGE_MASK; |
| @@ -540,7 +540,7 @@ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std: | |||
| 540 | 540 | ||
| 541 | void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, | 541 | void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, |
| 542 | const std::size_t size) { | 542 | const std::size_t size) { |
| 543 | auto& page_table = process.vm_manager.page_table; | 543 | const auto& page_table = process.VMManager().page_table; |
| 544 | std::size_t remaining_size = size; | 544 | std::size_t remaining_size = size; |
| 545 | std::size_t page_index = src_addr >> PAGE_BITS; | 545 | std::size_t page_index = src_addr >> PAGE_BITS; |
| 546 | std::size_t page_offset = src_addr & PAGE_MASK; | 546 | std::size_t page_offset = src_addr & PAGE_MASK; |
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp index c17a122cd..c0a57e71f 100644 --- a/src/tests/core/arm/arm_test_common.cpp +++ b/src/tests/core/arm/arm_test_common.cpp | |||
| @@ -16,7 +16,7 @@ TestEnvironment::TestEnvironment(bool mutable_memory_) | |||
| 16 | : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) { | 16 | : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) { |
| 17 | 17 | ||
| 18 | Core::CurrentProcess() = Kernel::Process::Create(kernel, ""); | 18 | Core::CurrentProcess() = Kernel::Process::Create(kernel, ""); |
| 19 | page_table = &Core::CurrentProcess()->vm_manager.page_table; | 19 | page_table = &Core::CurrentProcess()->VMManager().page_table; |
| 20 | 20 | ||
| 21 | std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr); | 21 | std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr); |
| 22 | page_table->special_regions.clear(); | 22 | page_table->special_regions.clear(); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 1fcd13f04..14d82a7bc 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -738,7 +738,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, | |||
| 738 | } | 738 | } |
| 739 | 739 | ||
| 740 | texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); | 740 | texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc); |
| 741 | Surface surface = res_cache.GetTextureSurface(texture); | 741 | Surface surface = res_cache.GetTextureSurface(texture, entry); |
| 742 | if (surface != nullptr) { | 742 | if (surface != nullptr) { |
| 743 | state.texture_units[current_bindpoint].texture = surface->Texture().handle; | 743 | state.texture_units[current_bindpoint].texture = surface->Texture().handle; |
| 744 | state.texture_units[current_bindpoint].target = surface->Target(); | 744 | state.texture_units[current_bindpoint].target = surface->Target(); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 24a540258..ce967c4d6 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -41,7 +41,7 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { | |||
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | /*static*/ SurfaceParams SurfaceParams::CreateForTexture( | 43 | /*static*/ SurfaceParams SurfaceParams::CreateForTexture( |
| 44 | const Tegra::Texture::FullTextureInfo& config) { | 44 | const Tegra::Texture::FullTextureInfo& config, const GLShader::SamplerEntry& entry) { |
| 45 | SurfaceParams params{}; | 45 | SurfaceParams params{}; |
| 46 | params.addr = TryGetCpuAddr(config.tic.Address()); | 46 | params.addr = TryGetCpuAddr(config.tic.Address()); |
| 47 | params.is_tiled = config.tic.IsTiled(); | 47 | params.is_tiled = config.tic.IsTiled(); |
| @@ -60,9 +60,23 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { | |||
| 60 | case SurfaceTarget::Texture2D: | 60 | case SurfaceTarget::Texture2D: |
| 61 | params.depth = 1; | 61 | params.depth = 1; |
| 62 | break; | 62 | break; |
| 63 | case SurfaceTarget::TextureCubemap: | ||
| 64 | params.depth = config.tic.Depth() * 6; | ||
| 65 | break; | ||
| 63 | case SurfaceTarget::Texture3D: | 66 | case SurfaceTarget::Texture3D: |
| 67 | params.depth = config.tic.Depth(); | ||
| 68 | break; | ||
| 64 | case SurfaceTarget::Texture2DArray: | 69 | case SurfaceTarget::Texture2DArray: |
| 65 | params.depth = config.tic.Depth(); | 70 | params.depth = config.tic.Depth(); |
| 71 | if (!entry.IsArray()) { | ||
| 72 | // TODO(bunnei): We have seen games re-use a Texture2D as Texture2DArray with depth of | ||
| 73 | // one, but sample the texture in the shader as if it were not an array texture. This | ||
| 74 | // probably is valid on hardware, but we still need to write a test to confirm this. In | ||
| 75 | // emulation, the workaround here is to continue to treat this as a Texture2D. An | ||
| 76 | // example game that does this is Super Mario Odyssey (in Cloud Kingdom). | ||
| 77 | ASSERT(params.depth == 1); | ||
| 78 | params.target = SurfaceTarget::Texture2D; | ||
| 79 | } | ||
| 66 | break; | 80 | break; |
| 67 | default: | 81 | default: |
| 68 | LOG_CRITICAL(HW_GPU, "Unknown depth for target={}", static_cast<u32>(params.target)); | 82 | LOG_CRITICAL(HW_GPU, "Unknown depth for target={}", static_cast<u32>(params.target)); |
| @@ -71,7 +85,11 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { | |||
| 71 | break; | 85 | break; |
| 72 | } | 86 | } |
| 73 | 87 | ||
| 74 | params.size_in_bytes = params.SizeInBytes(); | 88 | params.size_in_bytes_total = params.SizeInBytesTotal(); |
| 89 | params.size_in_bytes_2d = params.SizeInBytes2D(); | ||
| 90 | params.max_mip_level = config.tic.max_mip_level + 1; | ||
| 91 | params.rt = {}; | ||
| 92 | |||
| 75 | return params; | 93 | return params; |
| 76 | } | 94 | } |
| 77 | 95 | ||
| @@ -89,7 +107,16 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { | |||
| 89 | params.unaligned_height = config.height; | 107 | params.unaligned_height = config.height; |
| 90 | params.target = SurfaceTarget::Texture2D; | 108 | params.target = SurfaceTarget::Texture2D; |
| 91 | params.depth = 1; | 109 | params.depth = 1; |
| 92 | params.size_in_bytes = params.SizeInBytes(); | 110 | params.size_in_bytes_total = params.SizeInBytesTotal(); |
| 111 | params.size_in_bytes_2d = params.SizeInBytes2D(); | ||
| 112 | params.max_mip_level = 0; | ||
| 113 | |||
| 114 | // Render target specific parameters, not used for caching | ||
| 115 | params.rt.index = static_cast<u32>(index); | ||
| 116 | params.rt.array_mode = config.array_mode; | ||
| 117 | params.rt.layer_stride = config.layer_stride; | ||
| 118 | params.rt.base_layer = config.base_layer; | ||
| 119 | |||
| 93 | return params; | 120 | return params; |
| 94 | } | 121 | } |
| 95 | 122 | ||
| @@ -108,7 +135,11 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { | |||
| 108 | params.unaligned_height = zeta_height; | 135 | params.unaligned_height = zeta_height; |
| 109 | params.target = SurfaceTarget::Texture2D; | 136 | params.target = SurfaceTarget::Texture2D; |
| 110 | params.depth = 1; | 137 | params.depth = 1; |
| 111 | params.size_in_bytes = params.SizeInBytes(); | 138 | params.size_in_bytes_total = params.SizeInBytesTotal(); |
| 139 | params.size_in_bytes_2d = params.SizeInBytes2D(); | ||
| 140 | params.max_mip_level = 0; | ||
| 141 | params.rt = {}; | ||
| 142 | |||
| 112 | return params; | 143 | return params; |
| 113 | } | 144 | } |
| 114 | 145 | ||
| @@ -400,9 +431,13 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, std::size_t, VAddr), | |||
| 400 | // clang-format on | 431 | // clang-format on |
| 401 | }; | 432 | }; |
| 402 | 433 | ||
| 403 | static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex, | 434 | static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, |
| 404 | const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type, | 435 | GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0, |
| 405 | GLuint read_fb_handle, GLuint draw_fb_handle) { | 436 | GLenum dst_attachment = 0, std::size_t cubemap_face = 0) { |
| 437 | |||
| 438 | const auto& src_params{src_surface->GetSurfaceParams()}; | ||
| 439 | const auto& dst_params{dst_surface->GetSurfaceParams()}; | ||
| 440 | |||
| 406 | OpenGLState prev_state{OpenGLState::GetCurState()}; | 441 | OpenGLState prev_state{OpenGLState::GetCurState()}; |
| 407 | SCOPE_EXIT({ prev_state.Apply(); }); | 442 | SCOPE_EXIT({ prev_state.Apply(); }); |
| 408 | 443 | ||
| @@ -413,47 +448,203 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rec | |||
| 413 | 448 | ||
| 414 | u32 buffers{}; | 449 | u32 buffers{}; |
| 415 | 450 | ||
| 416 | if (type == SurfaceType::ColorTexture) { | 451 | if (src_params.type == SurfaceType::ColorTexture) { |
| 417 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src_tex, | 452 | switch (src_params.target) { |
| 418 | 0); | 453 | case SurfaceParams::SurfaceTarget::Texture2D: |
| 419 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, | 454 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, |
| 420 | 0); | 455 | GL_TEXTURE_2D, src_surface->Texture().handle, 0); |
| 456 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | ||
| 457 | 0, 0); | ||
| 458 | break; | ||
| 459 | case SurfaceParams::SurfaceTarget::TextureCubemap: | ||
| 460 | glFramebufferTexture2D( | ||
| 461 | GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, | ||
| 462 | static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), | ||
| 463 | src_surface->Texture().handle, 0); | ||
| 464 | glFramebufferTexture2D( | ||
| 465 | GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, | ||
| 466 | static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0); | ||
| 467 | break; | ||
| 468 | case SurfaceParams::SurfaceTarget::Texture2DArray: | ||
| 469 | glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, | ||
| 470 | src_surface->Texture().handle, 0, 0); | ||
| 471 | glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); | ||
| 472 | break; | ||
| 473 | case SurfaceParams::SurfaceTarget::Texture3D: | ||
| 474 | glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, | ||
| 475 | SurfaceTargetToGL(src_params.target), | ||
| 476 | src_surface->Texture().handle, 0, 0); | ||
| 477 | glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, | ||
| 478 | SurfaceTargetToGL(src_params.target), 0, 0, 0); | ||
| 479 | break; | ||
| 480 | default: | ||
| 481 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, | ||
| 482 | GL_TEXTURE_2D, src_surface->Texture().handle, 0); | ||
| 483 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | ||
| 484 | 0, 0); | ||
| 485 | break; | ||
| 486 | } | ||
| 487 | |||
| 488 | switch (dst_params.target) { | ||
| 489 | case SurfaceParams::SurfaceTarget::Texture2D: | ||
| 490 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, | ||
| 491 | GL_TEXTURE_2D, dst_surface->Texture().handle, 0); | ||
| 492 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | ||
| 493 | 0, 0); | ||
| 494 | break; | ||
| 495 | case SurfaceParams::SurfaceTarget::TextureCubemap: | ||
| 496 | glFramebufferTexture2D( | ||
| 497 | GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, | ||
| 498 | static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), | ||
| 499 | dst_surface->Texture().handle, 0); | ||
| 500 | glFramebufferTexture2D( | ||
| 501 | GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, | ||
| 502 | static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0); | ||
| 503 | break; | ||
| 504 | case SurfaceParams::SurfaceTarget::Texture2DArray: | ||
| 505 | glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, | ||
| 506 | dst_surface->Texture().handle, 0, 0); | ||
| 507 | glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); | ||
| 508 | break; | ||
| 421 | 509 | ||
| 422 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_tex, | 510 | case SurfaceParams::SurfaceTarget::Texture3D: |
| 423 | 0); | 511 | glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, |
| 424 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, | 512 | SurfaceTargetToGL(dst_params.target), |
| 425 | 0); | 513 | dst_surface->Texture().handle, 0, 0); |
| 514 | glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, | ||
| 515 | SurfaceTargetToGL(dst_params.target), 0, 0, 0); | ||
| 516 | break; | ||
| 517 | default: | ||
| 518 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, | ||
| 519 | GL_TEXTURE_2D, dst_surface->Texture().handle, 0); | ||
| 520 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | ||
| 521 | 0, 0); | ||
| 522 | break; | ||
| 523 | } | ||
| 426 | 524 | ||
| 427 | buffers = GL_COLOR_BUFFER_BIT; | 525 | buffers = GL_COLOR_BUFFER_BIT; |
| 428 | } else if (type == SurfaceType::Depth) { | 526 | } else if (src_params.type == SurfaceType::Depth) { |
| 429 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | 527 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, |
| 430 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, src_tex, 0); | 528 | GL_TEXTURE_2D, 0, 0); |
| 529 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, | ||
| 530 | src_surface->Texture().handle, 0); | ||
| 431 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); | 531 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); |
| 432 | 532 | ||
| 433 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | 533 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, |
| 434 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, dst_tex, 0); | 534 | GL_TEXTURE_2D, 0, 0); |
| 535 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, | ||
| 536 | dst_surface->Texture().handle, 0); | ||
| 435 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); | 537 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); |
| 436 | 538 | ||
| 437 | buffers = GL_DEPTH_BUFFER_BIT; | 539 | buffers = GL_DEPTH_BUFFER_BIT; |
| 438 | } else if (type == SurfaceType::DepthStencil) { | 540 | } else if (src_params.type == SurfaceType::DepthStencil) { |
| 439 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | 541 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, |
| 542 | GL_TEXTURE_2D, 0, 0); | ||
| 440 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | 543 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 441 | src_tex, 0); | 544 | src_surface->Texture().handle, 0); |
| 442 | 545 | ||
| 443 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | 546 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, |
| 547 | GL_TEXTURE_2D, 0, 0); | ||
| 444 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | 548 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 445 | dst_tex, 0); | 549 | dst_surface->Texture().handle, 0); |
| 446 | 550 | ||
| 447 | buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; | 551 | buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; |
| 448 | } | 552 | } |
| 449 | 553 | ||
| 450 | glBlitFramebuffer(src_rect.left, src_rect.bottom, src_rect.right, src_rect.top, dst_rect.left, | 554 | const auto& rect{src_params.GetRect()}; |
| 451 | dst_rect.bottom, dst_rect.right, dst_rect.top, buffers, | 555 | glBlitFramebuffer(rect.left, rect.bottom, rect.right, rect.top, rect.left, rect.bottom, |
| 556 | rect.right, rect.top, buffers, | ||
| 452 | buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST); | 557 | buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST); |
| 453 | 558 | ||
| 454 | return true; | 559 | return true; |
| 455 | } | 560 | } |
| 456 | 561 | ||
| 562 | static void CopySurface(const Surface& src_surface, const Surface& dst_surface, | ||
| 563 | GLuint copy_pbo_handle, GLenum src_attachment = 0, | ||
| 564 | GLenum dst_attachment = 0, std::size_t cubemap_face = 0) { | ||
| 565 | ASSERT_MSG(dst_attachment == 0, "Unimplemented"); | ||
| 566 | |||
| 567 | const auto& src_params{src_surface->GetSurfaceParams()}; | ||
| 568 | const auto& dst_params{dst_surface->GetSurfaceParams()}; | ||
| 569 | |||
| 570 | auto source_format = GetFormatTuple(src_params.pixel_format, src_params.component_type); | ||
| 571 | auto dest_format = GetFormatTuple(dst_params.pixel_format, dst_params.component_type); | ||
| 572 | |||
| 573 | std::size_t buffer_size = | ||
| 574 | std::max(src_params.size_in_bytes_total, dst_params.size_in_bytes_total); | ||
| 575 | |||
| 576 | glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle); | ||
| 577 | glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); | ||
| 578 | if (source_format.compressed) { | ||
| 579 | glGetCompressedTextureImage(src_surface->Texture().handle, src_attachment, | ||
| 580 | static_cast<GLsizei>(src_params.size_in_bytes_total), nullptr); | ||
| 581 | } else { | ||
| 582 | glGetTextureImage(src_surface->Texture().handle, src_attachment, source_format.format, | ||
| 583 | source_format.type, static_cast<GLsizei>(src_params.size_in_bytes_total), | ||
| 584 | nullptr); | ||
| 585 | } | ||
| 586 | // If the new texture is bigger than the previous one, we need to fill in the rest with data | ||
| 587 | // from the CPU. | ||
| 588 | if (src_params.size_in_bytes_total < dst_params.size_in_bytes_total) { | ||
| 589 | // Upload the rest of the memory. | ||
| 590 | if (dst_params.is_tiled) { | ||
| 591 | // TODO(Subv): We might have to de-tile the subtexture and re-tile it with the rest | ||
| 592 | // of the data in this case. Games like Super Mario Odyssey seem to hit this case | ||
| 593 | // when drawing, it re-uses the memory of a previous texture as a bigger framebuffer | ||
| 594 | // but it doesn't clear it beforehand, the texture is already full of zeros. | ||
| 595 | LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during " | ||
| 596 | "reinterpretation but the texture is tiled."); | ||
| 597 | } | ||
| 598 | std::size_t remaining_size = | ||
| 599 | dst_params.size_in_bytes_total - src_params.size_in_bytes_total; | ||
| 600 | std::vector<u8> data(remaining_size); | ||
| 601 | Memory::ReadBlock(dst_params.addr + src_params.size_in_bytes_total, data.data(), | ||
| 602 | data.size()); | ||
| 603 | glBufferSubData(GL_PIXEL_PACK_BUFFER, src_params.size_in_bytes_total, remaining_size, | ||
| 604 | data.data()); | ||
| 605 | } | ||
| 606 | |||
| 607 | glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); | ||
| 608 | |||
| 609 | const GLsizei width{static_cast<GLsizei>( | ||
| 610 | std::min(src_params.GetRect().GetWidth(), dst_params.GetRect().GetWidth()))}; | ||
| 611 | const GLsizei height{static_cast<GLsizei>( | ||
| 612 | std::min(src_params.GetRect().GetHeight(), dst_params.GetRect().GetHeight()))}; | ||
| 613 | |||
| 614 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, copy_pbo_handle); | ||
| 615 | if (dest_format.compressed) { | ||
| 616 | LOG_CRITICAL(HW_GPU, "Compressed copy is unimplemented!"); | ||
| 617 | UNREACHABLE(); | ||
| 618 | } else { | ||
| 619 | switch (dst_params.target) { | ||
| 620 | case SurfaceParams::SurfaceTarget::Texture1D: | ||
| 621 | glTextureSubImage1D(dst_surface->Texture().handle, 0, 0, width, dest_format.format, | ||
| 622 | dest_format.type, nullptr); | ||
| 623 | break; | ||
| 624 | case SurfaceParams::SurfaceTarget::Texture2D: | ||
| 625 | glTextureSubImage2D(dst_surface->Texture().handle, 0, 0, 0, width, height, | ||
| 626 | dest_format.format, dest_format.type, nullptr); | ||
| 627 | break; | ||
| 628 | case SurfaceParams::SurfaceTarget::Texture3D: | ||
| 629 | case SurfaceParams::SurfaceTarget::Texture2DArray: | ||
| 630 | glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 0, width, height, | ||
| 631 | static_cast<GLsizei>(dst_params.depth), dest_format.format, | ||
| 632 | dest_format.type, nullptr); | ||
| 633 | break; | ||
| 634 | case SurfaceParams::SurfaceTarget::TextureCubemap: | ||
| 635 | glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, | ||
| 636 | static_cast<GLint>(cubemap_face), width, height, 1, | ||
| 637 | dest_format.format, dest_format.type, nullptr); | ||
| 638 | break; | ||
| 639 | default: | ||
| 640 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | ||
| 641 | static_cast<u32>(dst_params.target)); | ||
| 642 | UNREACHABLE(); | ||
| 643 | } | ||
| 644 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | ||
| 645 | } | ||
| 646 | } | ||
| 647 | |||
| 457 | CachedSurface::CachedSurface(const SurfaceParams& params) | 648 | CachedSurface::CachedSurface(const SurfaceParams& params) |
| 458 | : params(params), gl_target(SurfaceTargetToGL(params.target)) { | 649 | : params(params), gl_target(SurfaceTargetToGL(params.target)) { |
| 459 | texture.Create(); | 650 | texture.Create(); |
| @@ -481,6 +672,7 @@ CachedSurface::CachedSurface(const SurfaceParams& params) | |||
| 481 | rect.GetWidth()); | 672 | rect.GetWidth()); |
| 482 | break; | 673 | break; |
| 483 | case SurfaceParams::SurfaceTarget::Texture2D: | 674 | case SurfaceParams::SurfaceTarget::Texture2D: |
| 675 | case SurfaceParams::SurfaceTarget::TextureCubemap: | ||
| 484 | glTexStorage2D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, | 676 | glTexStorage2D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, |
| 485 | rect.GetWidth(), rect.GetHeight()); | 677 | rect.GetWidth(), rect.GetHeight()); |
| 486 | break; | 678 | break; |
| @@ -585,29 +777,39 @@ void CachedSurface::LoadGLBuffer() { | |||
| 585 | 777 | ||
| 586 | const u32 bytes_per_pixel = GetGLBytesPerPixel(params.pixel_format); | 778 | const u32 bytes_per_pixel = GetGLBytesPerPixel(params.pixel_format); |
| 587 | const u32 copy_size = params.width * params.height * bytes_per_pixel; | 779 | const u32 copy_size = params.width * params.height * bytes_per_pixel; |
| 780 | const std::size_t total_size = copy_size * params.depth; | ||
| 588 | 781 | ||
| 589 | MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); | 782 | MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); |
| 590 | 783 | ||
| 591 | if (params.is_tiled) { | 784 | if (params.is_tiled) { |
| 785 | gl_buffer.resize(total_size); | ||
| 786 | |||
| 592 | // TODO(bunnei): This only unswizzles and copies a 2D texture - we do not yet know how to do | 787 | // TODO(bunnei): This only unswizzles and copies a 2D texture - we do not yet know how to do |
| 593 | // this for 3D textures, etc. | 788 | // this for 3D textures, etc. |
| 594 | switch (params.target) { | 789 | switch (params.target) { |
| 595 | case SurfaceParams::SurfaceTarget::Texture2D: | 790 | case SurfaceParams::SurfaceTarget::Texture2D: |
| 596 | // Pass impl. to the fallback code below | 791 | // Pass impl. to the fallback code below |
| 597 | break; | 792 | break; |
| 793 | case SurfaceParams::SurfaceTarget::Texture2DArray: | ||
| 794 | case SurfaceParams::SurfaceTarget::TextureCubemap: | ||
| 795 | for (std::size_t index = 0; index < params.depth; ++index) { | ||
| 796 | const std::size_t offset{index * copy_size}; | ||
| 797 | morton_to_gl_fns[static_cast<std::size_t>(params.pixel_format)]( | ||
| 798 | params.width, params.block_height, params.height, gl_buffer.data() + offset, | ||
| 799 | copy_size, params.addr + offset); | ||
| 800 | } | ||
| 801 | break; | ||
| 598 | default: | 802 | default: |
| 599 | LOG_CRITICAL(HW_GPU, "Unimplemented tiled load for target={}", | 803 | LOG_CRITICAL(HW_GPU, "Unimplemented tiled load for target={}", |
| 600 | static_cast<u32>(params.target)); | 804 | static_cast<u32>(params.target)); |
| 601 | UNREACHABLE(); | 805 | UNREACHABLE(); |
| 602 | } | 806 | } |
| 603 | 807 | ||
| 604 | gl_buffer.resize(static_cast<std::size_t>(params.depth) * copy_size); | ||
| 605 | morton_to_gl_fns[static_cast<std::size_t>(params.pixel_format)]( | 808 | morton_to_gl_fns[static_cast<std::size_t>(params.pixel_format)]( |
| 606 | params.width, params.block_height, params.height, gl_buffer.data(), copy_size, | 809 | params.width, params.block_height, params.height, gl_buffer.data(), copy_size, |
| 607 | params.addr); | 810 | params.addr); |
| 608 | } else { | 811 | } else { |
| 609 | const u8* const texture_src_data_end{texture_src_data + | 812 | const u8* const texture_src_data_end{texture_src_data + total_size}; |
| 610 | (static_cast<std::size_t>(params.depth) * copy_size)}; | ||
| 611 | gl_buffer.assign(texture_src_data, texture_src_data_end); | 813 | gl_buffer.assign(texture_src_data, texture_src_data_end); |
| 612 | } | 814 | } |
| 613 | 815 | ||
| @@ -634,7 +836,7 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle | |||
| 634 | // Load data from memory to the surface | 836 | // Load data from memory to the surface |
| 635 | const GLint x0 = static_cast<GLint>(rect.left); | 837 | const GLint x0 = static_cast<GLint>(rect.left); |
| 636 | const GLint y0 = static_cast<GLint>(rect.bottom); | 838 | const GLint y0 = static_cast<GLint>(rect.bottom); |
| 637 | const std::size_t buffer_offset = | 839 | std::size_t buffer_offset = |
| 638 | static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.width + | 840 | static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.width + |
| 639 | static_cast<std::size_t>(x0)) * | 841 | static_cast<std::size_t>(x0)) * |
| 640 | GetGLBytesPerPixel(params.pixel_format); | 842 | GetGLBytesPerPixel(params.pixel_format); |
| @@ -663,15 +865,25 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle | |||
| 663 | glCompressedTexImage2D( | 865 | glCompressedTexImage2D( |
| 664 | SurfaceTargetToGL(params.target), 0, tuple.internal_format, | 866 | SurfaceTargetToGL(params.target), 0, tuple.internal_format, |
| 665 | static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0, | 867 | static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0, |
| 666 | static_cast<GLsizei>(params.size_in_bytes), &gl_buffer[buffer_offset]); | 868 | static_cast<GLsizei>(params.size_in_bytes_2d), &gl_buffer[buffer_offset]); |
| 667 | break; | 869 | break; |
| 668 | case SurfaceParams::SurfaceTarget::Texture3D: | 870 | case SurfaceParams::SurfaceTarget::Texture3D: |
| 669 | case SurfaceParams::SurfaceTarget::Texture2DArray: | 871 | case SurfaceParams::SurfaceTarget::Texture2DArray: |
| 670 | glCompressedTexImage3D( | 872 | glCompressedTexImage3D( |
| 671 | SurfaceTargetToGL(params.target), 0, tuple.internal_format, | 873 | SurfaceTargetToGL(params.target), 0, tuple.internal_format, |
| 672 | static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), | 874 | static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), |
| 673 | static_cast<GLsizei>(params.depth), 0, static_cast<GLsizei>(params.size_in_bytes), | 875 | static_cast<GLsizei>(params.depth), 0, |
| 674 | &gl_buffer[buffer_offset]); | 876 | static_cast<GLsizei>(params.size_in_bytes_total), &gl_buffer[buffer_offset]); |
| 877 | break; | ||
| 878 | case SurfaceParams::SurfaceTarget::TextureCubemap: | ||
| 879 | for (std::size_t face = 0; face < params.depth; ++face) { | ||
| 880 | glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), | ||
| 881 | 0, tuple.internal_format, static_cast<GLsizei>(params.width), | ||
| 882 | static_cast<GLsizei>(params.height), 0, | ||
| 883 | static_cast<GLsizei>(params.size_in_bytes_2d), | ||
| 884 | &gl_buffer[buffer_offset]); | ||
| 885 | buffer_offset += params.size_in_bytes_2d; | ||
| 886 | } | ||
| 675 | break; | 887 | break; |
| 676 | default: | 888 | default: |
| 677 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | 889 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", |
| @@ -679,8 +891,8 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle | |||
| 679 | UNREACHABLE(); | 891 | UNREACHABLE(); |
| 680 | glCompressedTexImage2D( | 892 | glCompressedTexImage2D( |
| 681 | GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), | 893 | GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), |
| 682 | static_cast<GLsizei>(params.height), 0, static_cast<GLsizei>(params.size_in_bytes), | 894 | static_cast<GLsizei>(params.height), 0, |
| 683 | &gl_buffer[buffer_offset]); | 895 | static_cast<GLsizei>(params.size_in_bytes_2d), &gl_buffer[buffer_offset]); |
| 684 | } | 896 | } |
| 685 | } else { | 897 | } else { |
| 686 | 898 | ||
| @@ -703,6 +915,15 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle | |||
| 703 | static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, | 915 | static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, |
| 704 | tuple.type, &gl_buffer[buffer_offset]); | 916 | tuple.type, &gl_buffer[buffer_offset]); |
| 705 | break; | 917 | break; |
| 918 | case SurfaceParams::SurfaceTarget::TextureCubemap: | ||
| 919 | for (std::size_t face = 0; face < params.depth; ++face) { | ||
| 920 | glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), 0, x0, | ||
| 921 | y0, static_cast<GLsizei>(rect.GetWidth()), | ||
| 922 | static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, | ||
| 923 | &gl_buffer[buffer_offset]); | ||
| 924 | buffer_offset += params.size_in_bytes_2d; | ||
| 925 | } | ||
| 926 | break; | ||
| 706 | default: | 927 | default: |
| 707 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | 928 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", |
| 708 | static_cast<u32>(params.target)); | 929 | static_cast<u32>(params.target)); |
| @@ -722,8 +943,9 @@ RasterizerCacheOpenGL::RasterizerCacheOpenGL() { | |||
| 722 | copy_pbo.Create(); | 943 | copy_pbo.Create(); |
| 723 | } | 944 | } |
| 724 | 945 | ||
| 725 | Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { | 946 | Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config, |
| 726 | return GetSurface(SurfaceParams::CreateForTexture(config)); | 947 | const GLShader::SamplerEntry& entry) { |
| 948 | return GetSurface(SurfaceParams::CreateForTexture(config, entry)); | ||
| 727 | } | 949 | } |
| 728 | 950 | ||
| 729 | Surface RasterizerCacheOpenGL::GetDepthBufferSurface(bool preserve_contents) { | 951 | Surface RasterizerCacheOpenGL::GetDepthBufferSurface(bool preserve_contents) { |
| @@ -811,98 +1033,69 @@ Surface RasterizerCacheOpenGL::GetUncachedSurface(const SurfaceParams& params) { | |||
| 811 | return surface; | 1033 | return surface; |
| 812 | } | 1034 | } |
| 813 | 1035 | ||
| 814 | Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, | 1036 | Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface, |
| 815 | const SurfaceParams& new_params) { | 1037 | const SurfaceParams& new_params) { |
| 816 | // Verify surface is compatible for blitting | 1038 | // Verify surface is compatible for blitting |
| 817 | const auto& params{surface->GetSurfaceParams()}; | 1039 | auto old_params{old_surface->GetSurfaceParams()}; |
| 818 | 1040 | ||
| 819 | // Get a new surface with the new parameters, and blit the previous surface to it | 1041 | // Get a new surface with the new parameters, and blit the previous surface to it |
| 820 | Surface new_surface{GetUncachedSurface(new_params)}; | 1042 | Surface new_surface{GetUncachedSurface(new_params)}; |
| 821 | 1043 | ||
| 822 | if (params.pixel_format == new_params.pixel_format || | 1044 | // If the format is the same, just do a framebuffer blit. This is significantly faster than |
| 823 | !Settings::values.use_accurate_framebuffers) { | 1045 | // using PBOs. The is also likely less accurate, as textures will be converted rather than |
| 824 | // If the format is the same, just do a framebuffer blit. This is significantly faster than | 1046 | // reinterpreted. When use_accurate_framebuffers setting is enabled, perform a more accurate |
| 825 | // using PBOs. The is also likely less accurate, as textures will be converted rather than | 1047 | // surface copy, where pixels are reinterpreted as a new format (without conversion). This |
| 826 | // reinterpreted. | 1048 | // code path uses OpenGL PBOs and is quite slow. |
| 827 | 1049 | const bool is_blit{old_params.pixel_format == new_params.pixel_format || | |
| 828 | BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle, | 1050 | !Settings::values.use_accurate_framebuffers}; |
| 829 | params.GetRect(), params.type, read_framebuffer.handle, | ||
| 830 | draw_framebuffer.handle); | ||
| 831 | } else { | ||
| 832 | // When use_accurate_framebuffers setting is enabled, perform a more accurate surface copy, | ||
| 833 | // where pixels are reinterpreted as a new format (without conversion). This code path uses | ||
| 834 | // OpenGL PBOs and is quite slow. | ||
| 835 | |||
| 836 | auto source_format = GetFormatTuple(params.pixel_format, params.component_type); | ||
| 837 | auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type); | ||
| 838 | |||
| 839 | std::size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes()); | ||
| 840 | 1051 | ||
| 841 | glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo.handle); | 1052 | switch (new_params.target) { |
| 842 | glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); | 1053 | case SurfaceParams::SurfaceTarget::Texture2D: |
| 843 | if (source_format.compressed) { | 1054 | if (is_blit) { |
| 844 | glGetCompressedTextureImage(surface->Texture().handle, 0, | 1055 | BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle); |
| 845 | static_cast<GLsizei>(params.SizeInBytes()), nullptr); | ||
| 846 | } else { | 1056 | } else { |
| 847 | glGetTextureImage(surface->Texture().handle, 0, source_format.format, | 1057 | CopySurface(old_surface, new_surface, copy_pbo.handle); |
| 848 | source_format.type, static_cast<GLsizei>(params.SizeInBytes()), | ||
| 849 | nullptr); | ||
| 850 | } | 1058 | } |
| 851 | // If the new texture is bigger than the previous one, we need to fill in the rest with data | 1059 | break; |
| 852 | // from the CPU. | 1060 | case SurfaceParams::SurfaceTarget::TextureCubemap: { |
| 853 | if (params.SizeInBytes() < new_params.SizeInBytes()) { | 1061 | if (old_params.rt.array_mode != 1) { |
| 854 | // Upload the rest of the memory. | 1062 | // TODO(bunnei): This is used by Breath of the Wild, I'm not sure how to implement this |
| 855 | if (new_params.is_tiled) { | 1063 | // yet (array rendering used as a cubemap texture). |
| 856 | // TODO(Subv): We might have to de-tile the subtexture and re-tile it with the rest | 1064 | LOG_CRITICAL(HW_GPU, "Unhandled rendertarget array_mode {}", old_params.rt.array_mode); |
| 857 | // of the data in this case. Games like Super Mario Odyssey seem to hit this case | 1065 | UNREACHABLE(); |
| 858 | // when drawing, it re-uses the memory of a previous texture as a bigger framebuffer | 1066 | return new_surface; |
| 859 | // but it doesn't clear it beforehand, the texture is already full of zeros. | ||
| 860 | LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during " | ||
| 861 | "reinterpretation but the texture is tiled."); | ||
| 862 | } | ||
| 863 | std::size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes(); | ||
| 864 | std::vector<u8> data(remaining_size); | ||
| 865 | Memory::ReadBlock(new_params.addr + params.SizeInBytes(), data.data(), data.size()); | ||
| 866 | glBufferSubData(GL_PIXEL_PACK_BUFFER, params.SizeInBytes(), remaining_size, | ||
| 867 | data.data()); | ||
| 868 | } | 1067 | } |
| 869 | 1068 | ||
| 870 | glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); | 1069 | // This seems to be used for render-to-cubemap texture |
| 871 | 1070 | ASSERT_MSG(old_params.target == SurfaceParams::SurfaceTarget::Texture2D, "Unexpected"); | |
| 872 | const auto& dest_rect{new_params.GetRect()}; | 1071 | ASSERT_MSG(old_params.pixel_format == new_params.pixel_format, "Unexpected"); |
| 873 | 1072 | ASSERT_MSG(old_params.rt.base_layer == 0, "Unimplemented"); | |
| 874 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, copy_pbo.handle); | 1073 | |
| 875 | if (dest_format.compressed) { | 1074 | // TODO(bunnei): Verify the below - this stride seems to be in 32-bit words, not pixels. |
| 876 | LOG_CRITICAL(HW_GPU, "Compressed copy is unimplemented!"); | 1075 | // Tested with Splatoon 2, Super Mario Odyssey, and Breath of the Wild. |
| 877 | UNREACHABLE(); | 1076 | const std::size_t byte_stride{old_params.rt.layer_stride * sizeof(u32)}; |
| 878 | } else { | 1077 | |
| 879 | switch (new_params.target) { | 1078 | for (std::size_t index = 0; index < new_params.depth; ++index) { |
| 880 | case SurfaceParams::SurfaceTarget::Texture1D: | 1079 | Surface face_surface{TryGetReservedSurface(old_params)}; |
| 881 | glTextureSubImage1D(new_surface->Texture().handle, 0, 0, | 1080 | ASSERT_MSG(face_surface, "Unexpected"); |
| 882 | static_cast<GLsizei>(dest_rect.GetWidth()), dest_format.format, | 1081 | |
| 883 | dest_format.type, nullptr); | 1082 | if (is_blit) { |
| 884 | break; | 1083 | BlitSurface(face_surface, new_surface, read_framebuffer.handle, |
| 885 | case SurfaceParams::SurfaceTarget::Texture2D: | 1084 | draw_framebuffer.handle, face_surface->GetSurfaceParams().rt.index, |
| 886 | glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0, | 1085 | new_params.rt.index, index); |
| 887 | static_cast<GLsizei>(dest_rect.GetWidth()), | 1086 | } else { |
| 888 | static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, | 1087 | CopySurface(face_surface, new_surface, copy_pbo.handle, |
| 889 | dest_format.type, nullptr); | 1088 | face_surface->GetSurfaceParams().rt.index, new_params.rt.index, index); |
| 890 | break; | ||
| 891 | case SurfaceParams::SurfaceTarget::Texture3D: | ||
| 892 | case SurfaceParams::SurfaceTarget::Texture2DArray: | ||
| 893 | glTextureSubImage3D(new_surface->Texture().handle, 0, 0, 0, 0, | ||
| 894 | static_cast<GLsizei>(dest_rect.GetWidth()), | ||
| 895 | static_cast<GLsizei>(dest_rect.GetHeight()), | ||
| 896 | static_cast<GLsizei>(new_params.depth), dest_format.format, | ||
| 897 | dest_format.type, nullptr); | ||
| 898 | break; | ||
| 899 | default: | ||
| 900 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | ||
| 901 | static_cast<u32>(params.target)); | ||
| 902 | UNREACHABLE(); | ||
| 903 | } | 1089 | } |
| 1090 | |||
| 1091 | old_params.addr += byte_stride; | ||
| 904 | } | 1092 | } |
| 905 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | 1093 | break; |
| 1094 | } | ||
| 1095 | default: | ||
| 1096 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | ||
| 1097 | static_cast<u32>(new_params.target)); | ||
| 1098 | UNREACHABLE(); | ||
| 906 | } | 1099 | } |
| 907 | 1100 | ||
| 908 | return new_surface; | 1101 | return new_surface; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 80c5f324b..49025a3fe 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h | |||
| @@ -9,12 +9,14 @@ | |||
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | #include <vector> | 10 | #include <vector> |
| 11 | 11 | ||
| 12 | #include "common/alignment.h" | ||
| 12 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 13 | #include "common/hash.h" | 14 | #include "common/hash.h" |
| 14 | #include "common/math_util.h" | 15 | #include "common/math_util.h" |
| 15 | #include "video_core/engines/maxwell_3d.h" | 16 | #include "video_core/engines/maxwell_3d.h" |
| 16 | #include "video_core/rasterizer_cache.h" | 17 | #include "video_core/rasterizer_cache.h" |
| 17 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 18 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 19 | #include "video_core/renderer_opengl/gl_shader_gen.h" | ||
| 18 | #include "video_core/textures/texture.h" | 20 | #include "video_core/textures/texture.h" |
| 19 | 21 | ||
| 20 | namespace OpenGL { | 22 | namespace OpenGL { |
| @@ -126,6 +128,8 @@ struct SurfaceParams { | |||
| 126 | case Tegra::Texture::TextureType::Texture2D: | 128 | case Tegra::Texture::TextureType::Texture2D: |
| 127 | case Tegra::Texture::TextureType::Texture2DNoMipmap: | 129 | case Tegra::Texture::TextureType::Texture2DNoMipmap: |
| 128 | return SurfaceTarget::Texture2D; | 130 | return SurfaceTarget::Texture2D; |
| 131 | case Tegra::Texture::TextureType::TextureCubemap: | ||
| 132 | return SurfaceTarget::TextureCubemap; | ||
| 129 | case Tegra::Texture::TextureType::Texture1DArray: | 133 | case Tegra::Texture::TextureType::Texture1DArray: |
| 130 | return SurfaceTarget::Texture1DArray; | 134 | return SurfaceTarget::Texture1DArray; |
| 131 | case Tegra::Texture::TextureType::Texture2DArray: | 135 | case Tegra::Texture::TextureType::Texture2DArray: |
| @@ -689,17 +693,23 @@ struct SurfaceParams { | |||
| 689 | /// Returns the rectangle corresponding to this surface | 693 | /// Returns the rectangle corresponding to this surface |
| 690 | MathUtil::Rectangle<u32> GetRect() const; | 694 | MathUtil::Rectangle<u32> GetRect() const; |
| 691 | 695 | ||
| 692 | /// Returns the size of this surface in bytes, adjusted for compression | 696 | /// Returns the size of this surface as a 2D texture in bytes, adjusted for compression |
| 693 | std::size_t SizeInBytes() const { | 697 | std::size_t SizeInBytes2D() const { |
| 694 | const u32 compression_factor{GetCompressionFactor(pixel_format)}; | 698 | const u32 compression_factor{GetCompressionFactor(pixel_format)}; |
| 695 | ASSERT(width % compression_factor == 0); | 699 | ASSERT(width % compression_factor == 0); |
| 696 | ASSERT(height % compression_factor == 0); | 700 | ASSERT(height % compression_factor == 0); |
| 697 | return (width / compression_factor) * (height / compression_factor) * | 701 | return (width / compression_factor) * (height / compression_factor) * |
| 698 | GetFormatBpp(pixel_format) * depth / CHAR_BIT; | 702 | GetFormatBpp(pixel_format) / CHAR_BIT; |
| 703 | } | ||
| 704 | |||
| 705 | /// Returns the total size of this surface in bytes, adjusted for compression | ||
| 706 | std::size_t SizeInBytesTotal() const { | ||
| 707 | return SizeInBytes2D() * depth; | ||
| 699 | } | 708 | } |
| 700 | 709 | ||
| 701 | /// Creates SurfaceParams from a texture configuration | 710 | /// Creates SurfaceParams from a texture configuration |
| 702 | static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config); | 711 | static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config, |
| 712 | const GLShader::SamplerEntry& entry); | ||
| 703 | 713 | ||
| 704 | /// Creates SurfaceParams from a framebuffer configuration | 714 | /// Creates SurfaceParams from a framebuffer configuration |
| 705 | static SurfaceParams CreateForFramebuffer(std::size_t index); | 715 | static SurfaceParams CreateForFramebuffer(std::size_t index); |
| @@ -711,8 +721,9 @@ struct SurfaceParams { | |||
| 711 | 721 | ||
| 712 | /// Checks if surfaces are compatible for caching | 722 | /// Checks if surfaces are compatible for caching |
| 713 | bool IsCompatibleSurface(const SurfaceParams& other) const { | 723 | bool IsCompatibleSurface(const SurfaceParams& other) const { |
| 714 | return std::tie(pixel_format, type, width, height) == | 724 | return std::tie(pixel_format, type, width, height, target, depth) == |
| 715 | std::tie(other.pixel_format, other.type, other.width, other.height); | 725 | std::tie(other.pixel_format, other.type, other.width, other.height, other.target, |
| 726 | other.depth); | ||
| 716 | } | 727 | } |
| 717 | 728 | ||
| 718 | VAddr addr; | 729 | VAddr addr; |
| @@ -725,8 +736,18 @@ struct SurfaceParams { | |||
| 725 | u32 height; | 736 | u32 height; |
| 726 | u32 depth; | 737 | u32 depth; |
| 727 | u32 unaligned_height; | 738 | u32 unaligned_height; |
| 728 | std::size_t size_in_bytes; | 739 | std::size_t size_in_bytes_total; |
| 740 | std::size_t size_in_bytes_2d; | ||
| 729 | SurfaceTarget target; | 741 | SurfaceTarget target; |
| 742 | u32 max_mip_level; | ||
| 743 | |||
| 744 | // Render target specific parameters, not used in caching | ||
| 745 | struct { | ||
| 746 | u32 index; | ||
| 747 | u32 array_mode; | ||
| 748 | u32 layer_stride; | ||
| 749 | u32 base_layer; | ||
| 750 | } rt; | ||
| 730 | }; | 751 | }; |
| 731 | 752 | ||
| 732 | }; // namespace OpenGL | 753 | }; // namespace OpenGL |
| @@ -736,6 +757,7 @@ struct SurfaceReserveKey : Common::HashableStruct<OpenGL::SurfaceParams> { | |||
| 736 | static SurfaceReserveKey Create(const OpenGL::SurfaceParams& params) { | 757 | static SurfaceReserveKey Create(const OpenGL::SurfaceParams& params) { |
| 737 | SurfaceReserveKey res; | 758 | SurfaceReserveKey res; |
| 738 | res.state = params; | 759 | res.state = params; |
| 760 | res.state.rt = {}; // Ignore rt config in caching | ||
| 739 | return res; | 761 | return res; |
| 740 | } | 762 | } |
| 741 | }; | 763 | }; |
| @@ -759,7 +781,7 @@ public: | |||
| 759 | } | 781 | } |
| 760 | 782 | ||
| 761 | std::size_t GetSizeInBytes() const { | 783 | std::size_t GetSizeInBytes() const { |
| 762 | return params.size_in_bytes; | 784 | return params.size_in_bytes_total; |
| 763 | } | 785 | } |
| 764 | 786 | ||
| 765 | const OGLTexture& Texture() const { | 787 | const OGLTexture& Texture() const { |
| @@ -800,7 +822,8 @@ public: | |||
| 800 | RasterizerCacheOpenGL(); | 822 | RasterizerCacheOpenGL(); |
| 801 | 823 | ||
| 802 | /// Get a surface based on the texture configuration | 824 | /// Get a surface based on the texture configuration |
| 803 | Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config); | 825 | Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config, |
| 826 | const GLShader::SamplerEntry& entry); | ||
| 804 | 827 | ||
| 805 | /// Get the depth surface based on the framebuffer configuration | 828 | /// Get the depth surface based on the framebuffer configuration |
| 806 | Surface GetDepthBufferSurface(bool preserve_contents); | 829 | Surface GetDepthBufferSurface(bool preserve_contents); |
| @@ -822,7 +845,7 @@ private: | |||
| 822 | Surface GetUncachedSurface(const SurfaceParams& params); | 845 | Surface GetUncachedSurface(const SurfaceParams& params); |
| 823 | 846 | ||
| 824 | /// Recreates a surface with new parameters | 847 | /// Recreates a surface with new parameters |
| 825 | Surface RecreateSurface(const Surface& surface, const SurfaceParams& new_params); | 848 | Surface RecreateSurface(const Surface& old_surface, const SurfaceParams& new_params); |
| 826 | 849 | ||
| 827 | /// Reserves a unique surface that can be reused later | 850 | /// Reserves a unique surface that can be reused later |
| 828 | void ReserveSurface(const Surface& surface); | 851 | void ReserveSurface(const Surface& surface); |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index b3e95187e..320babdb1 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -2000,6 +2000,14 @@ private: | |||
| 2000 | } | 2000 | } |
| 2001 | break; | 2001 | break; |
| 2002 | } | 2002 | } |
| 2003 | case Tegra::Shader::TextureType::TextureCube: { | ||
| 2004 | ASSERT_MSG(!is_array, "Unimplemented"); | ||
| 2005 | std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2006 | std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2007 | std::string z = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2008 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | ||
| 2009 | break; | ||
| 2010 | } | ||
| 2003 | default: | 2011 | default: |
| 2004 | LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", | 2012 | LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", |
| 2005 | static_cast<u32>(texture_type)); | 2013 | static_cast<u32>(texture_type)); |
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index c2fb824b2..14aea4838 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h | |||
| @@ -165,6 +165,8 @@ struct TICEntry { | |||
| 165 | 165 | ||
| 166 | // High 16 bits of the pitch value | 166 | // High 16 bits of the pitch value |
| 167 | BitField<0, 16, u32> pitch_high; | 167 | BitField<0, 16, u32> pitch_high; |
| 168 | |||
| 169 | BitField<28, 4, u32> max_mip_level; | ||
| 168 | }; | 170 | }; |
| 169 | union { | 171 | union { |
| 170 | BitField<0, 16, u32> width_minus_1; | 172 | BitField<0, 16, u32> width_minus_1; |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index d74489935..27015d02c 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -622,9 +622,9 @@ void GMainWindow::BootGame(const QString& filename) { | |||
| 622 | std::string title_name; | 622 | std::string title_name; |
| 623 | const auto res = Core::System::GetInstance().GetGameName(title_name); | 623 | const auto res = Core::System::GetInstance().GetGameName(title_name); |
| 624 | if (res != Loader::ResultStatus::Success) { | 624 | if (res != Loader::ResultStatus::Success) { |
| 625 | const u64 program_id = Core::System::GetInstance().CurrentProcess()->program_id; | 625 | const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); |
| 626 | 626 | ||
| 627 | const auto [nacp, icon_file] = FileSys::PatchManager(program_id).GetControlMetadata(); | 627 | const auto [nacp, icon_file] = FileSys::PatchManager(title_id).GetControlMetadata(); |
| 628 | if (nacp != nullptr) | 628 | if (nacp != nullptr) |
| 629 | title_name = nacp->GetApplicationName(); | 629 | title_name = nacp->GetApplicationName(); |
| 630 | 630 | ||
| @@ -1055,11 +1055,21 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 1055 | return; | 1055 | return; |
| 1056 | } | 1056 | } |
| 1057 | 1057 | ||
| 1058 | if (index >= 5) | 1058 | // If index is equal to or past Game, add the jump in TitleType. |
| 1059 | index += 0x7B; | 1059 | if (index >= 5) { |
| 1060 | index += static_cast<size_t>(FileSys::TitleType::Application) - | ||
| 1061 | static_cast<size_t>(FileSys::TitleType::FirmwarePackageB); | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | FileSys::InstallResult res; | ||
| 1065 | if (index >= static_cast<size_t>(FileSys::TitleType::Application)) { | ||
| 1066 | res = Service::FileSystem::GetUserNANDContents()->InstallEntry( | ||
| 1067 | nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); | ||
| 1068 | } else { | ||
| 1069 | res = Service::FileSystem::GetSystemNANDContents()->InstallEntry( | ||
| 1070 | nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); | ||
| 1071 | } | ||
| 1060 | 1072 | ||
| 1061 | const auto res = Service::FileSystem::GetUserNANDContents()->InstallEntry( | ||
| 1062 | nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); | ||
| 1063 | if (res == FileSys::InstallResult::Success) { | 1073 | if (res == FileSys::InstallResult::Success) { |
| 1064 | success(); | 1074 | success(); |
| 1065 | } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { | 1075 | } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { |