summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/arm/arm_interface.h10
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp12
-rw-r--r--src/core/file_sys/romfs_factory.cpp2
-rw-r--r--src/core/file_sys/savedata_factory.cpp2
-rw-r--r--src/core/gdbstub/gdbstub.cpp6
-rw-r--r--src/core/hle/kernel/errors.h2
-rw-r--r--src/core/hle/kernel/process.cpp1
-rw-r--r--src/core/hle/kernel/process.h107
-rw-r--r--src/core/hle/kernel/scheduler.cpp2
-rw-r--r--src/core/hle/kernel/shared_memory.cpp14
-rw-r--r--src/core/hle/kernel/svc.cpp62
-rw-r--r--src/core/hle/kernel/svc_wrap.h5
-rw-r--r--src/core/hle/kernel/thread.cpp4
-rw-r--r--src/core/hle/service/fatal/fatal.cpp2
-rw-r--r--src/core/hle/service/ns/pl_u.cpp6
-rw-r--r--src/core/hle/service/vi/vi.cpp20
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp2
-rw-r--r--src/core/loader/elf.cpp2
-rw-r--r--src/core/loader/nro.cpp2
-rw-r--r--src/core/loader/nso.cpp2
-rw-r--r--src/core/memory.cpp14
-rw-r--r--src/tests/core/arm/arm_test_common.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp429
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h43
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp8
-rw-r--r--src/video_core/textures/texture.h2
-rw-r--r--src/yuzu/main.cpp22
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
131std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const { 131std::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
252void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { 254void 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
261void ARM_Dynarmic::PrepareReschedule() { 265void 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,
58constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); 59constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
59constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); 60constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
60constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); 61constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize);
62constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::Kernel, ErrCodes::AlreadyRegistered);
61constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); 63constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
62constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel, 64constexpr 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
48void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { 48void 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
217private: 240private:
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
124ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { 124ResultCode 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
130VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { 130VMAPermission 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
418static ResultCode GetThreadContext(Handle handle, VAddr addr) { 418static 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
67template <ResultCode func(u64, u32)>
68void SvcWrap() {
69 FuncReturn(func(Param(0), static_cast<u32>(Param(1))).raw);
70}
71
67template <ResultCode func(u64*, u64)> 72template <ResultCode func(u64*, u64)>
68void SvcWrap() { 73void 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) {
259SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, 259SharedPtr<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
53static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) { 53static 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
318void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { 318void 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
668class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { 686class 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
119static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) { 119static 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
216bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { 216bool 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
388void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, 388void 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
453void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, 453void 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
500void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { 500void 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
541void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, 541void 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
403static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex, 434static 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
562static 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
457CachedSurface::CachedSurface(const SurfaceParams& params) 648CachedSurface::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
725Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { 946Surface 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
729Surface RasterizerCacheOpenGL::GetDepthBufferSurface(bool preserve_contents) { 951Surface 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
814Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, 1036Surface 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
20namespace OpenGL { 22namespace 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) {