summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/core.cpp3
-rw-r--r--src/core/hle/kernel/vm_manager.cpp72
-rw-r--r--src/core/hle/kernel/vm_manager.h8
-rw-r--r--src/core/hle/service/acc/acc.cpp124
-rw-r--r--src/core/hle/service/acc/acc.h1
-rw-r--r--src/core/hle/service/acc/acc_su.cpp2
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp11
-rw-r--r--src/core/hle/service/acc/profile_manager.h2
-rw-r--r--src/core/hle/service/am/am.cpp50
-rw-r--r--src/core/hle/service/am/am.h28
-rw-r--r--src/core/hle/service/am/applet_ae.cpp14
-rw-r--r--src/core/hle/service/am/applet_oe.cpp9
-rw-r--r--src/core/hle/service/am/applets/applets.cpp25
-rw-r--r--src/core/hle/service/am/applets/applets.h17
-rw-r--r--src/core/hle/service/am/applets/error.cpp7
-rw-r--r--src/core/hle/service/am/applets/error.h7
-rw-r--r--src/core/hle/service/am/applets/general_backend.cpp13
-rw-r--r--src/core/hle/service/am/applets/general_backend.h12
-rw-r--r--src/core/hle/service/am/applets/profile_select.cpp5
-rw-r--r--src/core/hle/service/am/applets/profile_select.h7
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp5
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.h7
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp19
-rw-r--r--src/core/hle/service/am/applets/web_browser.h12
-rw-r--r--src/core/loader/nro.cpp9
-rw-r--r--src/core/loader/nro.h1
-rw-r--r--src/video_core/engines/kepler_compute.cpp53
-rw-r--r--src/video_core/engines/kepler_compute.h23
-rw-r--r--src/video_core/engines/maxwell_3d.cpp22
-rw-r--r--src/video_core/engines/maxwell_3d.h12
-rw-r--r--src/video_core/engines/shader_bytecode.h54
-rw-r--r--src/video_core/macro_interpreter.cpp22
-rw-r--r--src/video_core/macro_interpreter.h8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp141
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h19
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp249
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp19
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp89
-rw-r--r--src/video_core/renderer_opengl/gl_state.h29
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h22
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp15
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h3
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp301
-rw-r--r--src/video_core/renderer_vulkan/vk_device.h62
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp98
-rw-r--r--src/video_core/shader/decode/image.cpp104
-rw-r--r--src/video_core/shader/decode/memory.cpp48
-rw-r--r--src/video_core/shader/decode/shift.cpp19
-rw-r--r--src/video_core/shader/decode/warp.cpp47
-rw-r--r--src/video_core/shader/node.h109
-rw-r--r--src/video_core/shader/shader_ir.cpp9
-rw-r--r--src/video_core/shader/shader_ir.h20
-rw-r--r--src/video_core/surface.cpp20
-rw-r--r--src/video_core/surface.h2
-rw-r--r--src/video_core/texture_cache/surface_base.h12
-rw-r--r--src/video_core/texture_cache/surface_params.cpp134
-rw-r--r--src/video_core/texture_cache/surface_params.h9
-rw-r--r--src/video_core/texture_cache/surface_view.cpp2
-rw-r--r--src/video_core/texture_cache/surface_view.h20
-rw-r--r--src/video_core/texture_cache/texture_cache.h21
61 files changed, 1688 insertions, 602 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 20d64f3b0..3d0978cbf 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -104,7 +104,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
104 return vfs->OpenFile(path, FileSys::Mode::Read); 104 return vfs->OpenFile(path, FileSys::Mode::Read);
105} 105}
106struct System::Impl { 106struct System::Impl {
107 explicit Impl(System& system) : kernel{system}, cpu_core_manager{system}, reporter{system} {} 107 explicit Impl(System& system)
108 : kernel{system}, cpu_core_manager{system}, applet_manager{system}, reporter{system} {}
108 109
109 Cpu& CurrentCpuCore() { 110 Cpu& CurrentCpuCore() {
110 return cpu_core_manager.GetCurrentCore(); 111 return cpu_core_manager.GetCurrentCore();
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 40cea1e7c..c7af87073 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -296,12 +296,6 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) {
296} 296}
297 297
298ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) { 298ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) {
299 const auto end_addr = target + size;
300 const auto last_addr = end_addr - 1;
301 VAddr cur_addr = target;
302
303 ResultCode result = RESULT_SUCCESS;
304
305 // Check how much memory we've already mapped. 299 // Check how much memory we've already mapped.
306 const auto mapped_size_result = SizeOfAllocatedVMAsInRange(target, size); 300 const auto mapped_size_result = SizeOfAllocatedVMAsInRange(target, size);
307 if (mapped_size_result.Failed()) { 301 if (mapped_size_result.Failed()) {
@@ -324,13 +318,16 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) {
324 318
325 // Keep track of the memory regions we unmap. 319 // Keep track of the memory regions we unmap.
326 std::vector<std::pair<u64, u64>> mapped_regions; 320 std::vector<std::pair<u64, u64>> mapped_regions;
321 ResultCode result = RESULT_SUCCESS;
327 322
328 // Iterate, trying to map memory. 323 // Iterate, trying to map memory.
329 { 324 {
330 cur_addr = target; 325 const auto end_addr = target + size;
326 const auto last_addr = end_addr - 1;
327 VAddr cur_addr = target;
331 328
332 auto iter = FindVMA(target); 329 auto iter = FindVMA(target);
333 ASSERT_MSG(iter != vma_map.end(), "MapPhysicalMemory iter != end"); 330 ASSERT(iter != vma_map.end());
334 331
335 while (true) { 332 while (true) {
336 const auto& vma = iter->second; 333 const auto& vma = iter->second;
@@ -342,7 +339,7 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) {
342 const auto map_size = std::min(end_addr - cur_addr, vma_end - cur_addr); 339 const auto map_size = std::min(end_addr - cur_addr, vma_end - cur_addr);
343 if (vma.state == MemoryState::Unmapped) { 340 if (vma.state == MemoryState::Unmapped) {
344 const auto map_res = 341 const auto map_res =
345 MapMemoryBlock(cur_addr, std::make_shared<PhysicalMemory>(map_size, 0), 0, 342 MapMemoryBlock(cur_addr, std::make_shared<PhysicalMemory>(map_size), 0,
346 map_size, MemoryState::Heap, VMAPermission::ReadWrite); 343 map_size, MemoryState::Heap, VMAPermission::ReadWrite);
347 result = map_res.Code(); 344 result = map_res.Code();
348 if (result.IsError()) { 345 if (result.IsError()) {
@@ -360,7 +357,7 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) {
360 // Advance to the next block. 357 // Advance to the next block.
361 cur_addr = vma_end; 358 cur_addr = vma_end;
362 iter = FindVMA(cur_addr); 359 iter = FindVMA(cur_addr);
363 ASSERT_MSG(iter != vma_map.end(), "MapPhysicalMemory iter != end"); 360 ASSERT(iter != vma_map.end());
364 } 361 }
365 } 362 }
366 363
@@ -368,7 +365,7 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) {
368 if (result.IsError()) { 365 if (result.IsError()) {
369 for (const auto [unmap_address, unmap_size] : mapped_regions) { 366 for (const auto [unmap_address, unmap_size] : mapped_regions) {
370 ASSERT_MSG(UnmapRange(unmap_address, unmap_size).IsSuccess(), 367 ASSERT_MSG(UnmapRange(unmap_address, unmap_size).IsSuccess(),
371 "MapPhysicalMemory un-map on error"); 368 "Failed to unmap memory range.");
372 } 369 }
373 370
374 return result; 371 return result;
@@ -381,12 +378,6 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) {
381} 378}
382 379
383ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) { 380ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) {
384 const auto end_addr = target + size;
385 const auto last_addr = end_addr - 1;
386 VAddr cur_addr = target;
387
388 ResultCode result = RESULT_SUCCESS;
389
390 // Check how much memory is currently mapped. 381 // Check how much memory is currently mapped.
391 const auto mapped_size_result = SizeOfUnmappablePhysicalMemoryInRange(target, size); 382 const auto mapped_size_result = SizeOfUnmappablePhysicalMemoryInRange(target, size);
392 if (mapped_size_result.Failed()) { 383 if (mapped_size_result.Failed()) {
@@ -401,13 +392,16 @@ ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) {
401 392
402 // Keep track of the memory regions we unmap. 393 // Keep track of the memory regions we unmap.
403 std::vector<std::pair<u64, u64>> unmapped_regions; 394 std::vector<std::pair<u64, u64>> unmapped_regions;
395 ResultCode result = RESULT_SUCCESS;
404 396
405 // Try to unmap regions. 397 // Try to unmap regions.
406 { 398 {
407 cur_addr = target; 399 const auto end_addr = target + size;
400 const auto last_addr = end_addr - 1;
401 VAddr cur_addr = target;
408 402
409 auto iter = FindVMA(target); 403 auto iter = FindVMA(target);
410 ASSERT_MSG(iter != vma_map.end(), "UnmapPhysicalMemory iter != end"); 404 ASSERT(iter != vma_map.end());
411 405
412 while (true) { 406 while (true) {
413 const auto& vma = iter->second; 407 const auto& vma = iter->second;
@@ -434,7 +428,7 @@ ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) {
434 // Advance to the next block. 428 // Advance to the next block.
435 cur_addr = vma_end; 429 cur_addr = vma_end;
436 iter = FindVMA(cur_addr); 430 iter = FindVMA(cur_addr);
437 ASSERT_MSG(iter != vma_map.end(), "UnmapPhysicalMemory iter != end"); 431 ASSERT(iter != vma_map.end());
438 } 432 }
439 } 433 }
440 434
@@ -443,10 +437,12 @@ ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) {
443 if (result.IsError()) { 437 if (result.IsError()) {
444 for (const auto [map_address, map_size] : unmapped_regions) { 438 for (const auto [map_address, map_size] : unmapped_regions) {
445 const auto remap_res = 439 const auto remap_res =
446 MapMemoryBlock(map_address, std::make_shared<PhysicalMemory>(map_size, 0), 0, 440 MapMemoryBlock(map_address, std::make_shared<PhysicalMemory>(map_size), 0, map_size,
447 map_size, MemoryState::Heap, VMAPermission::None); 441 MemoryState::Heap, VMAPermission::None);
448 ASSERT_MSG(remap_res.Succeeded(), "UnmapPhysicalMemory re-map on error"); 442 ASSERT_MSG(remap_res.Succeeded(), "Failed to remap a memory block.");
449 } 443 }
444
445 return result;
450 } 446 }
451 447
452 // Update mapped amount 448 // Update mapped amount
@@ -757,20 +753,26 @@ void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryAre
757 // Always merge allocated memory blocks, even when they don't share the same backing block. 753 // Always merge allocated memory blocks, even when they don't share the same backing block.
758 if (left.type == VMAType::AllocatedMemoryBlock && 754 if (left.type == VMAType::AllocatedMemoryBlock &&
759 (left.backing_block != right.backing_block || left.offset + left.size != right.offset)) { 755 (left.backing_block != right.backing_block || left.offset + left.size != right.offset)) {
756 const auto right_begin = right.backing_block->begin() + right.offset;
757 const auto right_end = right_begin + right.size;
758
760 // Check if we can save work. 759 // Check if we can save work.
761 if (left.offset == 0 && left.size == left.backing_block->size()) { 760 if (left.offset == 0 && left.size == left.backing_block->size()) {
762 // Fast case: left is an entire backing block. 761 // Fast case: left is an entire backing block.
763 left.backing_block->insert(left.backing_block->end(), 762 left.backing_block->insert(left.backing_block->end(), right_begin, right_end);
764 right.backing_block->begin() + right.offset,
765 right.backing_block->begin() + right.offset + right.size);
766 } else { 763 } else {
767 // Slow case: make a new memory block for left and right. 764 // Slow case: make a new memory block for left and right.
765 const auto left_begin = left.backing_block->begin() + left.offset;
766 const auto left_end = left_begin + left.size;
767 const auto left_size = static_cast<std::size_t>(std::distance(left_begin, left_end));
768 const auto right_size = static_cast<std::size_t>(std::distance(right_begin, right_end));
769
768 auto new_memory = std::make_shared<PhysicalMemory>(); 770 auto new_memory = std::make_shared<PhysicalMemory>();
769 new_memory->insert(new_memory->end(), left.backing_block->begin() + left.offset, 771 new_memory->reserve(left_size + right_size);
770 left.backing_block->begin() + left.offset + left.size); 772 new_memory->insert(new_memory->end(), left_begin, left_end);
771 new_memory->insert(new_memory->end(), right.backing_block->begin() + right.offset, 773 new_memory->insert(new_memory->end(), right_begin, right_end);
772 right.backing_block->begin() + right.offset + right.size); 774
773 left.backing_block = new_memory; 775 left.backing_block = std::move(new_memory);
774 left.offset = 0; 776 left.offset = 0;
775 } 777 }
776 778
@@ -965,7 +967,7 @@ ResultVal<std::size_t> VMManager::SizeOfAllocatedVMAsInRange(VAddr address,
965 967
966 VAddr cur_addr = address; 968 VAddr cur_addr = address;
967 auto iter = FindVMA(cur_addr); 969 auto iter = FindVMA(cur_addr);
968 ASSERT_MSG(iter != vma_map.end(), "SizeOfAllocatedVMAsInRange iter != end"); 970 ASSERT(iter != vma_map.end());
969 971
970 while (true) { 972 while (true) {
971 const auto& vma = iter->second; 973 const auto& vma = iter->second;
@@ -986,7 +988,7 @@ ResultVal<std::size_t> VMManager::SizeOfAllocatedVMAsInRange(VAddr address,
986 // Advance to the next block. 988 // Advance to the next block.
987 cur_addr = vma_end; 989 cur_addr = vma_end;
988 iter = std::next(iter); 990 iter = std::next(iter);
989 ASSERT_MSG(iter != vma_map.end(), "SizeOfAllocatedVMAsInRange iter != end"); 991 ASSERT(iter != vma_map.end());
990 } 992 }
991 993
992 return MakeResult(mapped_size); 994 return MakeResult(mapped_size);
@@ -1000,7 +1002,7 @@ ResultVal<std::size_t> VMManager::SizeOfUnmappablePhysicalMemoryInRange(VAddr ad
1000 1002
1001 VAddr cur_addr = address; 1003 VAddr cur_addr = address;
1002 auto iter = FindVMA(cur_addr); 1004 auto iter = FindVMA(cur_addr);
1003 ASSERT_MSG(iter != vma_map.end(), "SizeOfUnmappablePhysicalMemoryInRange iter != end"); 1005 ASSERT(iter != vma_map.end());
1004 1006
1005 while (true) { 1007 while (true) {
1006 const auto& vma = iter->second; 1008 const auto& vma = iter->second;
@@ -1029,7 +1031,7 @@ ResultVal<std::size_t> VMManager::SizeOfUnmappablePhysicalMemoryInRange(VAddr ad
1029 // Advance to the next block. 1031 // Advance to the next block.
1030 cur_addr = vma_end; 1032 cur_addr = vma_end;
1031 iter = std::next(iter); 1033 iter = std::next(iter);
1032 ASSERT_MSG(iter != vma_map.end(), "SizeOfUnmappablePhysicalMemoryInRange iter != end"); 1034 ASSERT(iter != vma_map.end());
1033 } 1035 }
1034 1036
1035 return MakeResult(mapped_size); 1037 return MakeResult(mapped_size);
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index b18cde619..850a7ebc3 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -454,8 +454,8 @@ public:
454 454
455 /// Maps memory at a given address. 455 /// Maps memory at a given address.
456 /// 456 ///
457 /// @param addr The virtual address to map memory at. 457 /// @param target The virtual address to map memory at.
458 /// @param size The amount of memory to map. 458 /// @param size The amount of memory to map.
459 /// 459 ///
460 /// @note The destination address must lie within the Map region. 460 /// @note The destination address must lie within the Map region.
461 /// 461 ///
@@ -468,8 +468,8 @@ public:
468 468
469 /// Unmaps memory at a given address. 469 /// Unmaps memory at a given address.
470 /// 470 ///
471 /// @param addr The virtual address to unmap memory at. 471 /// @param target The virtual address to unmap memory at.
472 /// @param size The amount of memory to unmap. 472 /// @param size The amount of memory to unmap.
473 /// 473 ///
474 /// @note The destination address must lie within the Map region. 474 /// @note The destination address must lie within the Map region.
475 /// 475 ///
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index c01ee3eda..a7c55e116 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -31,6 +31,9 @@
31 31
32namespace Service::Account { 32namespace Service::Account {
33 33
34constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 30};
35constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100};
36
34static std::string GetImagePath(Common::UUID uuid) { 37static std::string GetImagePath(Common::UUID uuid) {
35 return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + 38 return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
36 "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; 39 "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg";
@@ -41,20 +44,31 @@ static constexpr u32 SanitizeJPEGSize(std::size_t size) {
41 return static_cast<u32>(std::min(size, max_jpeg_image_size)); 44 return static_cast<u32>(std::min(size, max_jpeg_image_size));
42} 45}
43 46
44class IProfile final : public ServiceFramework<IProfile> { 47class IProfileCommon : public ServiceFramework<IProfileCommon> {
45public: 48public:
46 explicit IProfile(Common::UUID user_id, ProfileManager& profile_manager) 49 explicit IProfileCommon(const char* name, bool editor_commands, Common::UUID user_id,
47 : ServiceFramework("IProfile"), profile_manager(profile_manager), user_id(user_id) { 50 ProfileManager& profile_manager)
51 : ServiceFramework(name), profile_manager(profile_manager), user_id(user_id) {
48 static const FunctionInfo functions[] = { 52 static const FunctionInfo functions[] = {
49 {0, &IProfile::Get, "Get"}, 53 {0, &IProfileCommon::Get, "Get"},
50 {1, &IProfile::GetBase, "GetBase"}, 54 {1, &IProfileCommon::GetBase, "GetBase"},
51 {10, &IProfile::GetImageSize, "GetImageSize"}, 55 {10, &IProfileCommon::GetImageSize, "GetImageSize"},
52 {11, &IProfile::LoadImage, "LoadImage"}, 56 {11, &IProfileCommon::LoadImage, "LoadImage"},
53 }; 57 };
58
54 RegisterHandlers(functions); 59 RegisterHandlers(functions);
60
61 if (editor_commands) {
62 static const FunctionInfo editor_functions[] = {
63 {100, &IProfileCommon::Store, "Store"},
64 {101, &IProfileCommon::StoreWithImage, "StoreWithImage"},
65 };
66
67 RegisterHandlers(editor_functions);
68 }
55 } 69 }
56 70
57private: 71protected:
58 void Get(Kernel::HLERequestContext& ctx) { 72 void Get(Kernel::HLERequestContext& ctx) {
59 LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); 73 LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
60 ProfileBase profile_base{}; 74 ProfileBase profile_base{};
@@ -127,10 +141,91 @@ private:
127 } 141 }
128 } 142 }
129 143
130 const ProfileManager& profile_manager; 144 void Store(Kernel::HLERequestContext& ctx) {
145 IPC::RequestParser rp{ctx};
146 const auto base = rp.PopRaw<ProfileBase>();
147
148 const auto user_data = ctx.ReadBuffer();
149
150 LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}",
151 Common::StringFromFixedZeroTerminatedBuffer(
152 reinterpret_cast<const char*>(base.username.data()), base.username.size()),
153 base.timestamp, base.user_uuid.Format());
154
155 if (user_data.size() < sizeof(ProfileData)) {
156 LOG_ERROR(Service_ACC, "ProfileData buffer too small!");
157 IPC::ResponseBuilder rb{ctx, 2};
158 rb.Push(ERR_INVALID_BUFFER_SIZE);
159 return;
160 }
161
162 ProfileData data;
163 std::memcpy(&data, user_data.data(), sizeof(ProfileData));
164
165 if (!profile_manager.SetProfileBaseAndData(user_id, base, data)) {
166 LOG_ERROR(Service_ACC, "Failed to update profile data and base!");
167 IPC::ResponseBuilder rb{ctx, 2};
168 rb.Push(ERR_FAILED_SAVE_DATA);
169 return;
170 }
171
172 IPC::ResponseBuilder rb{ctx, 2};
173 rb.Push(RESULT_SUCCESS);
174 }
175
176 void StoreWithImage(Kernel::HLERequestContext& ctx) {
177 IPC::RequestParser rp{ctx};
178 const auto base = rp.PopRaw<ProfileBase>();
179
180 const auto user_data = ctx.ReadBuffer();
181 const auto image_data = ctx.ReadBuffer(1);
182
183 LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}",
184 Common::StringFromFixedZeroTerminatedBuffer(
185 reinterpret_cast<const char*>(base.username.data()), base.username.size()),
186 base.timestamp, base.user_uuid.Format());
187
188 if (user_data.size() < sizeof(ProfileData)) {
189 LOG_ERROR(Service_ACC, "ProfileData buffer too small!");
190 IPC::ResponseBuilder rb{ctx, 2};
191 rb.Push(ERR_INVALID_BUFFER_SIZE);
192 return;
193 }
194
195 ProfileData data;
196 std::memcpy(&data, user_data.data(), sizeof(ProfileData));
197
198 FileUtil::IOFile image(GetImagePath(user_id), "wb");
199
200 if (!image.IsOpen() || !image.Resize(image_data.size()) ||
201 image.WriteBytes(image_data.data(), image_data.size()) != image_data.size() ||
202 !profile_manager.SetProfileBaseAndData(user_id, base, data)) {
203 LOG_ERROR(Service_ACC, "Failed to update profile data, base, and image!");
204 IPC::ResponseBuilder rb{ctx, 2};
205 rb.Push(ERR_FAILED_SAVE_DATA);
206 return;
207 }
208
209 IPC::ResponseBuilder rb{ctx, 2};
210 rb.Push(RESULT_SUCCESS);
211 }
212
213 ProfileManager& profile_manager;
131 Common::UUID user_id; ///< The user id this profile refers to. 214 Common::UUID user_id; ///< The user id this profile refers to.
132}; 215};
133 216
217class IProfile final : public IProfileCommon {
218public:
219 IProfile(Common::UUID user_id, ProfileManager& profile_manager)
220 : IProfileCommon("IProfile", false, user_id, profile_manager) {}
221};
222
223class IProfileEditor final : public IProfileCommon {
224public:
225 IProfileEditor(Common::UUID user_id, ProfileManager& profile_manager)
226 : IProfileCommon("IProfileEditor", true, user_id, profile_manager) {}
227};
228
134class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { 229class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
135public: 230public:
136 IManagerForApplication() : ServiceFramework("IManagerForApplication") { 231 IManagerForApplication() : ServiceFramework("IManagerForApplication") {
@@ -322,6 +417,17 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx
322 rb.Push(is_locked); 417 rb.Push(is_locked);
323} 418}
324 419
420void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) {
421 IPC::RequestParser rp{ctx};
422 Common::UUID user_id = rp.PopRaw<Common::UUID>();
423
424 LOG_DEBUG(Service_ACC, "called, user_id={}", user_id.Format());
425
426 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
427 rb.Push(RESULT_SUCCESS);
428 rb.PushIpcInterface<IProfileEditor>(user_id, *profile_manager);
429}
430
325void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { 431void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
326 LOG_DEBUG(Service_ACC, "called"); 432 LOG_DEBUG(Service_ACC, "called");
327 // A u8 is passed into this function which we can safely ignore. It's to determine if we have 433 // A u8 is passed into this function which we can safely ignore. It's to determine if we have
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h
index f651773b7..7a7dc9ec6 100644
--- a/src/core/hle/service/acc/acc.h
+++ b/src/core/hle/service/acc/acc.h
@@ -32,6 +32,7 @@ public:
32 void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx); 32 void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx);
33 void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx); 33 void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx);
34 void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx); 34 void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx);
35 void GetProfileEditor(Kernel::HLERequestContext& ctx);
35 36
36 private: 37 private:
37 ResultCode InitializeApplicationInfoBase(u64 process_id); 38 ResultCode InitializeApplicationInfoBase(u64 process_id);
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp
index 1b7ec3ed0..0d1663657 100644
--- a/src/core/hle/service/acc/acc_su.cpp
+++ b/src/core/hle/service/acc/acc_su.cpp
@@ -41,7 +41,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
41 {202, nullptr, "CancelUserRegistration"}, 41 {202, nullptr, "CancelUserRegistration"},
42 {203, nullptr, "DeleteUser"}, 42 {203, nullptr, "DeleteUser"},
43 {204, nullptr, "SetUserPosition"}, 43 {204, nullptr, "SetUserPosition"},
44 {205, nullptr, "GetProfileEditor"}, 44 {205, &ACC_SU::GetProfileEditor, "GetProfileEditor"},
45 {206, nullptr, "CompleteUserRegistrationForcibly"}, 45 {206, nullptr, "CompleteUserRegistrationForcibly"},
46 {210, nullptr, "CreateFloatingRegistrationRequest"}, 46 {210, nullptr, "CreateFloatingRegistrationRequest"},
47 {230, nullptr, "AuthenticateServiceAsync"}, 47 {230, nullptr, "AuthenticateServiceAsync"},
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 49aa5908b..8f9986326 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -305,6 +305,17 @@ bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) {
305 return true; 305 return true;
306} 306}
307 307
308bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& profile_new,
309 const ProfileData& data_new) {
310 const auto index = GetUserIndex(uuid);
311 if (index.has_value() && SetProfileBase(uuid, profile_new)) {
312 profiles[*index].data = data_new;
313 return true;
314 }
315
316 return false;
317}
318
308void ProfileManager::ParseUserSaveFile() { 319void ProfileManager::ParseUserSaveFile() {
309 FileUtil::IOFile save(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + 320 FileUtil::IOFile save(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
310 ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat", 321 ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat",
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index fd7abb541..5a6d28925 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -91,6 +91,8 @@ public:
91 91
92 bool RemoveUser(Common::UUID uuid); 92 bool RemoveUser(Common::UUID uuid);
93 bool SetProfileBase(Common::UUID uuid, const ProfileBase& profile_new); 93 bool SetProfileBase(Common::UUID uuid, const ProfileBase& profile_new);
94 bool SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& profile_new,
95 const ProfileData& data_new);
94 96
95private: 97private:
96 void ParseUserSaveFile(); 98 void ParseUserSaveFile();
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 111633ba3..aa2c83937 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -56,7 +56,8 @@ struct LaunchParameters {
56}; 56};
57static_assert(sizeof(LaunchParameters) == 0x88); 57static_assert(sizeof(LaunchParameters) == 0x88);
58 58
59IWindowController::IWindowController() : ServiceFramework("IWindowController") { 59IWindowController::IWindowController(Core::System& system_)
60 : ServiceFramework("IWindowController"), system{system_} {
60 // clang-format off 61 // clang-format off
61 static const FunctionInfo functions[] = { 62 static const FunctionInfo functions[] = {
62 {0, nullptr, "CreateWindow"}, 63 {0, nullptr, "CreateWindow"},
@@ -75,7 +76,7 @@ IWindowController::IWindowController() : ServiceFramework("IWindowController") {
75IWindowController::~IWindowController() = default; 76IWindowController::~IWindowController() = default;
76 77
77void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) { 78void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) {
78 const u64 process_id = Core::System::GetInstance().Kernel().CurrentProcess()->GetProcessID(); 79 const u64 process_id = system.CurrentProcess()->GetProcessID();
79 80
80 LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id); 81 LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id);
81 82
@@ -231,8 +232,9 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} {
231 232
232IDebugFunctions::~IDebugFunctions() = default; 233IDebugFunctions::~IDebugFunctions() = default;
233 234
234ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) 235ISelfController::ISelfController(Core::System& system_,
235 : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) { 236 std::shared_ptr<NVFlinger::NVFlinger> nvflinger_)
237 : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger_)) {
236 // clang-format off 238 // clang-format off
237 static const FunctionInfo functions[] = { 239 static const FunctionInfo functions[] = {
238 {0, nullptr, "Exit"}, 240 {0, nullptr, "Exit"},
@@ -280,7 +282,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
280 282
281 RegisterHandlers(functions); 283 RegisterHandlers(functions);
282 284
283 auto& kernel = Core::System::GetInstance().Kernel(); 285 auto& kernel = system_.Kernel();
284 launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, 286 launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
285 "ISelfController:LaunchableEvent"); 287 "ISelfController:LaunchableEvent");
286 288
@@ -501,8 +503,7 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest
501 rb.PushCopyObjects(accumulated_suspended_tick_changed_event.readable); 503 rb.PushCopyObjects(accumulated_suspended_tick_changed_event.readable);
502} 504}
503 505
504AppletMessageQueue::AppletMessageQueue() { 506AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) {
505 auto& kernel = Core::System::GetInstance().Kernel();
506 on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, 507 on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
507 "AMMessageQueue:OnMessageRecieved"); 508 "AMMessageQueue:OnMessageRecieved");
508 on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair( 509 on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair(
@@ -937,9 +938,8 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
937 rb.Push(RESULT_SUCCESS); 938 rb.Push(RESULT_SUCCESS);
938} 939}
939 940
940ILibraryAppletCreator::ILibraryAppletCreator(u64 current_process_title_id) 941ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_)
941 : ServiceFramework("ILibraryAppletCreator"), 942 : ServiceFramework("ILibraryAppletCreator"), system{system_} {
942 current_process_title_id(current_process_title_id) {
943 static const FunctionInfo functions[] = { 943 static const FunctionInfo functions[] = {
944 {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, 944 {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
945 {1, nullptr, "TerminateAllLibraryApplets"}, 945 {1, nullptr, "TerminateAllLibraryApplets"},
@@ -961,8 +961,8 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
961 LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", 961 LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}",
962 static_cast<u32>(applet_id), applet_mode); 962 static_cast<u32>(applet_id), applet_mode);
963 963
964 const auto& applet_manager{Core::System::GetInstance().GetAppletManager()}; 964 const auto& applet_manager{system.GetAppletManager()};
965 const auto applet = applet_manager.GetApplet(applet_id, current_process_title_id); 965 const auto applet = applet_manager.GetApplet(applet_id);
966 966
967 if (applet == nullptr) { 967 if (applet == nullptr) {
968 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id)); 968 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id));
@@ -999,8 +999,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
999 const auto handle{rp.Pop<Kernel::Handle>()}; 999 const auto handle{rp.Pop<Kernel::Handle>()};
1000 1000
1001 const auto transfer_mem = 1001 const auto transfer_mem =
1002 Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>( 1002 system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
1003 handle);
1004 1003
1005 if (transfer_mem == nullptr) { 1004 if (transfer_mem == nullptr) {
1006 LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle); 1005 LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle);
@@ -1018,7 +1017,8 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
1018 rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory))); 1017 rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory)));
1019} 1018}
1020 1019
1021IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { 1020IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1021 : ServiceFramework("IApplicationFunctions"), system{system_} {
1022 // clang-format off 1022 // clang-format off
1023 static const FunctionInfo functions[] = { 1023 static const FunctionInfo functions[] = {
1024 {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, 1024 {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
@@ -1180,7 +1180,7 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
1180 // Get supported languages from NACP, if possible 1180 // Get supported languages from NACP, if possible
1181 // Default to 0 (all languages supported) 1181 // Default to 0 (all languages supported)
1182 u32 supported_languages = 0; 1182 u32 supported_languages = 0;
1183 FileSys::PatchManager pm{Core::System::GetInstance().CurrentProcess()->GetTitleID()}; 1183 FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()};
1184 1184
1185 const auto res = pm.GetControlMetadata(); 1185 const auto res = pm.GetControlMetadata();
1186 if (res.first != nullptr) { 1186 if (res.first != nullptr) {
@@ -1188,8 +1188,8 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
1188 } 1188 }
1189 1189
1190 // Call IApplicationManagerInterface implementation. 1190 // Call IApplicationManagerInterface implementation.
1191 auto& service_manager = Core::System::GetInstance().ServiceManager(); 1191 auto& service_manager = system.ServiceManager();
1192 auto ns_am2 = service_manager.GetService<Service::NS::NS>("ns:am2"); 1192 auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
1193 auto app_man = ns_am2->GetApplicationManagerInterface(); 1193 auto app_man = ns_am2->GetApplicationManagerInterface();
1194 1194
1195 // Get desired application language 1195 // Get desired application language
@@ -1261,8 +1261,8 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
1261 "new_journal={:016X}", 1261 "new_journal={:016X}",
1262 static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); 1262 static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
1263 1263
1264 FileSystem::WriteSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id, 1264 const auto title_id = system.CurrentProcess()->GetTitleID();
1265 {new_normal_size, new_journal_size}); 1265 FileSystem::WriteSaveDataSize(type, title_id, user_id, {new_normal_size, new_journal_size});
1266 1266
1267 IPC::ResponseBuilder rb{ctx, 4}; 1267 IPC::ResponseBuilder rb{ctx, 4};
1268 rb.Push(RESULT_SUCCESS); 1268 rb.Push(RESULT_SUCCESS);
@@ -1281,8 +1281,8 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
1281 LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type), 1281 LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type),
1282 user_id[1], user_id[0]); 1282 user_id[1], user_id[0]);
1283 1283
1284 const auto size = 1284 const auto title_id = system.CurrentProcess()->GetTitleID();
1285 FileSystem::ReadSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id); 1285 const auto size = FileSystem::ReadSaveDataSize(type, title_id, user_id);
1286 1286
1287 IPC::ResponseBuilder rb{ctx, 6}; 1287 IPC::ResponseBuilder rb{ctx, 6};
1288 rb.Push(RESULT_SUCCESS); 1288 rb.Push(RESULT_SUCCESS);
@@ -1300,9 +1300,9 @@ void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestCon
1300 1300
1301void InstallInterfaces(SM::ServiceManager& service_manager, 1301void InstallInterfaces(SM::ServiceManager& service_manager,
1302 std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) { 1302 std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) {
1303 auto message_queue = std::make_shared<AppletMessageQueue>(); 1303 auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel());
1304 message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on 1304 // Needed on game boot
1305 // game boot 1305 message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
1306 1306
1307 std::make_shared<AppletAE>(nvflinger, message_queue, system)->InstallAsService(service_manager); 1307 std::make_shared<AppletAE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
1308 std::make_shared<AppletOE>(nvflinger, message_queue, system)->InstallAsService(service_manager); 1308 std::make_shared<AppletOE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index cbc9da7b6..28f870302 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -10,12 +10,15 @@
10#include "core/hle/kernel/writable_event.h" 10#include "core/hle/kernel/writable_event.h"
11#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
12 12
13namespace Service { 13namespace Kernel {
14namespace NVFlinger { 14class KernelCore;
15}
16
17namespace Service::NVFlinger {
15class NVFlinger; 18class NVFlinger;
16} 19}
17 20
18namespace AM { 21namespace Service::AM {
19 22
20enum SystemLanguage { 23enum SystemLanguage {
21 Japanese = 0, 24 Japanese = 0,
@@ -47,7 +50,7 @@ public:
47 PerformanceModeChanged = 31, 50 PerformanceModeChanged = 31,
48 }; 51 };
49 52
50 AppletMessageQueue(); 53 explicit AppletMessageQueue(Kernel::KernelCore& kernel);
51 ~AppletMessageQueue(); 54 ~AppletMessageQueue();
52 55
53 const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const; 56 const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const;
@@ -65,12 +68,14 @@ private:
65 68
66class IWindowController final : public ServiceFramework<IWindowController> { 69class IWindowController final : public ServiceFramework<IWindowController> {
67public: 70public:
68 IWindowController(); 71 explicit IWindowController(Core::System& system_);
69 ~IWindowController() override; 72 ~IWindowController() override;
70 73
71private: 74private:
72 void GetAppletResourceUserId(Kernel::HLERequestContext& ctx); 75 void GetAppletResourceUserId(Kernel::HLERequestContext& ctx);
73 void AcquireForegroundRights(Kernel::HLERequestContext& ctx); 76 void AcquireForegroundRights(Kernel::HLERequestContext& ctx);
77
78 Core::System& system;
74}; 79};
75 80
76class IAudioController final : public ServiceFramework<IAudioController> { 81class IAudioController final : public ServiceFramework<IAudioController> {
@@ -113,7 +118,8 @@ public:
113 118
114class ISelfController final : public ServiceFramework<ISelfController> { 119class ISelfController final : public ServiceFramework<ISelfController> {
115public: 120public:
116 explicit ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger); 121 explicit ISelfController(Core::System& system_,
122 std::shared_ptr<NVFlinger::NVFlinger> nvflinger_);
117 ~ISelfController() override; 123 ~ISelfController() override;
118 124
119private: 125private:
@@ -208,7 +214,7 @@ private:
208 214
209class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { 215class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
210public: 216public:
211 ILibraryAppletCreator(u64 current_process_title_id); 217 explicit ILibraryAppletCreator(Core::System& system_);
212 ~ILibraryAppletCreator() override; 218 ~ILibraryAppletCreator() override;
213 219
214private: 220private:
@@ -216,12 +222,12 @@ private:
216 void CreateStorage(Kernel::HLERequestContext& ctx); 222 void CreateStorage(Kernel::HLERequestContext& ctx);
217 void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); 223 void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx);
218 224
219 u64 current_process_title_id; 225 Core::System& system;
220}; 226};
221 227
222class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { 228class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
223public: 229public:
224 IApplicationFunctions(); 230 explicit IApplicationFunctions(Core::System& system_);
225 ~IApplicationFunctions() override; 231 ~IApplicationFunctions() override;
226 232
227private: 233private:
@@ -245,6 +251,7 @@ private:
245 void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); 251 void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
246 252
247 Kernel::EventPair gpu_error_detected_event; 253 Kernel::EventPair gpu_error_detected_event;
254 Core::System& system;
248}; 255};
249 256
250class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { 257class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
@@ -278,5 +285,4 @@ public:
278void InstallInterfaces(SM::ServiceManager& service_manager, 285void InstallInterfaces(SM::ServiceManager& service_manager,
279 std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system); 286 std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system);
280 287
281} // namespace AM 288} // namespace Service::AM
282} // namespace Service
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index a34368c8b..e454b77d8 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -50,7 +50,7 @@ private:
50 50
51 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 51 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
52 rb.Push(RESULT_SUCCESS); 52 rb.Push(RESULT_SUCCESS);
53 rb.PushIpcInterface<ISelfController>(nvflinger); 53 rb.PushIpcInterface<ISelfController>(system, nvflinger);
54 } 54 }
55 55
56 void GetWindowController(Kernel::HLERequestContext& ctx) { 56 void GetWindowController(Kernel::HLERequestContext& ctx) {
@@ -58,7 +58,7 @@ private:
58 58
59 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 59 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
60 rb.Push(RESULT_SUCCESS); 60 rb.Push(RESULT_SUCCESS);
61 rb.PushIpcInterface<IWindowController>(); 61 rb.PushIpcInterface<IWindowController>(system);
62 } 62 }
63 63
64 void GetAudioController(Kernel::HLERequestContext& ctx) { 64 void GetAudioController(Kernel::HLERequestContext& ctx) {
@@ -98,7 +98,7 @@ private:
98 98
99 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 99 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
100 rb.Push(RESULT_SUCCESS); 100 rb.Push(RESULT_SUCCESS);
101 rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID()); 101 rb.PushIpcInterface<ILibraryAppletCreator>(system);
102 } 102 }
103 103
104 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { 104 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
@@ -106,7 +106,7 @@ private:
106 106
107 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 107 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
108 rb.Push(RESULT_SUCCESS); 108 rb.Push(RESULT_SUCCESS);
109 rb.PushIpcInterface<IApplicationFunctions>(); 109 rb.PushIpcInterface<IApplicationFunctions>(system);
110 } 110 }
111 111
112 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 112 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
@@ -154,7 +154,7 @@ private:
154 154
155 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 155 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
156 rb.Push(RESULT_SUCCESS); 156 rb.Push(RESULT_SUCCESS);
157 rb.PushIpcInterface<ISelfController>(nvflinger); 157 rb.PushIpcInterface<ISelfController>(system, nvflinger);
158 } 158 }
159 159
160 void GetWindowController(Kernel::HLERequestContext& ctx) { 160 void GetWindowController(Kernel::HLERequestContext& ctx) {
@@ -162,7 +162,7 @@ private:
162 162
163 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 163 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
164 rb.Push(RESULT_SUCCESS); 164 rb.Push(RESULT_SUCCESS);
165 rb.PushIpcInterface<IWindowController>(); 165 rb.PushIpcInterface<IWindowController>(system);
166 } 166 }
167 167
168 void GetAudioController(Kernel::HLERequestContext& ctx) { 168 void GetAudioController(Kernel::HLERequestContext& ctx) {
@@ -194,7 +194,7 @@ private:
194 194
195 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 195 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
196 rb.Push(RESULT_SUCCESS); 196 rb.Push(RESULT_SUCCESS);
197 rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID()); 197 rb.PushIpcInterface<ILibraryAppletCreator>(system);
198 } 198 }
199 199
200 void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) { 200 void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index 5d53ef113..a2ffaa440 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -4,7 +4,6 @@
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/process.h"
8#include "core/hle/service/am/am.h" 7#include "core/hle/service/am/am.h"
9#include "core/hle/service/am/applet_oe.h" 8#include "core/hle/service/am/applet_oe.h"
10#include "core/hle/service/nvflinger/nvflinger.h" 9#include "core/hle/service/nvflinger/nvflinger.h"
@@ -64,7 +63,7 @@ private:
64 63
65 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 64 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
66 rb.Push(RESULT_SUCCESS); 65 rb.Push(RESULT_SUCCESS);
67 rb.PushIpcInterface<IWindowController>(); 66 rb.PushIpcInterface<IWindowController>(system);
68 } 67 }
69 68
70 void GetSelfController(Kernel::HLERequestContext& ctx) { 69 void GetSelfController(Kernel::HLERequestContext& ctx) {
@@ -72,7 +71,7 @@ private:
72 71
73 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 72 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
74 rb.Push(RESULT_SUCCESS); 73 rb.Push(RESULT_SUCCESS);
75 rb.PushIpcInterface<ISelfController>(nvflinger); 74 rb.PushIpcInterface<ISelfController>(system, nvflinger);
76 } 75 }
77 76
78 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { 77 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
@@ -88,7 +87,7 @@ private:
88 87
89 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 88 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
90 rb.Push(RESULT_SUCCESS); 89 rb.Push(RESULT_SUCCESS);
91 rb.PushIpcInterface<ILibraryAppletCreator>(system.CurrentProcess()->GetTitleID()); 90 rb.PushIpcInterface<ILibraryAppletCreator>(system);
92 } 91 }
93 92
94 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { 93 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
@@ -96,7 +95,7 @@ private:
96 95
97 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 96 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
98 rb.Push(RESULT_SUCCESS); 97 rb.Push(RESULT_SUCCESS);
99 rb.PushIpcInterface<IApplicationFunctions>(); 98 rb.PushIpcInterface<IApplicationFunctions>(system);
100 } 99 }
101 100
102 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 101 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index 6bdba2468..d2e35362f 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -23,8 +23,7 @@
23 23
24namespace Service::AM::Applets { 24namespace Service::AM::Applets {
25 25
26AppletDataBroker::AppletDataBroker() { 26AppletDataBroker::AppletDataBroker(Kernel::KernelCore& kernel) {
27 auto& kernel = Core::System::GetInstance().Kernel();
28 state_changed_event = Kernel::WritableEvent::CreateEventPair( 27 state_changed_event = Kernel::WritableEvent::CreateEventPair(
29 kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:StateChangedEvent"); 28 kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:StateChangedEvent");
30 pop_out_data_event = Kernel::WritableEvent::CreateEventPair( 29 pop_out_data_event = Kernel::WritableEvent::CreateEventPair(
@@ -121,7 +120,7 @@ Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent(
121 return state_changed_event.readable; 120 return state_changed_event.readable;
122} 121}
123 122
124Applet::Applet() = default; 123Applet::Applet(Kernel::KernelCore& kernel_) : broker{kernel_} {}
125 124
126Applet::~Applet() = default; 125Applet::~Applet() = default;
127 126
@@ -154,7 +153,7 @@ AppletFrontendSet::AppletFrontendSet(AppletFrontendSet&&) noexcept = default;
154 153
155AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default; 154AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default;
156 155
157AppletManager::AppletManager() = default; 156AppletManager::AppletManager(Core::System& system_) : system{system_} {}
158 157
159AppletManager::~AppletManager() = default; 158AppletManager::~AppletManager() = default;
160 159
@@ -216,28 +215,28 @@ void AppletManager::ClearAll() {
216 frontend = {}; 215 frontend = {};
217} 216}
218 217
219std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, u64 current_process_title_id) const { 218std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
220 switch (id) { 219 switch (id) {
221 case AppletId::Auth: 220 case AppletId::Auth:
222 return std::make_shared<Auth>(*frontend.parental_controls); 221 return std::make_shared<Auth>(system, *frontend.parental_controls);
223 case AppletId::Error: 222 case AppletId::Error:
224 return std::make_shared<Error>(*frontend.error); 223 return std::make_shared<Error>(system, *frontend.error);
225 case AppletId::ProfileSelect: 224 case AppletId::ProfileSelect:
226 return std::make_shared<ProfileSelect>(*frontend.profile_select); 225 return std::make_shared<ProfileSelect>(system, *frontend.profile_select);
227 case AppletId::SoftwareKeyboard: 226 case AppletId::SoftwareKeyboard:
228 return std::make_shared<SoftwareKeyboard>(*frontend.software_keyboard); 227 return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard);
229 case AppletId::PhotoViewer: 228 case AppletId::PhotoViewer:
230 return std::make_shared<PhotoViewer>(*frontend.photo_viewer); 229 return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer);
231 case AppletId::LibAppletShop: 230 case AppletId::LibAppletShop:
232 return std::make_shared<WebBrowser>(*frontend.web_browser, current_process_title_id, 231 return std::make_shared<WebBrowser>(system, *frontend.web_browser,
233 frontend.e_commerce.get()); 232 frontend.e_commerce.get());
234 case AppletId::LibAppletOff: 233 case AppletId::LibAppletOff:
235 return std::make_shared<WebBrowser>(*frontend.web_browser, current_process_title_id); 234 return std::make_shared<WebBrowser>(system, *frontend.web_browser);
236 default: 235 default:
237 UNIMPLEMENTED_MSG( 236 UNIMPLEMENTED_MSG(
238 "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", 237 "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
239 static_cast<u8>(id)); 238 static_cast<u8>(id));
240 return std::make_shared<StubApplet>(id); 239 return std::make_shared<StubApplet>(system, id);
241 } 240 }
242} 241}
243 242
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index adc973dad..764c3418c 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -12,6 +12,10 @@
12 12
13union ResultCode; 13union ResultCode;
14 14
15namespace Core {
16class System;
17}
18
15namespace Core::Frontend { 19namespace Core::Frontend {
16class ECommerceApplet; 20class ECommerceApplet;
17class ErrorApplet; 21class ErrorApplet;
@@ -22,6 +26,10 @@ class SoftwareKeyboardApplet;
22class WebBrowserApplet; 26class WebBrowserApplet;
23} // namespace Core::Frontend 27} // namespace Core::Frontend
24 28
29namespace Kernel {
30class KernelCore;
31}
32
25namespace Service::AM { 33namespace Service::AM {
26 34
27class IStorage; 35class IStorage;
@@ -53,7 +61,7 @@ enum class AppletId : u32 {
53 61
54class AppletDataBroker final { 62class AppletDataBroker final {
55public: 63public:
56 AppletDataBroker(); 64 explicit AppletDataBroker(Kernel::KernelCore& kernel_);
57 ~AppletDataBroker(); 65 ~AppletDataBroker();
58 66
59 struct RawChannelData { 67 struct RawChannelData {
@@ -108,7 +116,7 @@ private:
108 116
109class Applet { 117class Applet {
110public: 118public:
111 Applet(); 119 explicit Applet(Kernel::KernelCore& kernel_);
112 virtual ~Applet(); 120 virtual ~Applet();
113 121
114 virtual void Initialize(); 122 virtual void Initialize();
@@ -179,7 +187,7 @@ struct AppletFrontendSet {
179 187
180class AppletManager { 188class AppletManager {
181public: 189public:
182 AppletManager(); 190 explicit AppletManager(Core::System& system_);
183 ~AppletManager(); 191 ~AppletManager();
184 192
185 void SetAppletFrontendSet(AppletFrontendSet set); 193 void SetAppletFrontendSet(AppletFrontendSet set);
@@ -187,10 +195,11 @@ public:
187 void SetDefaultAppletsIfMissing(); 195 void SetDefaultAppletsIfMissing();
188 void ClearAll(); 196 void ClearAll();
189 197
190 std::shared_ptr<Applet> GetApplet(AppletId id, u64 current_process_title_id) const; 198 std::shared_ptr<Applet> GetApplet(AppletId id) const;
191 199
192private: 200private:
193 AppletFrontendSet frontend; 201 AppletFrontendSet frontend;
202 Core::System& system;
194}; 203};
195 204
196} // namespace Applets 205} // namespace Applets
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp
index af3a900f8..a7db26725 100644
--- a/src/core/hle/service/am/applets/error.cpp
+++ b/src/core/hle/service/am/applets/error.cpp
@@ -85,7 +85,8 @@ ResultCode Decode64BitError(u64 error) {
85 85
86} // Anonymous namespace 86} // Anonymous namespace
87 87
88Error::Error(const Core::Frontend::ErrorApplet& frontend) : frontend(frontend) {} 88Error::Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_)
89 : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {}
89 90
90Error::~Error() = default; 91Error::~Error() = default;
91 92
@@ -145,8 +146,8 @@ void Error::Execute() {
145 } 146 }
146 147
147 const auto callback = [this] { DisplayCompleted(); }; 148 const auto callback = [this] { DisplayCompleted(); };
148 const auto title_id = Core::CurrentProcess()->GetTitleID(); 149 const auto title_id = system.CurrentProcess()->GetTitleID();
149 const auto& reporter{Core::System::GetInstance().GetReporter()}; 150 const auto& reporter{system.GetReporter()};
150 151
151 switch (mode) { 152 switch (mode) {
152 case ErrorAppletMode::ShowError: 153 case ErrorAppletMode::ShowError:
diff --git a/src/core/hle/service/am/applets/error.h b/src/core/hle/service/am/applets/error.h
index a3590d181..a105cdb0c 100644
--- a/src/core/hle/service/am/applets/error.h
+++ b/src/core/hle/service/am/applets/error.h
@@ -7,6 +7,10 @@
7#include "core/hle/result.h" 7#include "core/hle/result.h"
8#include "core/hle/service/am/applets/applets.h" 8#include "core/hle/service/am/applets/applets.h"
9 9
10namespace Core {
11class System;
12}
13
10namespace Service::AM::Applets { 14namespace Service::AM::Applets {
11 15
12enum class ErrorAppletMode : u8 { 16enum class ErrorAppletMode : u8 {
@@ -21,7 +25,7 @@ enum class ErrorAppletMode : u8 {
21 25
22class Error final : public Applet { 26class Error final : public Applet {
23public: 27public:
24 explicit Error(const Core::Frontend::ErrorApplet& frontend); 28 explicit Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_);
25 ~Error() override; 29 ~Error() override;
26 30
27 void Initialize() override; 31 void Initialize() override;
@@ -42,6 +46,7 @@ private:
42 std::unique_ptr<ErrorArguments> args; 46 std::unique_ptr<ErrorArguments> args;
43 47
44 bool complete = false; 48 bool complete = false;
49 Core::System& system;
45}; 50};
46 51
47} // namespace Service::AM::Applets 52} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp
index e0def8dff..328438a1d 100644
--- a/src/core/hle/service/am/applets/general_backend.cpp
+++ b/src/core/hle/service/am/applets/general_backend.cpp
@@ -37,7 +37,8 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix)
37 } 37 }
38} 38}
39 39
40Auth::Auth(Core::Frontend::ParentalControlsApplet& frontend) : frontend(frontend) {} 40Auth::Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_)
41 : Applet{system_.Kernel()}, frontend(frontend_) {}
41 42
42Auth::~Auth() = default; 43Auth::~Auth() = default;
43 44
@@ -151,7 +152,8 @@ void Auth::AuthFinished(bool successful) {
151 broker.SignalStateChanged(); 152 broker.SignalStateChanged();
152} 153}
153 154
154PhotoViewer::PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend) : frontend(frontend) {} 155PhotoViewer::PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_)
156 : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {}
155 157
156PhotoViewer::~PhotoViewer() = default; 158PhotoViewer::~PhotoViewer() = default;
157 159
@@ -185,7 +187,7 @@ void PhotoViewer::Execute() {
185 const auto callback = [this] { ViewFinished(); }; 187 const auto callback = [this] { ViewFinished(); };
186 switch (mode) { 188 switch (mode) {
187 case PhotoViewerAppletMode::CurrentApp: 189 case PhotoViewerAppletMode::CurrentApp:
188 frontend.ShowPhotosForApplication(Core::CurrentProcess()->GetTitleID(), callback); 190 frontend.ShowPhotosForApplication(system.CurrentProcess()->GetTitleID(), callback);
189 break; 191 break;
190 case PhotoViewerAppletMode::AllApps: 192 case PhotoViewerAppletMode::AllApps:
191 frontend.ShowAllPhotos(callback); 193 frontend.ShowAllPhotos(callback);
@@ -200,7 +202,8 @@ void PhotoViewer::ViewFinished() {
200 broker.SignalStateChanged(); 202 broker.SignalStateChanged();
201} 203}
202 204
203StubApplet::StubApplet(AppletId id) : id(id) {} 205StubApplet::StubApplet(Core::System& system_, AppletId id_)
206 : Applet{system_.Kernel()}, id(id_), system{system_} {}
204 207
205StubApplet::~StubApplet() = default; 208StubApplet::~StubApplet() = default;
206 209
@@ -209,7 +212,7 @@ void StubApplet::Initialize() {
209 Applet::Initialize(); 212 Applet::Initialize();
210 213
211 const auto data = broker.PeekDataToAppletForDebug(); 214 const auto data = broker.PeekDataToAppletForDebug();
212 Core::System::GetInstance().GetReporter().SaveUnimplementedAppletReport( 215 system.GetReporter().SaveUnimplementedAppletReport(
213 static_cast<u32>(id), common_args.arguments_version, common_args.library_version, 216 static_cast<u32>(id), common_args.arguments_version, common_args.library_version,
214 common_args.theme_color, common_args.play_startup_sound, common_args.system_tick, 217 common_args.theme_color, common_args.play_startup_sound, common_args.system_tick,
215 data.normal, data.interactive); 218 data.normal, data.interactive);
diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/general_backend.h
index 0da252044..cfa2df369 100644
--- a/src/core/hle/service/am/applets/general_backend.h
+++ b/src/core/hle/service/am/applets/general_backend.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/am/applets/applets.h" 7#include "core/hle/service/am/applets/applets.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::AM::Applets { 13namespace Service::AM::Applets {
10 14
11enum class AuthAppletType : u32 { 15enum class AuthAppletType : u32 {
@@ -16,7 +20,7 @@ enum class AuthAppletType : u32 {
16 20
17class Auth final : public Applet { 21class Auth final : public Applet {
18public: 22public:
19 explicit Auth(Core::Frontend::ParentalControlsApplet& frontend); 23 explicit Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_);
20 ~Auth() override; 24 ~Auth() override;
21 25
22 void Initialize() override; 26 void Initialize() override;
@@ -45,7 +49,7 @@ enum class PhotoViewerAppletMode : u8 {
45 49
46class PhotoViewer final : public Applet { 50class PhotoViewer final : public Applet {
47public: 51public:
48 explicit PhotoViewer(const Core::Frontend::PhotoViewerApplet& frontend); 52 explicit PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_);
49 ~PhotoViewer() override; 53 ~PhotoViewer() override;
50 54
51 void Initialize() override; 55 void Initialize() override;
@@ -60,11 +64,12 @@ private:
60 const Core::Frontend::PhotoViewerApplet& frontend; 64 const Core::Frontend::PhotoViewerApplet& frontend;
61 bool complete = false; 65 bool complete = false;
62 PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp; 66 PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp;
67 Core::System& system;
63}; 68};
64 69
65class StubApplet final : public Applet { 70class StubApplet final : public Applet {
66public: 71public:
67 explicit StubApplet(AppletId id); 72 explicit StubApplet(Core::System& system_, AppletId id_);
68 ~StubApplet() override; 73 ~StubApplet() override;
69 74
70 void Initialize() override; 75 void Initialize() override;
@@ -76,6 +81,7 @@ public:
76 81
77private: 82private:
78 AppletId id; 83 AppletId id;
84 Core::System& system;
79}; 85};
80 86
81} // namespace Service::AM::Applets 87} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp
index 57b5419e8..3eba696ca 100644
--- a/src/core/hle/service/am/applets/profile_select.cpp
+++ b/src/core/hle/service/am/applets/profile_select.cpp
@@ -15,8 +15,9 @@ namespace Service::AM::Applets {
15 15
16constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1}; 16constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1};
17 17
18ProfileSelect::ProfileSelect(const Core::Frontend::ProfileSelectApplet& frontend) 18ProfileSelect::ProfileSelect(Core::System& system_,
19 : frontend(frontend) {} 19 const Core::Frontend::ProfileSelectApplet& frontend_)
20 : Applet{system_.Kernel()}, frontend(frontend_) {}
20 21
21ProfileSelect::~ProfileSelect() = default; 22ProfileSelect::~ProfileSelect() = default;
22 23
diff --git a/src/core/hle/service/am/applets/profile_select.h b/src/core/hle/service/am/applets/profile_select.h
index 563cd744a..16364ead7 100644
--- a/src/core/hle/service/am/applets/profile_select.h
+++ b/src/core/hle/service/am/applets/profile_select.h
@@ -11,6 +11,10 @@
11#include "core/hle/result.h" 11#include "core/hle/result.h"
12#include "core/hle/service/am/applets/applets.h" 12#include "core/hle/service/am/applets/applets.h"
13 13
14namespace Core {
15class System;
16}
17
14namespace Service::AM::Applets { 18namespace Service::AM::Applets {
15 19
16struct UserSelectionConfig { 20struct UserSelectionConfig {
@@ -29,7 +33,8 @@ static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has inco
29 33
30class ProfileSelect final : public Applet { 34class ProfileSelect final : public Applet {
31public: 35public:
32 explicit ProfileSelect(const Core::Frontend::ProfileSelectApplet& frontend); 36 explicit ProfileSelect(Core::System& system_,
37 const Core::Frontend::ProfileSelectApplet& frontend_);
33 ~ProfileSelect() override; 38 ~ProfileSelect() override;
34 39
35 void Initialize() override; 40 void Initialize() override;
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index e197990f7..748559cd0 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -39,8 +39,9 @@ static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
39 return params; 39 return params;
40} 40}
41 41
42SoftwareKeyboard::SoftwareKeyboard(const Core::Frontend::SoftwareKeyboardApplet& frontend) 42SoftwareKeyboard::SoftwareKeyboard(Core::System& system_,
43 : frontend(frontend) {} 43 const Core::Frontend::SoftwareKeyboardApplet& frontend_)
44 : Applet{system_.Kernel()}, frontend(frontend_) {}
44 45
45SoftwareKeyboard::~SoftwareKeyboard() = default; 46SoftwareKeyboard::~SoftwareKeyboard() = default;
46 47
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h
index 0fbc43e51..ef4801fc6 100644
--- a/src/core/hle/service/am/applets/software_keyboard.h
+++ b/src/core/hle/service/am/applets/software_keyboard.h
@@ -16,6 +16,10 @@
16 16
17union ResultCode; 17union ResultCode;
18 18
19namespace Core {
20class System;
21}
22
19namespace Service::AM::Applets { 23namespace Service::AM::Applets {
20 24
21enum class KeysetDisable : u32 { 25enum class KeysetDisable : u32 {
@@ -55,7 +59,8 @@ static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect siz
55 59
56class SoftwareKeyboard final : public Applet { 60class SoftwareKeyboard final : public Applet {
57public: 61public:
58 explicit SoftwareKeyboard(const Core::Frontend::SoftwareKeyboardApplet& frontend); 62 explicit SoftwareKeyboard(Core::System& system_,
63 const Core::Frontend::SoftwareKeyboardApplet& frontend_);
59 ~SoftwareKeyboard() override; 64 ~SoftwareKeyboard() override;
60 65
61 void Initialize() override; 66 void Initialize() override;
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index f3c9fef0e..32283e819 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -190,8 +190,9 @@ std::map<WebArgTLVType, std::vector<u8>> GetWebArguments(const std::vector<u8>&
190 return out; 190 return out;
191} 191}
192 192
193FileSys::VirtualFile GetApplicationRomFS(u64 title_id, FileSys::ContentRecordType type) { 193FileSys::VirtualFile GetApplicationRomFS(const Core::System& system, u64 title_id,
194 const auto& installed{Core::System::GetInstance().GetContentProvider()}; 194 FileSys::ContentRecordType type) {
195 const auto& installed{system.GetContentProvider()};
195 const auto res = installed.GetEntry(title_id, type); 196 const auto res = installed.GetEntry(title_id, type);
196 197
197 if (res != nullptr) { 198 if (res != nullptr) {
@@ -207,10 +208,10 @@ FileSys::VirtualFile GetApplicationRomFS(u64 title_id, FileSys::ContentRecordTyp
207 208
208} // Anonymous namespace 209} // Anonymous namespace
209 210
210WebBrowser::WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id, 211WebBrowser::WebBrowser(Core::System& system_, Core::Frontend::WebBrowserApplet& frontend_,
211 Core::Frontend::ECommerceApplet* frontend_e_commerce) 212 Core::Frontend::ECommerceApplet* frontend_e_commerce_)
212 : frontend(frontend), frontend_e_commerce(frontend_e_commerce), 213 : Applet{system_.Kernel()}, frontend(frontend_),
213 current_process_title_id(current_process_title_id) {} 214 frontend_e_commerce(frontend_e_commerce_), system{system_} {}
214 215
215WebBrowser::~WebBrowser() = default; 216WebBrowser::~WebBrowser() = default;
216 217
@@ -266,7 +267,7 @@ void WebBrowser::UnpackRomFS() {
266 ASSERT(offline_romfs != nullptr); 267 ASSERT(offline_romfs != nullptr);
267 const auto dir = 268 const auto dir =
268 FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard); 269 FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard);
269 const auto& vfs{Core::System::GetInstance().GetFilesystem()}; 270 const auto& vfs{system.GetFilesystem()};
270 const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite); 271 const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite);
271 FileSys::VfsRawCopyD(dir, temp_dir); 272 FileSys::VfsRawCopyD(dir, temp_dir);
272 273
@@ -470,10 +471,10 @@ void WebBrowser::InitializeOffline() {
470 } 471 }
471 472
472 if (title_id == 0) { 473 if (title_id == 0) {
473 title_id = current_process_title_id; 474 title_id = system.CurrentProcess()->GetTitleID();
474 } 475 }
475 476
476 offline_romfs = GetApplicationRomFS(title_id, type); 477 offline_romfs = GetApplicationRomFS(system, title_id, type);
477 if (offline_romfs == nullptr) { 478 if (offline_romfs == nullptr) {
478 status = ResultCode(-1); 479 status = ResultCode(-1);
479 LOG_ERROR(Service_AM, "Failed to find offline data for request!"); 480 LOG_ERROR(Service_AM, "Failed to find offline data for request!");
diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h
index 870f57b64..8d4027411 100644
--- a/src/core/hle/service/am/applets/web_browser.h
+++ b/src/core/hle/service/am/applets/web_browser.h
@@ -9,6 +9,10 @@
9#include "core/hle/service/am/am.h" 9#include "core/hle/service/am/am.h"
10#include "core/hle/service/am/applets/applets.h" 10#include "core/hle/service/am/applets/applets.h"
11 11
12namespace Core {
13class System;
14}
15
12namespace Service::AM::Applets { 16namespace Service::AM::Applets {
13 17
14enum class ShimKind : u32; 18enum class ShimKind : u32;
@@ -17,8 +21,8 @@ enum class WebArgTLVType : u16;
17 21
18class WebBrowser final : public Applet { 22class WebBrowser final : public Applet {
19public: 23public:
20 WebBrowser(Core::Frontend::WebBrowserApplet& frontend, u64 current_process_title_id, 24 WebBrowser(Core::System& system_, Core::Frontend::WebBrowserApplet& frontend_,
21 Core::Frontend::ECommerceApplet* frontend_e_commerce = nullptr); 25 Core::Frontend::ECommerceApplet* frontend_e_commerce_ = nullptr);
22 26
23 ~WebBrowser() override; 27 ~WebBrowser() override;
24 28
@@ -59,8 +63,6 @@ private:
59 bool unpacked = false; 63 bool unpacked = false;
60 ResultCode status = RESULT_SUCCESS; 64 ResultCode status = RESULT_SUCCESS;
61 65
62 u64 current_process_title_id;
63
64 ShimKind kind; 66 ShimKind kind;
65 std::map<WebArgTLVType, std::vector<u8>> args; 67 std::map<WebArgTLVType, std::vector<u8>> args;
66 68
@@ -74,6 +76,8 @@ private:
74 std::optional<u128> user_id; 76 std::optional<u128> user_id;
75 std::optional<bool> shop_full_display; 77 std::optional<bool> shop_full_display;
76 std::string shop_extra_parameter; 78 std::string shop_extra_parameter;
79
80 Core::System& system;
77}; 81};
78 82
79} // namespace Service::AM::Applets 83} // namespace Service::AM::Applets
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index e92e2e06e..3a5361fdd 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -258,6 +258,15 @@ ResultStatus AppLoader_NRO::ReadTitle(std::string& title) {
258 return ResultStatus::Success; 258 return ResultStatus::Success;
259} 259}
260 260
261ResultStatus AppLoader_NRO::ReadControlData(FileSys::NACP& control) {
262 if (nacp == nullptr) {
263 return ResultStatus::ErrorNoControl;
264 }
265
266 control = *nacp;
267 return ResultStatus::Success;
268}
269
261bool AppLoader_NRO::IsRomFSUpdatable() const { 270bool AppLoader_NRO::IsRomFSUpdatable() const {
262 return false; 271 return false;
263} 272}
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index 1ffdae805..71811bc29 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -43,6 +43,7 @@ public:
43 ResultStatus ReadProgramId(u64& out_program_id) override; 43 ResultStatus ReadProgramId(u64& out_program_id) override;
44 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 44 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
45 ResultStatus ReadTitle(std::string& title) override; 45 ResultStatus ReadTitle(std::string& title) override;
46 ResultStatus ReadControlData(FileSys::NACP& control) override;
46 bool IsRomFSUpdatable() const override; 47 bool IsRomFSUpdatable() const override;
47 48
48private: 49private:
diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp
index 08586d33c..63d449135 100644
--- a/src/video_core/engines/kepler_compute.cpp
+++ b/src/video_core/engines/kepler_compute.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <bitset>
5#include "common/assert.h" 6#include "common/assert.h"
6#include "common/logging/log.h" 7#include "common/logging/log.h"
7#include "core/core.h" 8#include "core/core.h"
@@ -49,6 +50,33 @@ void KeplerCompute::CallMethod(const GPU::MethodCall& method_call) {
49 } 50 }
50} 51}
51 52
53Tegra::Texture::FullTextureInfo KeplerCompute::GetTexture(std::size_t offset) const {
54 const std::bitset<8> cbuf_mask = launch_description.const_buffer_enable_mask.Value();
55 ASSERT(cbuf_mask[regs.tex_cb_index]);
56
57 const auto& texinfo = launch_description.const_buffer_config[regs.tex_cb_index];
58 ASSERT(texinfo.Address() != 0);
59
60 const GPUVAddr address = texinfo.Address() + offset * sizeof(Texture::TextureHandle);
61 ASSERT(address < texinfo.Address() + texinfo.size);
62
63 const Texture::TextureHandle tex_handle{memory_manager.Read<u32>(address)};
64 return GetTextureInfo(tex_handle, offset);
65}
66
67Texture::FullTextureInfo KeplerCompute::GetTextureInfo(const Texture::TextureHandle tex_handle,
68 std::size_t offset) const {
69 return Texture::FullTextureInfo{static_cast<u32>(offset), GetTICEntry(tex_handle.tic_id),
70 GetTSCEntry(tex_handle.tsc_id)};
71}
72
73u32 KeplerCompute::AccessConstBuffer32(u64 const_buffer, u64 offset) const {
74 const auto& buffer = launch_description.const_buffer_config[const_buffer];
75 u32 result;
76 std::memcpy(&result, memory_manager.GetPointer(buffer.Address() + offset), sizeof(u32));
77 return result;
78}
79
52void KeplerCompute::ProcessLaunch() { 80void KeplerCompute::ProcessLaunch() {
53 const GPUVAddr launch_desc_loc = regs.launch_desc_loc.Address(); 81 const GPUVAddr launch_desc_loc = regs.launch_desc_loc.Address();
54 memory_manager.ReadBlockUnsafe(launch_desc_loc, &launch_description, 82 memory_manager.ReadBlockUnsafe(launch_desc_loc, &launch_description,
@@ -60,4 +88,29 @@ void KeplerCompute::ProcessLaunch() {
60 rasterizer.DispatchCompute(code_addr); 88 rasterizer.DispatchCompute(code_addr);
61} 89}
62 90
91Texture::TICEntry KeplerCompute::GetTICEntry(u32 tic_index) const {
92 const GPUVAddr tic_address_gpu{regs.tic.Address() + tic_index * sizeof(Texture::TICEntry)};
93
94 Texture::TICEntry tic_entry;
95 memory_manager.ReadBlockUnsafe(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry));
96
97 const auto r_type{tic_entry.r_type.Value()};
98 const auto g_type{tic_entry.g_type.Value()};
99 const auto b_type{tic_entry.b_type.Value()};
100 const auto a_type{tic_entry.a_type.Value()};
101
102 // TODO(Subv): Different data types for separate components are not supported
103 DEBUG_ASSERT(r_type == g_type && r_type == b_type && r_type == a_type);
104
105 return tic_entry;
106}
107
108Texture::TSCEntry KeplerCompute::GetTSCEntry(u32 tsc_index) const {
109 const GPUVAddr tsc_address_gpu{regs.tsc.Address() + tsc_index * sizeof(Texture::TSCEntry)};
110
111 Texture::TSCEntry tsc_entry;
112 memory_manager.ReadBlockUnsafe(tsc_address_gpu, &tsc_entry, sizeof(Texture::TSCEntry));
113 return tsc_entry;
114}
115
63} // namespace Tegra::Engines 116} // namespace Tegra::Engines
diff --git a/src/video_core/engines/kepler_compute.h b/src/video_core/engines/kepler_compute.h
index 6a3309a2c..90cf650d2 100644
--- a/src/video_core/engines/kepler_compute.h
+++ b/src/video_core/engines/kepler_compute.h
@@ -12,6 +12,7 @@
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "video_core/engines/engine_upload.h" 13#include "video_core/engines/engine_upload.h"
14#include "video_core/gpu.h" 14#include "video_core/gpu.h"
15#include "video_core/textures/texture.h"
15 16
16namespace Core { 17namespace Core {
17class System; 18class System;
@@ -111,7 +112,7 @@ public:
111 112
112 INSERT_PADDING_WORDS(0x3FE); 113 INSERT_PADDING_WORDS(0x3FE);
113 114
114 u32 texture_const_buffer_index; 115 u32 tex_cb_index;
115 116
116 INSERT_PADDING_WORDS(0x374); 117 INSERT_PADDING_WORDS(0x374);
117 }; 118 };
@@ -149,7 +150,7 @@ public:
149 union { 150 union {
150 BitField<0, 8, u32> const_buffer_enable_mask; 151 BitField<0, 8, u32> const_buffer_enable_mask;
151 BitField<29, 2, u32> cache_layout; 152 BitField<29, 2, u32> cache_layout;
152 } memory_config; 153 };
153 154
154 INSERT_PADDING_WORDS(0x8); 155 INSERT_PADDING_WORDS(0x8);
155 156
@@ -194,6 +195,14 @@ public:
194 /// Write the value to the register identified by method. 195 /// Write the value to the register identified by method.
195 void CallMethod(const GPU::MethodCall& method_call); 196 void CallMethod(const GPU::MethodCall& method_call);
196 197
198 Tegra::Texture::FullTextureInfo GetTexture(std::size_t offset) const;
199
200 /// Given a Texture Handle, returns the TSC and TIC entries.
201 Texture::FullTextureInfo GetTextureInfo(const Texture::TextureHandle tex_handle,
202 std::size_t offset) const;
203
204 u32 AccessConstBuffer32(u64 const_buffer, u64 offset) const;
205
197private: 206private:
198 Core::System& system; 207 Core::System& system;
199 VideoCore::RasterizerInterface& rasterizer; 208 VideoCore::RasterizerInterface& rasterizer;
@@ -201,6 +210,12 @@ private:
201 Upload::State upload_state; 210 Upload::State upload_state;
202 211
203 void ProcessLaunch(); 212 void ProcessLaunch();
213
214 /// Retrieves information about a specific TIC entry from the TIC buffer.
215 Texture::TICEntry GetTICEntry(u32 tic_index) const;
216
217 /// Retrieves information about a specific TSC entry from the TSC buffer.
218 Texture::TSCEntry GetTSCEntry(u32 tsc_index) const;
204}; 219};
205 220
206#define ASSERT_REG_POSITION(field_name, position) \ 221#define ASSERT_REG_POSITION(field_name, position) \
@@ -218,12 +233,12 @@ ASSERT_REG_POSITION(launch, 0xAF);
218ASSERT_REG_POSITION(tsc, 0x557); 233ASSERT_REG_POSITION(tsc, 0x557);
219ASSERT_REG_POSITION(tic, 0x55D); 234ASSERT_REG_POSITION(tic, 0x55D);
220ASSERT_REG_POSITION(code_loc, 0x582); 235ASSERT_REG_POSITION(code_loc, 0x582);
221ASSERT_REG_POSITION(texture_const_buffer_index, 0x982); 236ASSERT_REG_POSITION(tex_cb_index, 0x982);
222ASSERT_LAUNCH_PARAM_POSITION(program_start, 0x8); 237ASSERT_LAUNCH_PARAM_POSITION(program_start, 0x8);
223ASSERT_LAUNCH_PARAM_POSITION(grid_dim_x, 0xC); 238ASSERT_LAUNCH_PARAM_POSITION(grid_dim_x, 0xC);
224ASSERT_LAUNCH_PARAM_POSITION(shared_alloc, 0x11); 239ASSERT_LAUNCH_PARAM_POSITION(shared_alloc, 0x11);
225ASSERT_LAUNCH_PARAM_POSITION(block_dim_x, 0x12); 240ASSERT_LAUNCH_PARAM_POSITION(block_dim_x, 0x12);
226ASSERT_LAUNCH_PARAM_POSITION(memory_config, 0x14); 241ASSERT_LAUNCH_PARAM_POSITION(const_buffer_enable_mask, 0x14);
227ASSERT_LAUNCH_PARAM_POSITION(const_buffer_config, 0x1D); 242ASSERT_LAUNCH_PARAM_POSITION(const_buffer_config, 0x1D);
228 243
229#undef ASSERT_REG_POSITION 244#undef ASSERT_REG_POSITION
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index f5158d219..c7a3c85a0 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -89,6 +89,9 @@ void Maxwell3D::InitializeRegisterDefaults() {
89 89
90 // Commercial games seem to assume this value is enabled and nouveau sets this value manually. 90 // Commercial games seem to assume this value is enabled and nouveau sets this value manually.
91 regs.rt_separate_frag_data = 1; 91 regs.rt_separate_frag_data = 1;
92
93 // Some games (like Super Mario Odyssey) assume that SRGB is enabled.
94 regs.framebuffer_srgb = 1;
92} 95}
93 96
94#define DIRTY_REGS_POS(field_name) (offsetof(Maxwell3D::DirtyRegs, field_name)) 97#define DIRTY_REGS_POS(field_name) (offsetof(Maxwell3D::DirtyRegs, field_name))
@@ -244,7 +247,7 @@ void Maxwell3D::InitDirtySettings() {
244 dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_clamp)] = polygon_offset_dirty_reg; 247 dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_clamp)] = polygon_offset_dirty_reg;
245} 248}
246 249
247void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { 250void Maxwell3D::CallMacroMethod(u32 method, std::size_t num_parameters, const u32* parameters) {
248 // Reset the current macro. 251 // Reset the current macro.
249 executing_macro = 0; 252 executing_macro = 0;
250 253
@@ -252,7 +255,7 @@ void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
252 const u32 entry = ((method - MacroRegistersStart) >> 1) % macro_positions.size(); 255 const u32 entry = ((method - MacroRegistersStart) >> 1) % macro_positions.size();
253 256
254 // Execute the current macro. 257 // Execute the current macro.
255 macro_interpreter.Execute(macro_positions[entry], std::move(parameters)); 258 macro_interpreter.Execute(macro_positions[entry], num_parameters, parameters);
256} 259}
257 260
258void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { 261void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
@@ -289,7 +292,8 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
289 292
290 // Call the macro when there are no more parameters in the command buffer 293 // Call the macro when there are no more parameters in the command buffer
291 if (method_call.IsLastCall()) { 294 if (method_call.IsLastCall()) {
292 CallMacroMethod(executing_macro, std::move(macro_params)); 295 CallMacroMethod(executing_macro, macro_params.size(), macro_params.data());
296 macro_params.clear();
293 } 297 }
294 return; 298 return;
295 } 299 }
@@ -328,6 +332,10 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
328 ProcessMacroBind(method_call.argument); 332 ProcessMacroBind(method_call.argument);
329 break; 333 break;
330 } 334 }
335 case MAXWELL3D_REG_INDEX(firmware[4]): {
336 ProcessFirmwareCall4();
337 break;
338 }
331 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]): 339 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
332 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]): 340 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]):
333 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]): 341 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):
@@ -418,6 +426,14 @@ void Maxwell3D::ProcessMacroBind(u32 data) {
418 macro_positions[regs.macros.entry++] = data; 426 macro_positions[regs.macros.entry++] = data;
419} 427}
420 428
429void Maxwell3D::ProcessFirmwareCall4() {
430 LOG_WARNING(HW_GPU, "(STUBBED) called");
431
432 // Firmware call 4 is a blob that changes some registers depending on its parameters.
433 // These registers don't affect emulation and so are stubbed by setting 0xd00 to 1.
434 regs.reg_array[0xd00] = 1;
435}
436
421void Maxwell3D::ProcessQueryGet() { 437void Maxwell3D::ProcessQueryGet() {
422 const GPUVAddr sequence_address{regs.query.QueryAddress()}; 438 const GPUVAddr sequence_address{regs.query.QueryAddress()};
423 // Since the sequence address is given as a GPU VAddr, we have to convert it to an application 439 // Since the sequence address is given as a GPU VAddr, we have to convert it to an application
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 0184342a0..e5ec90717 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -62,6 +62,7 @@ public:
62 static constexpr std::size_t NumVertexAttributes = 32; 62 static constexpr std::size_t NumVertexAttributes = 32;
63 static constexpr std::size_t NumVaryings = 31; 63 static constexpr std::size_t NumVaryings = 31;
64 static constexpr std::size_t NumTextureSamplers = 32; 64 static constexpr std::size_t NumTextureSamplers = 32;
65 static constexpr std::size_t NumImages = 8; // TODO(Rodrigo): Investigate this number
65 static constexpr std::size_t NumClipDistances = 8; 66 static constexpr std::size_t NumClipDistances = 8;
66 static constexpr std::size_t MaxShaderProgram = 6; 67 static constexpr std::size_t MaxShaderProgram = 6;
67 static constexpr std::size_t MaxShaderStage = 5; 68 static constexpr std::size_t MaxShaderStage = 5;
@@ -1088,7 +1089,9 @@ public:
1088 INSERT_PADDING_WORDS(14); 1089 INSERT_PADDING_WORDS(14);
1089 } shader_config[MaxShaderProgram]; 1090 } shader_config[MaxShaderProgram];
1090 1091
1091 INSERT_PADDING_WORDS(0x80); 1092 INSERT_PADDING_WORDS(0x60);
1093
1094 u32 firmware[0x20];
1092 1095
1093 struct { 1096 struct {
1094 u32 cb_size; 1097 u32 cb_size;
@@ -1307,9 +1310,10 @@ private:
1307 /** 1310 /**
1308 * Call a macro on this engine. 1311 * Call a macro on this engine.
1309 * @param method Method to call 1312 * @param method Method to call
1313 * @param num_parameters Number of arguments
1310 * @param parameters Arguments to the method call 1314 * @param parameters Arguments to the method call
1311 */ 1315 */
1312 void CallMacroMethod(u32 method, std::vector<u32> parameters); 1316 void CallMacroMethod(u32 method, std::size_t num_parameters, const u32* parameters);
1313 1317
1314 /// Handles writes to the macro uploading register. 1318 /// Handles writes to the macro uploading register.
1315 void ProcessMacroUpload(u32 data); 1319 void ProcessMacroUpload(u32 data);
@@ -1317,6 +1321,9 @@ private:
1317 /// Handles writes to the macro bind register. 1321 /// Handles writes to the macro bind register.
1318 void ProcessMacroBind(u32 data); 1322 void ProcessMacroBind(u32 data);
1319 1323
1324 /// Handles firmware blob 4
1325 void ProcessFirmwareCall4();
1326
1320 /// Handles a write to the CLEAR_BUFFERS register. 1327 /// Handles a write to the CLEAR_BUFFERS register.
1321 void ProcessClearBuffers(); 1328 void ProcessClearBuffers();
1322 1329
@@ -1429,6 +1436,7 @@ ASSERT_REG_POSITION(vertex_array[0], 0x700);
1429ASSERT_REG_POSITION(independent_blend, 0x780); 1436ASSERT_REG_POSITION(independent_blend, 0x780);
1430ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0); 1437ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0);
1431ASSERT_REG_POSITION(shader_config[0], 0x800); 1438ASSERT_REG_POSITION(shader_config[0], 0x800);
1439ASSERT_REG_POSITION(firmware, 0x8C0);
1432ASSERT_REG_POSITION(const_buffer, 0x8E0); 1440ASSERT_REG_POSITION(const_buffer, 0x8E0);
1433ASSERT_REG_POSITION(cb_bind[0], 0x904); 1441ASSERT_REG_POSITION(cb_bind[0], 0x904);
1434ASSERT_REG_POSITION(tex_cb_index, 0x982); 1442ASSERT_REG_POSITION(tex_cb_index, 0x982);
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index c3678b9ea..a6110bd86 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -544,6 +544,35 @@ enum class VoteOperation : u64 {
544 Eq = 2, // allThreadsEqualNV 544 Eq = 2, // allThreadsEqualNV
545}; 545};
546 546
547enum class ImageAtomicSize : u64 {
548 U32 = 0,
549 S32 = 1,
550 U64 = 2,
551 F32 = 3,
552 S64 = 5,
553 SD32 = 6,
554 SD64 = 7,
555};
556
557enum class ImageAtomicOperation : u64 {
558 Add = 0,
559 Min = 1,
560 Max = 2,
561 Inc = 3,
562 Dec = 4,
563 And = 5,
564 Or = 6,
565 Xor = 7,
566 Exch = 8,
567};
568
569enum class ShuffleOperation : u64 {
570 Idx = 0, // shuffleNV
571 Up = 1, // shuffleUpNV
572 Down = 2, // shuffleDownNV
573 Bfly = 3, // shuffleXorNV
574};
575
547union Instruction { 576union Instruction {
548 Instruction& operator=(const Instruction& instr) { 577 Instruction& operator=(const Instruction& instr) {
549 value = instr.value; 578 value = instr.value;
@@ -578,6 +607,15 @@ union Instruction {
578 } vote; 607 } vote;
579 608
580 union { 609 union {
610 BitField<30, 2, ShuffleOperation> operation;
611 BitField<48, 3, u64> pred48;
612 BitField<28, 1, u64> is_index_imm;
613 BitField<29, 1, u64> is_mask_imm;
614 BitField<20, 5, u64> index_imm;
615 BitField<34, 13, u64> mask_imm;
616 } shfl;
617
618 union {
581 BitField<8, 8, Register> gpr; 619 BitField<8, 8, Register> gpr;
582 BitField<20, 24, s64> offset; 620 BitField<20, 24, s64> offset;
583 } gmem; 621 } gmem;
@@ -675,6 +713,10 @@ union Instruction {
675 } shift; 713 } shift;
676 714
677 union { 715 union {
716 BitField<39, 1, u64> wrap;
717 } shr;
718
719 union {
678 BitField<39, 5, u64> shift_amount; 720 BitField<39, 5, u64> shift_amount;
679 BitField<48, 1, u64> negate_b; 721 BitField<48, 1, u64> negate_b;
680 BitField<49, 1, u64> negate_a; 722 BitField<49, 1, u64> negate_a;
@@ -1388,6 +1430,14 @@ union Instruction {
1388 } sust; 1430 } sust;
1389 1431
1390 union { 1432 union {
1433 BitField<28, 1, u64> is_ba;
1434 BitField<51, 3, ImageAtomicSize> size;
1435 BitField<33, 3, ImageType> image_type;
1436 BitField<29, 4, ImageAtomicOperation> operation;
1437 BitField<49, 2, OutOfBoundsStore> out_of_bounds_store;
1438 } suatom_d;
1439
1440 union {
1391 BitField<20, 24, u64> target; 1441 BitField<20, 24, u64> target;
1392 BitField<5, 1, u64> constant_buffer; 1442 BitField<5, 1, u64> constant_buffer;
1393 1443
@@ -1508,6 +1558,7 @@ public:
1508 BRK, 1558 BRK,
1509 DEPBAR, 1559 DEPBAR,
1510 VOTE, 1560 VOTE,
1561 SHFL,
1511 BFE_C, 1562 BFE_C,
1512 BFE_R, 1563 BFE_R,
1513 BFE_IMM, 1564 BFE_IMM,
@@ -1539,6 +1590,7 @@ public:
1539 TMML_B, // Texture Mip Map Level 1590 TMML_B, // Texture Mip Map Level
1540 TMML, // Texture Mip Map Level 1591 TMML, // Texture Mip Map Level
1541 SUST, // Surface Store 1592 SUST, // Surface Store
1593 SUATOM, // Surface Atomic Operation
1542 EXIT, 1594 EXIT,
1543 NOP, 1595 NOP,
1544 IPA, 1596 IPA,
@@ -1798,6 +1850,7 @@ private:
1798 INST("111000110000----", Id::EXIT, Type::Flow, "EXIT"), 1850 INST("111000110000----", Id::EXIT, Type::Flow, "EXIT"),
1799 INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"), 1851 INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"),
1800 INST("0101000011011---", Id::VOTE, Type::Warp, "VOTE"), 1852 INST("0101000011011---", Id::VOTE, Type::Warp, "VOTE"),
1853 INST("1110111100010---", Id::SHFL, Type::Warp, "SHFL"),
1801 INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), 1854 INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),
1802 INST("1110111101001---", Id::LD_S, Type::Memory, "LD_S"), 1855 INST("1110111101001---", Id::LD_S, Type::Memory, "LD_S"),
1803 INST("1110111101000---", Id::LD_L, Type::Memory, "LD_L"), 1856 INST("1110111101000---", Id::LD_L, Type::Memory, "LD_L"),
@@ -1822,6 +1875,7 @@ private:
1822 INST("110111110110----", Id::TMML_B, Type::Texture, "TMML_B"), 1875 INST("110111110110----", Id::TMML_B, Type::Texture, "TMML_B"),
1823 INST("1101111101011---", Id::TMML, Type::Texture, "TMML"), 1876 INST("1101111101011---", Id::TMML, Type::Texture, "TMML"),
1824 INST("11101011001-----", Id::SUST, Type::Image, "SUST"), 1877 INST("11101011001-----", Id::SUST, Type::Image, "SUST"),
1878 INST("1110101000------", Id::SUATOM, Type::Image, "SUATOM_D"),
1825 INST("0101000010110---", Id::NOP, Type::Trivial, "NOP"), 1879 INST("0101000010110---", Id::NOP, Type::Trivial, "NOP"),
1826 INST("11100000--------", Id::IPA, Type::Trivial, "IPA"), 1880 INST("11100000--------", Id::IPA, Type::Trivial, "IPA"),
1827 INST("1111101111100---", Id::OUT_R, Type::Trivial, "OUT_R"), 1881 INST("1111101111100---", Id::OUT_R, Type::Trivial, "OUT_R"),
diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp
index 9f59a2dc1..62afc0d11 100644
--- a/src/video_core/macro_interpreter.cpp
+++ b/src/video_core/macro_interpreter.cpp
@@ -14,11 +14,18 @@ namespace Tegra {
14 14
15MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {} 15MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
16 16
17void MacroInterpreter::Execute(u32 offset, std::vector<u32> parameters) { 17void MacroInterpreter::Execute(u32 offset, std::size_t num_parameters, const u32* parameters) {
18 MICROPROFILE_SCOPE(MacroInterp); 18 MICROPROFILE_SCOPE(MacroInterp);
19 Reset(); 19 Reset();
20
20 registers[1] = parameters[0]; 21 registers[1] = parameters[0];
21 this->parameters = std::move(parameters); 22
23 if (num_parameters > parameters_capacity) {
24 parameters_capacity = num_parameters;
25 this->parameters = std::make_unique<u32[]>(num_parameters);
26 }
27 std::memcpy(this->parameters.get(), parameters, num_parameters * sizeof(u32));
28 this->num_parameters = num_parameters;
22 29
23 // Execute the code until we hit an exit condition. 30 // Execute the code until we hit an exit condition.
24 bool keep_executing = true; 31 bool keep_executing = true;
@@ -27,7 +34,7 @@ void MacroInterpreter::Execute(u32 offset, std::vector<u32> parameters) {
27 } 34 }
28 35
29 // Assert the the macro used all the input parameters 36 // Assert the the macro used all the input parameters
30 ASSERT(next_parameter_index == this->parameters.size()); 37 ASSERT(next_parameter_index == num_parameters);
31} 38}
32 39
33void MacroInterpreter::Reset() { 40void MacroInterpreter::Reset() {
@@ -35,7 +42,7 @@ void MacroInterpreter::Reset() {
35 pc = 0; 42 pc = 0;
36 delayed_pc = {}; 43 delayed_pc = {};
37 method_address.raw = 0; 44 method_address.raw = 0;
38 parameters.clear(); 45 num_parameters = 0;
39 // The next parameter index starts at 1, because $r1 already has the value of the first 46 // The next parameter index starts at 1, because $r1 already has the value of the first
40 // parameter. 47 // parameter.
41 next_parameter_index = 1; 48 next_parameter_index = 1;
@@ -124,9 +131,7 @@ bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) {
124 131
125 // An instruction with the Exit flag will not actually 132 // An instruction with the Exit flag will not actually
126 // cause an exit if it's executed inside a delay slot. 133 // cause an exit if it's executed inside a delay slot.
127 // TODO(Blinkhawk): Reversed to always exit. The behavior explained above requires further 134 if (opcode.is_exit && !is_delay_slot) {
128 // testing on the MME code.
129 if (opcode.is_exit) {
130 // Exit has a delay slot, execute the next instruction 135 // Exit has a delay slot, execute the next instruction
131 Step(offset, true); 136 Step(offset, true);
132 return false; 137 return false;
@@ -229,7 +234,8 @@ void MacroInterpreter::ProcessResult(ResultOperation operation, u32 reg, u32 res
229} 234}
230 235
231u32 MacroInterpreter::FetchParameter() { 236u32 MacroInterpreter::FetchParameter() {
232 return parameters.at(next_parameter_index++); 237 ASSERT(next_parameter_index < num_parameters);
238 return parameters[next_parameter_index++];
233} 239}
234 240
235u32 MacroInterpreter::GetRegister(u32 register_id) const { 241u32 MacroInterpreter::GetRegister(u32 register_id) const {
diff --git a/src/video_core/macro_interpreter.h b/src/video_core/macro_interpreter.h
index cde360288..76b6a895b 100644
--- a/src/video_core/macro_interpreter.h
+++ b/src/video_core/macro_interpreter.h
@@ -25,7 +25,7 @@ public:
25 * @param offset Offset to start execution at. 25 * @param offset Offset to start execution at.
26 * @param parameters The parameters of the macro. 26 * @param parameters The parameters of the macro.
27 */ 27 */
28 void Execute(u32 offset, std::vector<u32> parameters); 28 void Execute(u32 offset, std::size_t num_parameters, const u32* parameters);
29 29
30private: 30private:
31 enum class Operation : u32 { 31 enum class Operation : u32 {
@@ -162,10 +162,12 @@ private:
162 MethodAddress method_address = {}; 162 MethodAddress method_address = {};
163 163
164 /// Input parameters of the current macro. 164 /// Input parameters of the current macro.
165 std::vector<u32> parameters; 165 std::unique_ptr<u32[]> parameters;
166 std::size_t num_parameters = 0;
167 std::size_t parameters_capacity = 0;
166 /// Index of the next parameter that will be fetched by the 'parm' instruction. 168 /// Index of the next parameter that will be fetched by the 'parm' instruction.
167 u32 next_parameter_index = 0; 169 u32 next_parameter_index = 0;
168 170
169 bool carry_flag{}; 171 bool carry_flag = false;
170}; 172};
171} // namespace Tegra 173} // namespace Tegra
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 01d89f47d..4dd08bccb 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -331,7 +331,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
331 const auto stage_enum = static_cast<Maxwell::ShaderStage>(stage); 331 const auto stage_enum = static_cast<Maxwell::ShaderStage>(stage);
332 SetupDrawConstBuffers(stage_enum, shader); 332 SetupDrawConstBuffers(stage_enum, shader);
333 SetupDrawGlobalMemory(stage_enum, shader); 333 SetupDrawGlobalMemory(stage_enum, shader);
334 const auto texture_buffer_usage{SetupTextures(stage_enum, shader, base_bindings)}; 334 const auto texture_buffer_usage{SetupDrawTextures(stage_enum, shader, base_bindings)};
335 335
336 const ProgramVariant variant{base_bindings, primitive_mode, texture_buffer_usage}; 336 const ProgramVariant variant{base_bindings, primitive_mode, texture_buffer_usage};
337 const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant); 337 const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant);
@@ -489,9 +489,6 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
489 // Assume that a surface will be written to if it is used as a framebuffer, even if 489 // Assume that a surface will be written to if it is used as a framebuffer, even if
490 // the shader doesn't actually write to it. 490 // the shader doesn't actually write to it.
491 texture_cache.MarkColorBufferInUse(*single_color_target); 491 texture_cache.MarkColorBufferInUse(*single_color_target);
492 // Workaround for and issue in nvidia drivers
493 // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/
494 state.framebuffer_srgb.enabled |= color_surface->GetSurfaceParams().srgb_conversion;
495 } 492 }
496 493
497 fbkey.is_single_buffer = true; 494 fbkey.is_single_buffer = true;
@@ -512,11 +509,6 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
512 // Assume that a surface will be written to if it is used as a framebuffer, even 509 // Assume that a surface will be written to if it is used as a framebuffer, even
513 // if the shader doesn't actually write to it. 510 // if the shader doesn't actually write to it.
514 texture_cache.MarkColorBufferInUse(index); 511 texture_cache.MarkColorBufferInUse(index);
515 // Enable sRGB only for supported formats
516 // Workaround for and issue in nvidia drivers
517 // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/
518 state.framebuffer_srgb.enabled |=
519 color_surface->GetSurfaceParams().srgb_conversion;
520 } 512 }
521 513
522 fbkey.color_attachments[index] = 514 fbkey.color_attachments[index] =
@@ -801,7 +793,11 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
801 } 793 }
802 794
803 auto kernel = shader_cache.GetComputeKernel(code_addr); 795 auto kernel = shader_cache.GetComputeKernel(code_addr);
804 const auto [program, next_bindings] = kernel->GetProgramHandle({}); 796 ProgramVariant variant;
797 variant.texture_buffer_usage = SetupComputeTextures(kernel);
798 SetupComputeImages(kernel);
799
800 const auto [program, next_bindings] = kernel->GetProgramHandle(variant);
805 state.draw.shader_program = program; 801 state.draw.shader_program = program;
806 state.draw.program_pipeline = 0; 802 state.draw.program_pipeline = 0;
807 803
@@ -816,13 +812,13 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
816 SetupComputeConstBuffers(kernel); 812 SetupComputeConstBuffers(kernel);
817 SetupComputeGlobalMemory(kernel); 813 SetupComputeGlobalMemory(kernel);
818 814
819 // TODO(Rodrigo): Bind images and samplers
820
821 buffer_cache.Unmap(); 815 buffer_cache.Unmap();
822 816
823 bind_ubo_pushbuffer.Bind(); 817 bind_ubo_pushbuffer.Bind();
824 bind_ssbo_pushbuffer.Bind(); 818 bind_ssbo_pushbuffer.Bind();
825 819
820 state.ApplyTextures();
821 state.ApplyImages();
826 state.ApplyShaderProgram(); 822 state.ApplyShaderProgram();
827 state.ApplyProgramPipeline(); 823 state.ApplyProgramPipeline();
828 824
@@ -902,6 +898,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
902 } 898 }
903 899
904 screen_info.display_texture = surface->GetTexture(); 900 screen_info.display_texture = surface->GetTexture();
901 screen_info.display_srgb = surface->GetSurfaceParams().srgb_conversion;
905 902
906 return true; 903 return true;
907} 904}
@@ -922,7 +919,7 @@ void RasterizerOpenGL::SetupComputeConstBuffers(const Shader& kernel) {
922 const auto& launch_desc = system.GPU().KeplerCompute().launch_description; 919 const auto& launch_desc = system.GPU().KeplerCompute().launch_description;
923 for (const auto& entry : kernel->GetShaderEntries().const_buffers) { 920 for (const auto& entry : kernel->GetShaderEntries().const_buffers) {
924 const auto& config = launch_desc.const_buffer_config[entry.GetIndex()]; 921 const auto& config = launch_desc.const_buffer_config[entry.GetIndex()];
925 const std::bitset<8> mask = launch_desc.memory_config.const_buffer_enable_mask.Value(); 922 const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value();
926 Tegra::Engines::ConstBufferInfo buffer; 923 Tegra::Engines::ConstBufferInfo buffer;
927 buffer.address = config.Address(); 924 buffer.address = config.Address();
928 buffer.size = config.size; 925 buffer.size = config.size;
@@ -981,53 +978,125 @@ void RasterizerOpenGL::SetupGlobalMemory(const GLShader::GlobalMemoryEntry& entr
981 bind_ssbo_pushbuffer.Push(ssbo, buffer_offset, static_cast<GLsizeiptr>(size)); 978 bind_ssbo_pushbuffer.Push(ssbo, buffer_offset, static_cast<GLsizeiptr>(size));
982} 979}
983 980
984TextureBufferUsage RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader, 981TextureBufferUsage RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stage,
985 BaseBindings base_bindings) { 982 const Shader& shader,
983 BaseBindings base_bindings) {
986 MICROPROFILE_SCOPE(OpenGL_Texture); 984 MICROPROFILE_SCOPE(OpenGL_Texture);
987 const auto& gpu = system.GPU(); 985 const auto& gpu = system.GPU();
988 const auto& maxwell3d = gpu.Maxwell3D(); 986 const auto& maxwell3d = gpu.Maxwell3D();
989 const auto& entries = shader->GetShaderEntries().samplers; 987 const auto& entries = shader->GetShaderEntries().samplers;
990 988
991 ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.texture_units), 989 ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.textures),
992 "Exceeded the number of active textures."); 990 "Exceeded the number of active textures.");
993 991
994 TextureBufferUsage texture_buffer_usage{0}; 992 TextureBufferUsage texture_buffer_usage{0};
995 993
996 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { 994 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
997 const auto& entry = entries[bindpoint]; 995 const auto& entry = entries[bindpoint];
998 Tegra::Texture::FullTextureInfo texture; 996 const auto texture = [&]() {
999 if (entry.IsBindless()) { 997 if (!entry.IsBindless()) {
998 return maxwell3d.GetStageTexture(stage, entry.GetOffset());
999 }
1000 const auto cbuf = entry.GetBindlessCBuf(); 1000 const auto cbuf = entry.GetBindlessCBuf();
1001 Tegra::Texture::TextureHandle tex_handle; 1001 Tegra::Texture::TextureHandle tex_handle;
1002 tex_handle.raw = maxwell3d.AccessConstBuffer32(stage, cbuf.first, cbuf.second); 1002 tex_handle.raw = maxwell3d.AccessConstBuffer32(stage, cbuf.first, cbuf.second);
1003 texture = maxwell3d.GetTextureInfo(tex_handle, entry.GetOffset()); 1003 return maxwell3d.GetTextureInfo(tex_handle, entry.GetOffset());
1004 } else { 1004 }();
1005 texture = maxwell3d.GetStageTexture(stage, entry.GetOffset()); 1005
1006 if (SetupTexture(base_bindings.sampler + bindpoint, texture, entry)) {
1007 texture_buffer_usage.set(bindpoint);
1006 } 1008 }
1007 const u32 current_bindpoint = base_bindings.sampler + bindpoint; 1009 }
1008 1010
1009 auto& unit{state.texture_units[current_bindpoint]}; 1011 return texture_buffer_usage;
1010 unit.sampler = sampler_cache.GetSampler(texture.tsc); 1012}
1011 1013
1012 if (const auto view{texture_cache.GetTextureSurface(texture, entry)}; view) { 1014TextureBufferUsage RasterizerOpenGL::SetupComputeTextures(const Shader& kernel) {
1013 if (view->GetSurfaceParams().IsBuffer()) { 1015 MICROPROFILE_SCOPE(OpenGL_Texture);
1014 // Record that this texture is a texture buffer. 1016 const auto& compute = system.GPU().KeplerCompute();
1015 texture_buffer_usage.set(bindpoint); 1017 const auto& entries = kernel->GetShaderEntries().samplers;
1016 } else { 1018
1017 // Apply swizzle to textures that are not buffers. 1019 ASSERT_MSG(entries.size() <= std::size(state.textures),
1018 view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source, 1020 "Exceeded the number of active textures.");
1019 texture.tic.w_source); 1021
1022 TextureBufferUsage texture_buffer_usage{0};
1023
1024 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
1025 const auto& entry = entries[bindpoint];
1026 const auto texture = [&]() {
1027 if (!entry.IsBindless()) {
1028 return compute.GetTexture(entry.GetOffset());
1020 } 1029 }
1021 state.texture_units[current_bindpoint].texture = view->GetTexture(); 1030 const auto cbuf = entry.GetBindlessCBuf();
1022 } else { 1031 Tegra::Texture::TextureHandle tex_handle;
1023 // Can occur when texture addr is null or its memory is unmapped/invalid 1032 tex_handle.raw = compute.AccessConstBuffer32(cbuf.first, cbuf.second);
1024 unit.texture = 0; 1033 return compute.GetTextureInfo(tex_handle, entry.GetOffset());
1034 }();
1035
1036 if (SetupTexture(bindpoint, texture, entry)) {
1037 texture_buffer_usage.set(bindpoint);
1025 } 1038 }
1026 } 1039 }
1027 1040
1028 return texture_buffer_usage; 1041 return texture_buffer_usage;
1029} 1042}
1030 1043
1044bool RasterizerOpenGL::SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture,
1045 const GLShader::SamplerEntry& entry) {
1046 state.samplers[binding] = sampler_cache.GetSampler(texture.tsc);
1047
1048 const auto view = texture_cache.GetTextureSurface(texture.tic, entry);
1049 if (!view) {
1050 // Can occur when texture addr is null or its memory is unmapped/invalid
1051 state.textures[binding] = 0;
1052 return false;
1053 }
1054 state.textures[binding] = view->GetTexture();
1055
1056 if (view->GetSurfaceParams().IsBuffer()) {
1057 return true;
1058 }
1059
1060 // Apply swizzle to textures that are not buffers.
1061 view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
1062 texture.tic.w_source);
1063 return false;
1064}
1065
1066void RasterizerOpenGL::SetupComputeImages(const Shader& shader) {
1067 const auto& compute = system.GPU().KeplerCompute();
1068 const auto& entries = shader->GetShaderEntries().images;
1069 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
1070 const auto& entry = entries[bindpoint];
1071 const auto tic = [&]() {
1072 if (!entry.IsBindless()) {
1073 return compute.GetTexture(entry.GetOffset()).tic;
1074 }
1075 const auto cbuf = entry.GetBindlessCBuf();
1076 Tegra::Texture::TextureHandle tex_handle;
1077 tex_handle.raw = compute.AccessConstBuffer32(cbuf.first, cbuf.second);
1078 return compute.GetTextureInfo(tex_handle, entry.GetOffset()).tic;
1079 }();
1080 SetupImage(bindpoint, tic, entry);
1081 }
1082}
1083
1084void RasterizerOpenGL::SetupImage(u32 binding, const Tegra::Texture::TICEntry& tic,
1085 const GLShader::ImageEntry& entry) {
1086 const auto view = texture_cache.GetImageSurface(tic, entry);
1087 if (!view) {
1088 state.images[binding] = 0;
1089 return;
1090 }
1091 if (!tic.IsBuffer()) {
1092 view->ApplySwizzle(tic.x_source, tic.y_source, tic.z_source, tic.w_source);
1093 }
1094 if (entry.IsWritten()) {
1095 view->MarkAsModified(texture_cache.Tick());
1096 }
1097 state.images[binding] = view->GetTexture();
1098}
1099
1031void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { 1100void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
1032 const auto& regs = system.GPU().Maxwell3D().regs; 1101 const auto& regs = system.GPU().Maxwell3D().regs;
1033 const bool geometry_shaders_enabled = 1102 const bool geometry_shaders_enabled =
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 9d20a4fbf..eada752e0 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -32,6 +32,7 @@
32#include "video_core/renderer_opengl/gl_state.h" 32#include "video_core/renderer_opengl/gl_state.h"
33#include "video_core/renderer_opengl/gl_texture_cache.h" 33#include "video_core/renderer_opengl/gl_texture_cache.h"
34#include "video_core/renderer_opengl/utils.h" 34#include "video_core/renderer_opengl/utils.h"
35#include "video_core/textures/texture.h"
35 36
36namespace Core { 37namespace Core {
37class System; 38class System;
@@ -137,8 +138,22 @@ private:
137 138
138 /// Configures the current textures to use for the draw command. Returns shaders texture buffer 139 /// Configures the current textures to use for the draw command. Returns shaders texture buffer
139 /// usage. 140 /// usage.
140 TextureBufferUsage SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, 141 TextureBufferUsage SetupDrawTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
141 const Shader& shader, BaseBindings base_bindings); 142 const Shader& shader, BaseBindings base_bindings);
143
144 /// Configures the textures used in a compute shader. Returns texture buffer usage.
145 TextureBufferUsage SetupComputeTextures(const Shader& kernel);
146
147 /// Configures a texture. Returns true when the texture is a texture buffer.
148 bool SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture,
149 const GLShader::SamplerEntry& entry);
150
151 /// Configures images in a compute shader.
152 void SetupComputeImages(const Shader& shader);
153
154 /// Configures an image.
155 void SetupImage(u32 binding, const Tegra::Texture::TICEntry& tic,
156 const GLShader::ImageEntry& entry);
142 157
143 /// Syncs the viewport and depth range to match the guest state 158 /// Syncs the viewport and depth range to match the guest state
144 void SyncViewport(OpenGLState& current_state); 159 void SyncViewport(OpenGLState& current_state);
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 909ccb82c..0dbc4c02f 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -214,7 +214,8 @@ CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEn
214 std::string source = "#version 430 core\n" 214 std::string source = "#version 430 core\n"
215 "#extension GL_ARB_separate_shader_objects : enable\n" 215 "#extension GL_ARB_separate_shader_objects : enable\n"
216 "#extension GL_NV_gpu_shader5 : enable\n" 216 "#extension GL_NV_gpu_shader5 : enable\n"
217 "#extension GL_NV_shader_thread_group : enable\n"; 217 "#extension GL_NV_shader_thread_group : enable\n"
218 "#extension GL_NV_shader_thread_shuffle : enable\n";
218 if (entries.shader_viewport_layer_array) { 219 if (entries.shader_viewport_layer_array) {
219 source += "#extension GL_ARB_shader_viewport_layer_array : enable\n"; 220 source += "#extension GL_ARB_shader_viewport_layer_array : enable\n";
220 } 221 }
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 4a8c7edc9..76439e7ab 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -325,6 +325,7 @@ public:
325 DeclareRegisters(); 325 DeclareRegisters();
326 DeclarePredicates(); 326 DeclarePredicates();
327 DeclareLocalMemory(); 327 DeclareLocalMemory();
328 DeclareSharedMemory();
328 DeclareInternalFlags(); 329 DeclareInternalFlags();
329 DeclareInputAttributes(); 330 DeclareInputAttributes();
330 DeclareOutputAttributes(); 331 DeclareOutputAttributes();
@@ -389,11 +390,10 @@ public:
389 for (const auto& sampler : ir.GetSamplers()) { 390 for (const auto& sampler : ir.GetSamplers()) {
390 entries.samplers.emplace_back(sampler); 391 entries.samplers.emplace_back(sampler);
391 } 392 }
392 for (const auto& image : ir.GetImages()) { 393 for (const auto& [offset, image] : ir.GetImages()) {
393 entries.images.emplace_back(image); 394 entries.images.emplace_back(image);
394 } 395 }
395 for (const auto& gmem_pair : ir.GetGlobalMemory()) { 396 for (const auto& [base, usage] : ir.GetGlobalMemory()) {
396 const auto& [base, usage] = gmem_pair;
397 entries.global_memory_entries.emplace_back(base.cbuf_index, base.cbuf_offset, 397 entries.global_memory_entries.emplace_back(base.cbuf_index, base.cbuf_offset,
398 usage.is_read, usage.is_written); 398 usage.is_read, usage.is_written);
399 } 399 }
@@ -500,6 +500,13 @@ private:
500 code.AddNewLine(); 500 code.AddNewLine();
501 } 501 }
502 502
503 void DeclareSharedMemory() {
504 if (stage != ProgramType::Compute) {
505 return;
506 }
507 code.AddLine("shared uint {}[];", GetSharedMemory());
508 }
509
503 void DeclareInternalFlags() { 510 void DeclareInternalFlags() {
504 for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) { 511 for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) {
505 const auto flag_code = static_cast<InternalFlag>(flag); 512 const auto flag_code = static_cast<InternalFlag>(flag);
@@ -706,8 +713,8 @@ private:
706 713
707 void DeclareImages() { 714 void DeclareImages() {
708 const auto& images{ir.GetImages()}; 715 const auto& images{ir.GetImages()};
709 for (const auto& image : images) { 716 for (const auto& [offset, image] : images) {
710 const std::string image_type = [&]() { 717 const char* image_type = [&] {
711 switch (image.GetType()) { 718 switch (image.GetType()) {
712 case Tegra::Shader::ImageType::Texture1D: 719 case Tegra::Shader::ImageType::Texture1D:
713 return "image1D"; 720 return "image1D";
@@ -726,9 +733,33 @@ private:
726 return "image1D"; 733 return "image1D";
727 } 734 }
728 }(); 735 }();
729 code.AddLine("layout (binding = IMAGE_BINDING_{}) coherent volatile writeonly uniform " 736
737 const auto [type_prefix, format] = [&]() -> std::pair<const char*, const char*> {
738 if (!image.IsSizeKnown()) {
739 return {"", ""};
740 }
741 switch (image.GetSize()) {
742 case Tegra::Shader::ImageAtomicSize::U32:
743 return {"u", "r32ui, "};
744 case Tegra::Shader::ImageAtomicSize::S32:
745 return {"i", "r32i, "};
746 default:
747 UNIMPLEMENTED_MSG("Unimplemented atomic size={}",
748 static_cast<u32>(image.GetSize()));
749 return {"", ""};
750 }
751 }();
752
753 std::string qualifier = "coherent volatile";
754 if (image.IsRead() && !image.IsWritten()) {
755 qualifier += " readonly";
756 } else if (image.IsWritten() && !image.IsRead()) {
757 qualifier += " writeonly";
758 }
759
760 code.AddLine("layout (binding = IMAGE_BINDING_{}) {} uniform "
730 "{} {};", 761 "{} {};",
731 image.GetIndex(), image_type, GetImage(image)); 762 image.GetIndex(), qualifier, image_type, GetImage(image));
732 } 763 }
733 if (!images.empty()) { 764 if (!images.empty()) {
734 code.AddNewLine(); 765 code.AddNewLine();
@@ -858,6 +889,12 @@ private:
858 Type::Uint}; 889 Type::Uint};
859 } 890 }
860 891
892 if (const auto smem = std::get_if<SmemNode>(&*node)) {
893 return {
894 fmt::format("{}[{} >> 2]", GetSharedMemory(), Visit(smem->GetAddress()).AsUint()),
895 Type::Uint};
896 }
897
861 if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) { 898 if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) {
862 return {GetInternalFlag(internal_flag->GetFlag()), Type::Bool}; 899 return {GetInternalFlag(internal_flag->GetFlag()), Type::Bool};
863 } 900 }
@@ -1174,6 +1211,74 @@ private:
1174 return expr; 1211 return expr;
1175 } 1212 }
1176 1213
1214 std::string BuildIntegerCoordinates(Operation operation) {
1215 constexpr std::array constructors{"int(", "ivec2(", "ivec3(", "ivec4("};
1216 const std::size_t coords_count{operation.GetOperandsCount()};
1217 std::string expr = constructors.at(coords_count - 1);
1218 for (std::size_t i = 0; i < coords_count; ++i) {
1219 expr += VisitOperand(operation, i).AsInt();
1220 if (i + 1 < coords_count) {
1221 expr += ", ";
1222 }
1223 }
1224 expr += ')';
1225 return expr;
1226 }
1227
1228 std::string BuildImageValues(Operation operation) {
1229 const auto meta{std::get<MetaImage>(operation.GetMeta())};
1230 const auto [constructors, type] = [&]() -> std::pair<std::array<const char*, 4>, Type> {
1231 constexpr std::array float_constructors{"float", "vec2", "vec3", "vec4"};
1232 if (!meta.image.IsSizeKnown()) {
1233 return {float_constructors, Type::Float};
1234 }
1235 switch (meta.image.GetSize()) {
1236 case Tegra::Shader::ImageAtomicSize::U32:
1237 return {{"uint", "uvec2", "uvec3", "uvec4"}, Type::Uint};
1238 case Tegra::Shader::ImageAtomicSize::S32:
1239 return {{"int", "ivec2", "ivec3", "ivec4"}, Type::Uint};
1240 default:
1241 UNIMPLEMENTED_MSG("Unimplemented image size={}",
1242 static_cast<u32>(meta.image.GetSize()));
1243 return {float_constructors, Type::Float};
1244 }
1245 }();
1246
1247 const std::size_t values_count{meta.values.size()};
1248 std::string expr = fmt::format("{}(", constructors.at(values_count - 1));
1249 for (std::size_t i = 0; i < values_count; ++i) {
1250 expr += Visit(meta.values.at(i)).As(type);
1251 if (i + 1 < values_count) {
1252 expr += ", ";
1253 }
1254 }
1255 expr += ')';
1256 return expr;
1257 }
1258
1259 Expression AtomicImage(Operation operation, const char* opname) {
1260 constexpr std::array constructors{"int(", "ivec2(", "ivec3(", "ivec4("};
1261 const auto meta{std::get<MetaImage>(operation.GetMeta())};
1262 ASSERT(meta.values.size() == 1);
1263 ASSERT(meta.image.IsSizeKnown());
1264
1265 const auto type = [&]() {
1266 switch (const auto size = meta.image.GetSize()) {
1267 case Tegra::Shader::ImageAtomicSize::U32:
1268 return Type::Uint;
1269 case Tegra::Shader::ImageAtomicSize::S32:
1270 return Type::Int;
1271 default:
1272 UNIMPLEMENTED_MSG("Unimplemented image size={}", static_cast<u32>(size));
1273 return Type::Uint;
1274 }
1275 }();
1276
1277 return {fmt::format("{}({}, {}, {})", opname, GetImage(meta.image),
1278 BuildIntegerCoordinates(operation), Visit(meta.values[0]).As(type)),
1279 type};
1280 }
1281
1177 Expression Assign(Operation operation) { 1282 Expression Assign(Operation operation) {
1178 const Node& dest = operation[0]; 1283 const Node& dest = operation[0];
1179 const Node& src = operation[1]; 1284 const Node& src = operation[1];
@@ -1199,6 +1304,11 @@ private:
1199 target = { 1304 target = {
1200 fmt::format("{}[{} >> 2]", GetLocalMemory(), Visit(lmem->GetAddress()).AsUint()), 1305 fmt::format("{}[{} >> 2]", GetLocalMemory(), Visit(lmem->GetAddress()).AsUint()),
1201 Type::Uint}; 1306 Type::Uint};
1307 } else if (const auto smem = std::get_if<SmemNode>(&*dest)) {
1308 ASSERT(stage == ProgramType::Compute);
1309 target = {
1310 fmt::format("{}[{} >> 2]", GetSharedMemory(), Visit(smem->GetAddress()).AsUint()),
1311 Type::Uint};
1202 } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) { 1312 } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) {
1203 const std::string real = Visit(gmem->GetRealAddress()).AsUint(); 1313 const std::string real = Visit(gmem->GetRealAddress()).AsUint();
1204 const std::string base = Visit(gmem->GetBaseAddress()).AsUint(); 1314 const std::string base = Visit(gmem->GetBaseAddress()).AsUint();
@@ -1692,36 +1802,37 @@ private:
1692 } 1802 }
1693 1803
1694 Expression ImageStore(Operation operation) { 1804 Expression ImageStore(Operation operation) {
1695 constexpr std::array constructors{"int(", "ivec2(", "ivec3(", "ivec4("};
1696 const auto meta{std::get<MetaImage>(operation.GetMeta())}; 1805 const auto meta{std::get<MetaImage>(operation.GetMeta())};
1806 code.AddLine("imageStore({}, {}, {});", GetImage(meta.image),
1807 BuildIntegerCoordinates(operation), BuildImageValues(operation));
1808 return {};
1809 }
1697 1810
1698 std::string expr = "imageStore("; 1811 Expression AtomicImageAdd(Operation operation) {
1699 expr += GetImage(meta.image); 1812 return AtomicImage(operation, "imageAtomicAdd");
1700 expr += ", "; 1813 }
1701 1814
1702 const std::size_t coords_count{operation.GetOperandsCount()}; 1815 Expression AtomicImageMin(Operation operation) {
1703 expr += constructors.at(coords_count - 1); 1816 return AtomicImage(operation, "imageAtomicMin");
1704 for (std::size_t i = 0; i < coords_count; ++i) { 1817 }
1705 expr += VisitOperand(operation, i).AsInt();
1706 if (i + 1 < coords_count) {
1707 expr += ", ";
1708 }
1709 }
1710 expr += "), ";
1711 1818
1712 const std::size_t values_count{meta.values.size()}; 1819 Expression AtomicImageMax(Operation operation) {
1713 UNIMPLEMENTED_IF(values_count != 4); 1820 return AtomicImage(operation, "imageAtomicMax");
1714 expr += "vec4("; 1821 }
1715 for (std::size_t i = 0; i < values_count; ++i) { 1822 Expression AtomicImageAnd(Operation operation) {
1716 expr += Visit(meta.values.at(i)).AsFloat(); 1823 return AtomicImage(operation, "imageAtomicAnd");
1717 if (i + 1 < values_count) { 1824 }
1718 expr += ", ";
1719 }
1720 }
1721 expr += "));";
1722 1825
1723 code.AddLine(expr); 1826 Expression AtomicImageOr(Operation operation) {
1724 return {}; 1827 return AtomicImage(operation, "imageAtomicOr");
1828 }
1829
1830 Expression AtomicImageXor(Operation operation) {
1831 return AtomicImage(operation, "imageAtomicXor");
1832 }
1833
1834 Expression AtomicImageExchange(Operation operation) {
1835 return AtomicImage(operation, "imageAtomicExchange");
1725 } 1836 }
1726 1837
1727 Expression Branch(Operation operation) { 1838 Expression Branch(Operation operation) {
@@ -1846,8 +1957,7 @@ private:
1846 Expression BallotThread(Operation operation) { 1957 Expression BallotThread(Operation operation) {
1847 const std::string value = VisitOperand(operation, 0).AsBool(); 1958 const std::string value = VisitOperand(operation, 0).AsBool();
1848 if (!device.HasWarpIntrinsics()) { 1959 if (!device.HasWarpIntrinsics()) {
1849 LOG_ERROR(Render_OpenGL, 1960 LOG_ERROR(Render_OpenGL, "Nvidia vote intrinsics are required by this shader");
1850 "Nvidia warp intrinsics are not available and its required by a shader");
1851 // Stub on non-Nvidia devices by simulating all threads voting the same as the active 1961 // Stub on non-Nvidia devices by simulating all threads voting the same as the active
1852 // one. 1962 // one.
1853 return {fmt::format("({} ? 0xFFFFFFFFU : 0U)", value), Type::Uint}; 1963 return {fmt::format("({} ? 0xFFFFFFFFU : 0U)", value), Type::Uint};
@@ -1858,8 +1968,7 @@ private:
1858 Expression Vote(Operation operation, const char* func) { 1968 Expression Vote(Operation operation, const char* func) {
1859 const std::string value = VisitOperand(operation, 0).AsBool(); 1969 const std::string value = VisitOperand(operation, 0).AsBool();
1860 if (!device.HasWarpIntrinsics()) { 1970 if (!device.HasWarpIntrinsics()) {
1861 LOG_ERROR(Render_OpenGL, 1971 LOG_ERROR(Render_OpenGL, "Nvidia vote intrinsics are required by this shader");
1862 "Nvidia vote intrinsics are not available and its required by a shader");
1863 // Stub with a warp size of one. 1972 // Stub with a warp size of one.
1864 return {value, Type::Bool}; 1973 return {value, Type::Bool};
1865 } 1974 }
@@ -1876,15 +1985,54 @@ private:
1876 1985
1877 Expression VoteEqual(Operation operation) { 1986 Expression VoteEqual(Operation operation) {
1878 if (!device.HasWarpIntrinsics()) { 1987 if (!device.HasWarpIntrinsics()) {
1879 LOG_ERROR(Render_OpenGL, 1988 LOG_ERROR(Render_OpenGL, "Nvidia vote intrinsics are required by this shader");
1880 "Nvidia vote intrinsics are not available and its required by a shader"); 1989 // We must return true here since a stub for a theoretical warp size of 1.
1881 // We must return true here since a stub for a theoretical warp size of 1 will always 1990 // This will always return an equal result across all votes.
1882 // return an equal result for all its votes.
1883 return {"true", Type::Bool}; 1991 return {"true", Type::Bool};
1884 } 1992 }
1885 return Vote(operation, "allThreadsEqualNV"); 1993 return Vote(operation, "allThreadsEqualNV");
1886 } 1994 }
1887 1995
1996 template <const std::string_view& func>
1997 Expression Shuffle(Operation operation) {
1998 const std::string value = VisitOperand(operation, 0).AsFloat();
1999 if (!device.HasWarpIntrinsics()) {
2000 LOG_ERROR(Render_OpenGL, "Nvidia shuffle intrinsics are required by this shader");
2001 // On a "single-thread" device we are either on the same thread or out of bounds. Both
2002 // cases return the passed value.
2003 return {value, Type::Float};
2004 }
2005
2006 const std::string index = VisitOperand(operation, 1).AsUint();
2007 const std::string width = VisitOperand(operation, 2).AsUint();
2008 return {fmt::format("{}({}, {}, {})", func, value, index, width), Type::Float};
2009 }
2010
2011 template <const std::string_view& func>
2012 Expression InRangeShuffle(Operation operation) {
2013 const std::string index = VisitOperand(operation, 0).AsUint();
2014 const std::string width = VisitOperand(operation, 1).AsUint();
2015 if (!device.HasWarpIntrinsics()) {
2016 // On a "single-thread" device we are only in bounds when the requested index is 0.
2017 return {fmt::format("({} == 0U)", index), Type::Bool};
2018 }
2019
2020 const std::string in_range = code.GenerateTemporary();
2021 code.AddLine("bool {};", in_range);
2022 code.AddLine("{}(0U, {}, {}, {});", func, index, width, in_range);
2023 return {in_range, Type::Bool};
2024 }
2025
2026 struct Func final {
2027 Func() = delete;
2028 ~Func() = delete;
2029
2030 static constexpr std::string_view ShuffleIndexed = "shuffleNV";
2031 static constexpr std::string_view ShuffleUp = "shuffleUpNV";
2032 static constexpr std::string_view ShuffleDown = "shuffleDownNV";
2033 static constexpr std::string_view ShuffleButterfly = "shuffleXorNV";
2034 };
2035
1888 static constexpr std::array operation_decompilers = { 2036 static constexpr std::array operation_decompilers = {
1889 &GLSLDecompiler::Assign, 2037 &GLSLDecompiler::Assign,
1890 2038
@@ -2017,6 +2165,13 @@ private:
2017 &GLSLDecompiler::TexelFetch, 2165 &GLSLDecompiler::TexelFetch,
2018 2166
2019 &GLSLDecompiler::ImageStore, 2167 &GLSLDecompiler::ImageStore,
2168 &GLSLDecompiler::AtomicImageAdd,
2169 &GLSLDecompiler::AtomicImageMin,
2170 &GLSLDecompiler::AtomicImageMax,
2171 &GLSLDecompiler::AtomicImageAnd,
2172 &GLSLDecompiler::AtomicImageOr,
2173 &GLSLDecompiler::AtomicImageXor,
2174 &GLSLDecompiler::AtomicImageExchange,
2020 2175
2021 &GLSLDecompiler::Branch, 2176 &GLSLDecompiler::Branch,
2022 &GLSLDecompiler::BranchIndirect, 2177 &GLSLDecompiler::BranchIndirect,
@@ -2040,6 +2195,16 @@ private:
2040 &GLSLDecompiler::VoteAll, 2195 &GLSLDecompiler::VoteAll,
2041 &GLSLDecompiler::VoteAny, 2196 &GLSLDecompiler::VoteAny,
2042 &GLSLDecompiler::VoteEqual, 2197 &GLSLDecompiler::VoteEqual,
2198
2199 &GLSLDecompiler::Shuffle<Func::ShuffleIndexed>,
2200 &GLSLDecompiler::Shuffle<Func::ShuffleUp>,
2201 &GLSLDecompiler::Shuffle<Func::ShuffleDown>,
2202 &GLSLDecompiler::Shuffle<Func::ShuffleButterfly>,
2203
2204 &GLSLDecompiler::InRangeShuffle<Func::ShuffleIndexed>,
2205 &GLSLDecompiler::InRangeShuffle<Func::ShuffleUp>,
2206 &GLSLDecompiler::InRangeShuffle<Func::ShuffleDown>,
2207 &GLSLDecompiler::InRangeShuffle<Func::ShuffleButterfly>,
2043 }; 2208 };
2044 static_assert(operation_decompilers.size() == static_cast<std::size_t>(OperationCode::Amount)); 2209 static_assert(operation_decompilers.size() == static_cast<std::size_t>(OperationCode::Amount));
2045 2210
@@ -2080,6 +2245,10 @@ private:
2080 return "lmem_" + suffix; 2245 return "lmem_" + suffix;
2081 } 2246 }
2082 2247
2248 std::string GetSharedMemory() const {
2249 return fmt::format("smem_{}", suffix);
2250 }
2251
2083 std::string GetInternalFlag(InternalFlag flag) const { 2252 std::string GetInternalFlag(InternalFlag flag) const {
2084 constexpr std::array InternalFlagNames = {"zero_flag", "sign_flag", "carry_flag", 2253 constexpr std::array InternalFlagNames = {"zero_flag", "sign_flag", "carry_flag",
2085 "overflow_flag"}; 2254 "overflow_flag"};
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index 969fe9ced..f141c4e3b 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -341,13 +341,22 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn
341 u64 index{}; 341 u64 index{};
342 u32 type{}; 342 u32 type{};
343 u8 is_bindless{}; 343 u8 is_bindless{};
344 u8 is_written{};
345 u8 is_read{};
346 u8 is_size_known{};
347 u32 size{};
344 if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) || 348 if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) ||
345 !LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless)) { 349 !LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless) ||
350 !LoadObjectFromPrecompiled(is_written) || !LoadObjectFromPrecompiled(is_read) ||
351 !LoadObjectFromPrecompiled(is_size_known) || !LoadObjectFromPrecompiled(size)) {
346 return {}; 352 return {};
347 } 353 }
348 entry.entries.images.emplace_back( 354 entry.entries.images.emplace_back(
349 static_cast<std::size_t>(offset), static_cast<std::size_t>(index), 355 static_cast<std::size_t>(offset), static_cast<std::size_t>(index),
350 static_cast<Tegra::Shader::ImageType>(type), is_bindless != 0); 356 static_cast<Tegra::Shader::ImageType>(type), is_bindless != 0, is_written != 0,
357 is_read != 0,
358 is_size_known ? std::make_optional(static_cast<Tegra::Shader::ImageAtomicSize>(size))
359 : std::nullopt);
351 } 360 }
352 361
353 u32 global_memory_count{}; 362 u32 global_memory_count{};
@@ -426,10 +435,14 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std:
426 return false; 435 return false;
427 } 436 }
428 for (const auto& image : entries.images) { 437 for (const auto& image : entries.images) {
438 const u32 size = image.IsSizeKnown() ? static_cast<u32>(image.GetSize()) : 0U;
429 if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) || 439 if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) ||
430 !SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) || 440 !SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) ||
431 !SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) || 441 !SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) ||
432 !SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0))) { 442 !SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0)) ||
443 !SaveObjectToPrecompiled(static_cast<u8>(image.IsWritten() ? 1 : 0)) ||
444 !SaveObjectToPrecompiled(static_cast<u8>(image.IsRead() ? 1 : 0)) ||
445 !SaveObjectToPrecompiled(image.IsSizeKnown()) || !SaveObjectToPrecompiled(size)) {
433 return false; 446 return false;
434 } 447 }
435 } 448 }
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index f4777d0b0..bf86b5a0b 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -16,7 +16,6 @@ namespace OpenGL {
16using Maxwell = Tegra::Engines::Maxwell3D::Regs; 16using Maxwell = Tegra::Engines::Maxwell3D::Regs;
17 17
18OpenGLState OpenGLState::cur_state; 18OpenGLState OpenGLState::cur_state;
19bool OpenGLState::s_rgb_used;
20 19
21namespace { 20namespace {
22 21
@@ -34,6 +33,25 @@ bool UpdateTie(T1 current_value, const T2 new_value) {
34 return changed; 33 return changed;
35} 34}
36 35
36template <typename T>
37std::optional<std::pair<GLuint, GLsizei>> UpdateArray(T& current_values, const T& new_values) {
38 std::optional<std::size_t> first;
39 std::size_t last;
40 for (std::size_t i = 0; i < std::size(current_values); ++i) {
41 if (!UpdateValue(current_values[i], new_values[i])) {
42 continue;
43 }
44 if (!first) {
45 first = i;
46 }
47 last = i;
48 }
49 if (!first) {
50 return std::nullopt;
51 }
52 return std::make_pair(static_cast<GLuint>(*first), static_cast<GLsizei>(last - *first + 1));
53}
54
37void Enable(GLenum cap, bool enable) { 55void Enable(GLenum cap, bool enable) {
38 if (enable) { 56 if (enable) {
39 glEnable(cap); 57 glEnable(cap);
@@ -134,10 +152,6 @@ OpenGLState::OpenGLState() {
134 logic_op.enabled = false; 152 logic_op.enabled = false;
135 logic_op.operation = GL_COPY; 153 logic_op.operation = GL_COPY;
136 154
137 for (auto& texture_unit : texture_units) {
138 texture_unit.Reset();
139 }
140
141 draw.read_framebuffer = 0; 155 draw.read_framebuffer = 0;
142 draw.draw_framebuffer = 0; 156 draw.draw_framebuffer = 0;
143 draw.vertex_array = 0; 157 draw.vertex_array = 0;
@@ -267,8 +281,6 @@ void OpenGLState::ApplySRgb() const {
267 return; 281 return;
268 cur_state.framebuffer_srgb.enabled = framebuffer_srgb.enabled; 282 cur_state.framebuffer_srgb.enabled = framebuffer_srgb.enabled;
269 if (framebuffer_srgb.enabled) { 283 if (framebuffer_srgb.enabled) {
270 // Track if sRGB is used
271 s_rgb_used = true;
272 glEnable(GL_FRAMEBUFFER_SRGB); 284 glEnable(GL_FRAMEBUFFER_SRGB);
273 } else { 285 } else {
274 glDisable(GL_FRAMEBUFFER_SRGB); 286 glDisable(GL_FRAMEBUFFER_SRGB);
@@ -496,52 +508,20 @@ void OpenGLState::ApplyAlphaTest() const {
496} 508}
497 509
498void OpenGLState::ApplyTextures() const { 510void OpenGLState::ApplyTextures() const {
499 bool has_delta{}; 511 if (const auto update = UpdateArray(cur_state.textures, textures)) {
500 std::size_t first{}; 512 glBindTextures(update->first, update->second, textures.data() + update->first);
501 std::size_t last{};
502 std::array<GLuint, Maxwell::NumTextureSamplers> textures;
503
504 for (std::size_t i = 0; i < std::size(texture_units); ++i) {
505 const auto& texture_unit = texture_units[i];
506 auto& cur_state_texture_unit = cur_state.texture_units[i];
507 textures[i] = texture_unit.texture;
508 if (cur_state_texture_unit.texture == textures[i]) {
509 continue;
510 }
511 cur_state_texture_unit.texture = textures[i];
512 if (!has_delta) {
513 first = i;
514 has_delta = true;
515 }
516 last = i;
517 }
518 if (has_delta) {
519 glBindTextures(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
520 textures.data() + first);
521 } 513 }
522} 514}
523 515
524void OpenGLState::ApplySamplers() const { 516void OpenGLState::ApplySamplers() const {
525 bool has_delta{}; 517 if (const auto update = UpdateArray(cur_state.samplers, samplers)) {
526 std::size_t first{}; 518 glBindSamplers(update->first, update->second, samplers.data() + update->first);
527 std::size_t last{};
528 std::array<GLuint, Maxwell::NumTextureSamplers> samplers;
529
530 for (std::size_t i = 0; i < std::size(samplers); ++i) {
531 samplers[i] = texture_units[i].sampler;
532 if (cur_state.texture_units[i].sampler == texture_units[i].sampler) {
533 continue;
534 }
535 cur_state.texture_units[i].sampler = texture_units[i].sampler;
536 if (!has_delta) {
537 first = i;
538 has_delta = true;
539 }
540 last = i;
541 } 519 }
542 if (has_delta) { 520}
543 glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1), 521
544 samplers.data() + first); 522void OpenGLState::ApplyImages() const {
523 if (const auto update = UpdateArray(cur_state.images, images)) {
524 glBindImageTextures(update->first, update->second, images.data() + update->first);
545 } 525 }
546} 526}
547 527
@@ -576,6 +556,7 @@ void OpenGLState::Apply() {
576 ApplyLogicOp(); 556 ApplyLogicOp();
577 ApplyTextures(); 557 ApplyTextures();
578 ApplySamplers(); 558 ApplySamplers();
559 ApplyImages();
579 if (dirty.polygon_offset) { 560 if (dirty.polygon_offset) {
580 ApplyPolygonOffset(); 561 ApplyPolygonOffset();
581 dirty.polygon_offset = false; 562 dirty.polygon_offset = false;
@@ -606,18 +587,18 @@ void OpenGLState::EmulateViewportWithScissor() {
606} 587}
607 588
608OpenGLState& OpenGLState::UnbindTexture(GLuint handle) { 589OpenGLState& OpenGLState::UnbindTexture(GLuint handle) {
609 for (auto& unit : texture_units) { 590 for (auto& texture : textures) {
610 if (unit.texture == handle) { 591 if (texture == handle) {
611 unit.Unbind(); 592 texture = 0;
612 } 593 }
613 } 594 }
614 return *this; 595 return *this;
615} 596}
616 597
617OpenGLState& OpenGLState::ResetSampler(GLuint handle) { 598OpenGLState& OpenGLState::ResetSampler(GLuint handle) {
618 for (auto& unit : texture_units) { 599 for (auto& sampler : samplers) {
619 if (unit.sampler == handle) { 600 if (sampler == handle) {
620 unit.sampler = 0; 601 sampler = 0;
621 } 602 }
622 } 603 }
623 return *this; 604 return *this;
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index fdf9a8a12..c358d3b38 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -118,21 +118,9 @@ public:
118 GLenum operation; 118 GLenum operation;
119 } logic_op; 119 } logic_op;
120 120
121 // 3 texture units - one for each that is used in PICA fragment shader emulation 121 std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> textures{};
122 struct TextureUnit { 122 std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers{};
123 GLuint texture; // GL_TEXTURE_BINDING_2D 123 std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumImages> images{};
124 GLuint sampler; // GL_SAMPLER_BINDING
125
126 void Unbind() {
127 texture = 0;
128 }
129
130 void Reset() {
131 Unbind();
132 sampler = 0;
133 }
134 };
135 std::array<TextureUnit, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_units;
136 124
137 struct { 125 struct {
138 GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING 126 GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING
@@ -187,14 +175,6 @@ public:
187 return cur_state; 175 return cur_state;
188 } 176 }
189 177
190 static bool GetsRGBUsed() {
191 return s_rgb_used;
192 }
193
194 static void ClearsRGBUsed() {
195 s_rgb_used = false;
196 }
197
198 void SetDefaultViewports(); 178 void SetDefaultViewports();
199 /// Apply this state as the current OpenGL state 179 /// Apply this state as the current OpenGL state
200 void Apply(); 180 void Apply();
@@ -220,6 +200,7 @@ public:
220 void ApplyLogicOp() const; 200 void ApplyLogicOp() const;
221 void ApplyTextures() const; 201 void ApplyTextures() const;
222 void ApplySamplers() const; 202 void ApplySamplers() const;
203 void ApplyImages() const;
223 void ApplyDepthClamp() const; 204 void ApplyDepthClamp() const;
224 void ApplyPolygonOffset() const; 205 void ApplyPolygonOffset() const;
225 void ApplyAlphaTest() const; 206 void ApplyAlphaTest() const;
@@ -264,8 +245,6 @@ public:
264private: 245private:
265 static OpenGLState cur_state; 246 static OpenGLState cur_state;
266 247
267 // Workaround for sRGB problems caused by QT not supporting srgb output
268 static bool s_rgb_used;
269 struct { 248 struct {
270 bool blend_state; 249 bool blend_state;
271 bool stencil_state; 250 bool stencil_state;
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 21324488a..8e13ab38b 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -78,6 +78,17 @@ public:
78 /// Attaches this texture view to the current bound GL_DRAW_FRAMEBUFFER 78 /// Attaches this texture view to the current bound GL_DRAW_FRAMEBUFFER
79 void Attach(GLenum attachment, GLenum target) const; 79 void Attach(GLenum attachment, GLenum target) const;
80 80
81 void ApplySwizzle(Tegra::Texture::SwizzleSource x_source,
82 Tegra::Texture::SwizzleSource y_source,
83 Tegra::Texture::SwizzleSource z_source,
84 Tegra::Texture::SwizzleSource w_source);
85
86 void DecorateViewName(GPUVAddr gpu_addr, std::string prefix);
87
88 void MarkAsModified(u64 tick) {
89 surface.MarkAsModified(true, tick);
90 }
91
81 GLuint GetTexture() const { 92 GLuint GetTexture() const {
82 if (is_proxy) { 93 if (is_proxy) {
83 return surface.GetTexture(); 94 return surface.GetTexture();
@@ -89,13 +100,6 @@ public:
89 return surface.GetSurfaceParams(); 100 return surface.GetSurfaceParams();
90 } 101 }
91 102
92 void ApplySwizzle(Tegra::Texture::SwizzleSource x_source,
93 Tegra::Texture::SwizzleSource y_source,
94 Tegra::Texture::SwizzleSource z_source,
95 Tegra::Texture::SwizzleSource w_source);
96
97 void DecorateViewName(GPUVAddr gpu_addr, std::string prefix);
98
99private: 103private:
100 u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source, 104 u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source,
101 Tegra::Texture::SwizzleSource y_source, 105 Tegra::Texture::SwizzleSource y_source,
@@ -111,8 +115,8 @@ private:
111 GLenum target{}; 115 GLenum target{};
112 116
113 OGLTextureView texture_view; 117 OGLTextureView texture_view;
114 u32 swizzle; 118 u32 swizzle{};
115 bool is_proxy; 119 bool is_proxy{};
116}; 120};
117 121
118class TextureCacheOpenGL final : public TextureCacheBase { 122class TextureCacheOpenGL final : public TextureCacheBase {
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index af9684839..1e6ef66ab 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -264,7 +264,6 @@ void RendererOpenGL::CreateRasterizer() {
264 if (rasterizer) { 264 if (rasterizer) {
265 return; 265 return;
266 } 266 }
267 OpenGLState::ClearsRGBUsed();
268 rasterizer = std::make_unique<RasterizerOpenGL>(system, emu_window, screen_info); 267 rasterizer = std::make_unique<RasterizerOpenGL>(system, emu_window, screen_info);
269} 268}
270 269
@@ -342,21 +341,17 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
342 ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v), 341 ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v),
343 }}; 342 }};
344 343
345 state.texture_units[0].texture = screen_info.display_texture; 344 state.textures[0] = screen_info.display_texture;
346 // Workaround brigthness problems in SMO by enabling sRGB in the final output 345 state.framebuffer_srgb.enabled = screen_info.display_srgb;
347 // if it has been used in the frame. Needed because of this bug in QT: QTBUG-50987
348 state.framebuffer_srgb.enabled = OpenGLState::GetsRGBUsed();
349 state.AllDirty(); 346 state.AllDirty();
350 state.Apply(); 347 state.Apply();
351 glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), vertices.data()); 348 glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), vertices.data());
352 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 349 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
353 // Restore default state 350 // Restore default state
354 state.framebuffer_srgb.enabled = false; 351 state.framebuffer_srgb.enabled = false;
355 state.texture_units[0].texture = 0; 352 state.textures[0] = 0;
356 state.AllDirty(); 353 state.AllDirty();
357 state.Apply(); 354 state.Apply();
358 // Clear sRGB state for the next frame
359 OpenGLState::ClearsRGBUsed();
360} 355}
361 356
362/** 357/**
@@ -406,8 +401,8 @@ void RendererOpenGL::CaptureScreenshot() {
406 GLuint renderbuffer; 401 GLuint renderbuffer;
407 glGenRenderbuffers(1, &renderbuffer); 402 glGenRenderbuffers(1, &renderbuffer);
408 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); 403 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
409 glRenderbufferStorage(GL_RENDERBUFFER, state.GetsRGBUsed() ? GL_SRGB8 : GL_RGB8, layout.width, 404 glRenderbufferStorage(GL_RENDERBUFFER, screen_info.display_srgb ? GL_SRGB8 : GL_RGB8,
410 layout.height); 405 layout.width, layout.height);
411 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); 406 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
412 407
413 DrawScreen(layout); 408 DrawScreen(layout);
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 9bd086368..cf26628ca 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -38,7 +38,8 @@ struct TextureInfo {
38 38
39/// Structure used for storing information about the display target for the Switch screen 39/// Structure used for storing information about the display target for the Switch screen
40struct ScreenInfo { 40struct ScreenInfo {
41 GLuint display_texture; 41 GLuint display_texture{};
42 bool display_srgb{};
42 const Common::Rectangle<float> display_texcoords{0.0f, 0.0f, 1.0f, 1.0f}; 43 const Common::Rectangle<float> display_texcoords{0.0f, 0.0f, 1.0f, 1.0f};
43 TextureInfo texture; 44 TextureInfo texture;
44}; 45};
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp
index 3b966ddc3..897cbb4e8 100644
--- a/src/video_core/renderer_vulkan/vk_device.cpp
+++ b/src/video_core/renderer_vulkan/vk_device.cpp
@@ -2,9 +2,10 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <bitset>
6#include <optional> 6#include <optional>
7#include <set> 7#include <set>
8#include <string_view>
8#include <vector> 9#include <vector>
9#include "common/assert.h" 10#include "common/assert.h"
10#include "video_core/renderer_vulkan/declarations.h" 11#include "video_core/renderer_vulkan/declarations.h"
@@ -12,13 +13,32 @@
12 13
13namespace Vulkan { 14namespace Vulkan {
14 15
16namespace {
17
18template <typename T>
19void SetNext(void**& next, T& data) {
20 *next = &data;
21 next = &data.pNext;
22}
23
24template <typename T>
25T GetFeatures(vk::PhysicalDevice physical, vk::DispatchLoaderDynamic dldi) {
26 vk::PhysicalDeviceFeatures2 features;
27 T extension_features;
28 features.pNext = &extension_features;
29 physical.getFeatures2(&features, dldi);
30 return extension_features;
31}
32
33} // Anonymous namespace
34
15namespace Alternatives { 35namespace Alternatives {
16 36
17constexpr std::array<vk::Format, 3> Depth24UnormS8Uint = { 37constexpr std::array Depth24UnormS8Uint = {vk::Format::eD32SfloatS8Uint,
18 vk::Format::eD32SfloatS8Uint, vk::Format::eD16UnormS8Uint, {}}; 38 vk::Format::eD16UnormS8Uint, vk::Format{}};
19constexpr std::array<vk::Format, 3> Depth16UnormS8Uint = { 39constexpr std::array Depth16UnormS8Uint = {vk::Format::eD24UnormS8Uint,
20 vk::Format::eD24UnormS8Uint, vk::Format::eD32SfloatS8Uint, {}}; 40 vk::Format::eD32SfloatS8Uint, vk::Format{}};
21constexpr std::array<vk::Format, 2> Astc = {vk::Format::eA8B8G8R8UnormPack32, {}}; 41constexpr std::array Astc = {vk::Format::eA8B8G8R8UnormPack32, vk::Format{}};
22 42
23} // namespace Alternatives 43} // namespace Alternatives
24 44
@@ -58,16 +78,53 @@ VKDevice::VKDevice(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice phy
58VKDevice::~VKDevice() = default; 78VKDevice::~VKDevice() = default;
59 79
60bool VKDevice::Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instance) { 80bool VKDevice::Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instance) {
61 vk::PhysicalDeviceFeatures device_features;
62 device_features.vertexPipelineStoresAndAtomics = true;
63 device_features.independentBlend = true;
64 device_features.textureCompressionASTC_LDR = is_optimal_astc_supported;
65
66 const auto queue_cis = GetDeviceQueueCreateInfos(); 81 const auto queue_cis = GetDeviceQueueCreateInfos();
67 const std::vector<const char*> extensions = LoadExtensions(dldi); 82 const std::vector extensions = LoadExtensions(dldi);
68 const vk::DeviceCreateInfo device_ci({}, static_cast<u32>(queue_cis.size()), queue_cis.data(), 83
69 0, nullptr, static_cast<u32>(extensions.size()), 84 vk::PhysicalDeviceFeatures2 features2;
70 extensions.data(), &device_features); 85 void** next = &features2.pNext;
86 auto& features = features2.features;
87 features.vertexPipelineStoresAndAtomics = true;
88 features.independentBlend = true;
89 features.depthClamp = true;
90 features.samplerAnisotropy = true;
91 features.largePoints = true;
92 features.textureCompressionASTC_LDR = is_optimal_astc_supported;
93
94 vk::PhysicalDeviceVertexAttributeDivisorFeaturesEXT vertex_divisor;
95 vertex_divisor.vertexAttributeInstanceRateDivisor = true;
96 vertex_divisor.vertexAttributeInstanceRateZeroDivisor = true;
97 SetNext(next, vertex_divisor);
98
99 vk::PhysicalDeviceFloat16Int8FeaturesKHR float16_int8;
100 if (is_float16_supported) {
101 float16_int8.shaderFloat16 = true;
102 SetNext(next, float16_int8);
103 } else {
104 LOG_INFO(Render_Vulkan, "Device doesn't support float16 natively");
105 }
106
107 vk::PhysicalDeviceUniformBufferStandardLayoutFeaturesKHR std430_layout;
108 if (khr_uniform_buffer_standard_layout) {
109 std430_layout.uniformBufferStandardLayout = true;
110 SetNext(next, std430_layout);
111 } else {
112 LOG_INFO(Render_Vulkan, "Device doesn't support packed UBOs");
113 }
114
115 vk::PhysicalDeviceIndexTypeUint8FeaturesEXT index_type_uint8;
116 if (ext_index_type_uint8) {
117 index_type_uint8.indexTypeUint8 = true;
118 SetNext(next, index_type_uint8);
119 } else {
120 LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes");
121 }
122
123 vk::DeviceCreateInfo device_ci({}, static_cast<u32>(queue_cis.size()), queue_cis.data(), 0,
124 nullptr, static_cast<u32>(extensions.size()), extensions.data(),
125 nullptr);
126 device_ci.pNext = &features2;
127
71 vk::Device dummy_logical; 128 vk::Device dummy_logical;
72 if (physical.createDevice(&device_ci, nullptr, &dummy_logical, dldi) != vk::Result::eSuccess) { 129 if (physical.createDevice(&device_ci, nullptr, &dummy_logical, dldi) != vk::Result::eSuccess) {
73 LOG_CRITICAL(Render_Vulkan, "Logical device failed to be created!"); 130 LOG_CRITICAL(Render_Vulkan, "Logical device failed to be created!");
@@ -78,6 +135,17 @@ bool VKDevice::Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instan
78 logical = UniqueDevice( 135 logical = UniqueDevice(
79 dummy_logical, vk::ObjectDestroy<vk::NoParent, vk::DispatchLoaderDynamic>(nullptr, dld)); 136 dummy_logical, vk::ObjectDestroy<vk::NoParent, vk::DispatchLoaderDynamic>(nullptr, dld));
80 137
138 if (khr_driver_properties) {
139 vk::PhysicalDeviceDriverPropertiesKHR driver;
140 vk::PhysicalDeviceProperties2 properties;
141 properties.pNext = &driver;
142 physical.getProperties2(&properties, dld);
143 driver_id = driver.driverID;
144 LOG_INFO(Render_Vulkan, "Driver: {} {}", driver.driverName, driver.driverInfo);
145 } else {
146 LOG_INFO(Render_Vulkan, "Driver: Unknown");
147 }
148
81 graphics_queue = logical->getQueue(graphics_family, 0, dld); 149 graphics_queue = logical->getQueue(graphics_family, 0, dld);
82 present_queue = logical->getQueue(present_family, 0, dld); 150 present_queue = logical->getQueue(present_family, 0, dld);
83 return true; 151 return true;
@@ -92,20 +160,19 @@ vk::Format VKDevice::GetSupportedFormat(vk::Format wanted_format,
92 // The wanted format is not supported by hardware, search for alternatives 160 // The wanted format is not supported by hardware, search for alternatives
93 const vk::Format* alternatives = GetFormatAlternatives(wanted_format); 161 const vk::Format* alternatives = GetFormatAlternatives(wanted_format);
94 if (alternatives == nullptr) { 162 if (alternatives == nullptr) {
95 LOG_CRITICAL(Render_Vulkan, 163 UNREACHABLE_MSG("Format={} with usage={} and type={} has no defined alternatives and host "
96 "Format={} with usage={} and type={} has no defined alternatives and host " 164 "hardware does not support it",
97 "hardware does not support it", 165 vk::to_string(wanted_format), vk::to_string(wanted_usage),
98 vk::to_string(wanted_format), vk::to_string(wanted_usage), 166 static_cast<u32>(format_type));
99 static_cast<u32>(format_type));
100 UNREACHABLE();
101 return wanted_format; 167 return wanted_format;
102 } 168 }
103 169
104 std::size_t i = 0; 170 std::size_t i = 0;
105 for (vk::Format alternative = alternatives[0]; alternative != vk::Format{}; 171 for (vk::Format alternative = alternatives[0]; alternative != vk::Format{};
106 alternative = alternatives[++i]) { 172 alternative = alternatives[++i]) {
107 if (!IsFormatSupported(alternative, wanted_usage, format_type)) 173 if (!IsFormatSupported(alternative, wanted_usage, format_type)) {
108 continue; 174 continue;
175 }
109 LOG_WARNING(Render_Vulkan, 176 LOG_WARNING(Render_Vulkan,
110 "Emulating format={} with alternative format={} with usage={} and type={}", 177 "Emulating format={} with alternative format={} with usage={} and type={}",
111 static_cast<u32>(wanted_format), static_cast<u32>(alternative), 178 static_cast<u32>(wanted_format), static_cast<u32>(alternative),
@@ -114,12 +181,10 @@ vk::Format VKDevice::GetSupportedFormat(vk::Format wanted_format,
114 } 181 }
115 182
116 // No alternatives found, panic 183 // No alternatives found, panic
117 LOG_CRITICAL(Render_Vulkan, 184 UNREACHABLE_MSG("Format={} with usage={} and type={} is not supported by the host hardware and "
118 "Format={} with usage={} and type={} is not supported by the host hardware and " 185 "doesn't support any of the alternatives",
119 "doesn't support any of the alternatives", 186 static_cast<u32>(wanted_format), static_cast<u32>(wanted_usage),
120 static_cast<u32>(wanted_format), static_cast<u32>(wanted_usage), 187 static_cast<u32>(format_type));
121 static_cast<u32>(format_type));
122 UNREACHABLE();
123 return wanted_format; 188 return wanted_format;
124} 189}
125 190
@@ -132,7 +197,7 @@ bool VKDevice::IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features
132 vk::FormatFeatureFlagBits::eSampledImage | vk::FormatFeatureFlagBits::eBlitSrc | 197 vk::FormatFeatureFlagBits::eSampledImage | vk::FormatFeatureFlagBits::eBlitSrc |
133 vk::FormatFeatureFlagBits::eBlitDst | vk::FormatFeatureFlagBits::eTransferSrc | 198 vk::FormatFeatureFlagBits::eBlitDst | vk::FormatFeatureFlagBits::eTransferSrc |
134 vk::FormatFeatureFlagBits::eTransferDst}; 199 vk::FormatFeatureFlagBits::eTransferDst};
135 constexpr std::array<vk::Format, 9> astc_formats = { 200 constexpr std::array astc_formats = {
136 vk::Format::eAstc4x4UnormBlock, vk::Format::eAstc4x4SrgbBlock, 201 vk::Format::eAstc4x4UnormBlock, vk::Format::eAstc4x4SrgbBlock,
137 vk::Format::eAstc8x8SrgbBlock, vk::Format::eAstc8x6SrgbBlock, 202 vk::Format::eAstc8x8SrgbBlock, vk::Format::eAstc8x6SrgbBlock,
138 vk::Format::eAstc5x4SrgbBlock, vk::Format::eAstc5x5UnormBlock, 203 vk::Format::eAstc5x4SrgbBlock, vk::Format::eAstc5x5UnormBlock,
@@ -151,76 +216,120 @@ bool VKDevice::IsFormatSupported(vk::Format wanted_format, vk::FormatFeatureFlag
151 FormatType format_type) const { 216 FormatType format_type) const {
152 const auto it = format_properties.find(wanted_format); 217 const auto it = format_properties.find(wanted_format);
153 if (it == format_properties.end()) { 218 if (it == format_properties.end()) {
154 LOG_CRITICAL(Render_Vulkan, "Unimplemented format query={}", vk::to_string(wanted_format)); 219 UNIMPLEMENTED_MSG("Unimplemented format query={}", vk::to_string(wanted_format));
155 UNREACHABLE();
156 return true; 220 return true;
157 } 221 }
158 const vk::FormatFeatureFlags supported_usage = GetFormatFeatures(it->second, format_type); 222 const auto supported_usage = GetFormatFeatures(it->second, format_type);
159 return (supported_usage & wanted_usage) == wanted_usage; 223 return (supported_usage & wanted_usage) == wanted_usage;
160} 224}
161 225
162bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical, 226bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical,
163 vk::SurfaceKHR surface) { 227 vk::SurfaceKHR surface) {
164 bool has_swapchain{}; 228 LOG_INFO(Render_Vulkan, "{}", physical.getProperties(dldi).deviceName);
229 bool is_suitable = true;
230
231 constexpr std::array required_extensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME,
232 VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME};
233 std::bitset<required_extensions.size()> available_extensions{};
234
165 for (const auto& prop : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) { 235 for (const auto& prop : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) {
166 has_swapchain |= prop.extensionName == std::string(VK_KHR_SWAPCHAIN_EXTENSION_NAME); 236 for (std::size_t i = 0; i < required_extensions.size(); ++i) {
237 if (available_extensions[i]) {
238 continue;
239 }
240 available_extensions[i] =
241 required_extensions[i] == std::string_view{prop.extensionName};
242 }
167 } 243 }
168 if (!has_swapchain) { 244 if (!available_extensions.all()) {
169 // The device doesn't support creating swapchains. 245 for (std::size_t i = 0; i < required_extensions.size(); ++i) {
170 return false; 246 if (available_extensions[i]) {
247 continue;
248 }
249 LOG_INFO(Render_Vulkan, "Missing required extension: {}", required_extensions[i]);
250 is_suitable = false;
251 }
171 } 252 }
172 253
173 bool has_graphics{}, has_present{}; 254 bool has_graphics{}, has_present{};
174 const auto queue_family_properties = physical.getQueueFamilyProperties(dldi); 255 const auto queue_family_properties = physical.getQueueFamilyProperties(dldi);
175 for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) { 256 for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) {
176 const auto& family = queue_family_properties[i]; 257 const auto& family = queue_family_properties[i];
177 if (family.queueCount == 0) 258 if (family.queueCount == 0) {
178 continue; 259 continue;
179 260 }
180 has_graphics |= 261 has_graphics |=
181 (family.queueFlags & vk::QueueFlagBits::eGraphics) != static_cast<vk::QueueFlagBits>(0); 262 (family.queueFlags & vk::QueueFlagBits::eGraphics) != static_cast<vk::QueueFlagBits>(0);
182 has_present |= physical.getSurfaceSupportKHR(i, surface, dldi) != 0; 263 has_present |= physical.getSurfaceSupportKHR(i, surface, dldi) != 0;
183 } 264 }
184 if (!has_graphics || !has_present) { 265 if (!has_graphics || !has_present) {
185 // The device doesn't have a graphics and present queue. 266 LOG_INFO(Render_Vulkan, "Device lacks a graphics and present queue");
186 return false; 267 is_suitable = false;
187 } 268 }
188 269
189 // TODO(Rodrigo): Check if the device matches all requeriments. 270 // TODO(Rodrigo): Check if the device matches all requeriments.
190 const auto properties{physical.getProperties(dldi)}; 271 const auto properties{physical.getProperties(dldi)};
191 const auto limits{properties.limits}; 272 const auto& limits{properties.limits};
192 if (limits.maxUniformBufferRange < 65536) { 273
193 return false; 274 constexpr u32 required_ubo_size = 65536;
275 if (limits.maxUniformBufferRange < required_ubo_size) {
276 LOG_INFO(Render_Vulkan, "Device UBO size {} is too small, {} is required)",
277 limits.maxUniformBufferRange, required_ubo_size);
278 is_suitable = false;
194 } 279 }
195 280
196 const vk::PhysicalDeviceFeatures features{physical.getFeatures(dldi)}; 281 const auto features{physical.getFeatures(dldi)};
197 if (!features.vertexPipelineStoresAndAtomics || !features.independentBlend) { 282 const std::array feature_report = {
198 return false; 283 std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
284 std::make_pair(features.independentBlend, "independentBlend"),
285 std::make_pair(features.depthClamp, "depthClamp"),
286 std::make_pair(features.samplerAnisotropy, "samplerAnisotropy"),
287 std::make_pair(features.largePoints, "largePoints"),
288 };
289 for (const auto& [supported, name] : feature_report) {
290 if (supported) {
291 continue;
292 }
293 LOG_INFO(Render_Vulkan, "Missing required feature: {}", name);
294 is_suitable = false;
199 } 295 }
200 296
201 // Device is suitable. 297 return is_suitable;
202 return true;
203} 298}
204 299
205std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynamic& dldi) { 300std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynamic& dldi) {
206 std::vector<const char*> extensions; 301 std::vector<const char*> extensions;
207 extensions.reserve(2); 302 extensions.reserve(7);
208 extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); 303 extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
304 extensions.push_back(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
209 305
210 const auto Test = [&](const vk::ExtensionProperties& extension, 306 const auto Test = [&](const vk::ExtensionProperties& extension,
211 std::optional<std::reference_wrapper<bool>> status, const char* name, 307 std::optional<std::reference_wrapper<bool>> status, const char* name,
212 u32 revision) { 308 bool push) {
213 if (extension.extensionName != std::string(name)) { 309 if (extension.extensionName != std::string_view(name)) {
214 return; 310 return;
215 } 311 }
216 extensions.push_back(name); 312 if (push) {
313 extensions.push_back(name);
314 }
217 if (status) { 315 if (status) {
218 status->get() = true; 316 status->get() = true;
219 } 317 }
220 }; 318 };
221 319
320 bool khr_shader_float16_int8{};
222 for (const auto& extension : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) { 321 for (const auto& extension : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) {
223 Test(extension, ext_scalar_block_layout, VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME, 1); 322 Test(extension, khr_uniform_buffer_standard_layout,
323 VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true);
324 Test(extension, ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true);
325 Test(extension, khr_driver_properties, VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, true);
326 Test(extension, khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
327 }
328
329 if (khr_shader_float16_int8) {
330 is_float16_supported =
331 GetFeatures<vk::PhysicalDeviceFloat16Int8FeaturesKHR>(physical, dldi).shaderFloat16;
332 extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME);
224 } 333 }
225 334
226 return extensions; 335 return extensions;
@@ -250,9 +359,10 @@ void VKDevice::SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceK
250} 359}
251 360
252void VKDevice::SetupProperties(const vk::DispatchLoaderDynamic& dldi) { 361void VKDevice::SetupProperties(const vk::DispatchLoaderDynamic& dldi) {
253 const vk::PhysicalDeviceProperties props = physical.getProperties(dldi); 362 const auto props = physical.getProperties(dldi);
254 device_type = props.deviceType; 363 device_type = props.deviceType;
255 uniform_buffer_alignment = static_cast<u64>(props.limits.minUniformBufferOffsetAlignment); 364 uniform_buffer_alignment = static_cast<u64>(props.limits.minUniformBufferOffsetAlignment);
365 storage_buffer_alignment = static_cast<u64>(props.limits.minStorageBufferOffsetAlignment);
256 max_storage_buffer_range = static_cast<u64>(props.limits.maxStorageBufferRange); 366 max_storage_buffer_range = static_cast<u64>(props.limits.maxStorageBufferRange);
257} 367}
258 368
@@ -273,42 +383,53 @@ std::vector<vk::DeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() con
273 return queue_cis; 383 return queue_cis;
274} 384}
275 385
276std::map<vk::Format, vk::FormatProperties> VKDevice::GetFormatProperties( 386std::unordered_map<vk::Format, vk::FormatProperties> VKDevice::GetFormatProperties(
277 const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical) { 387 const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical) {
278 static constexpr std::array formats{vk::Format::eA8B8G8R8UnormPack32, 388 constexpr std::array formats{vk::Format::eA8B8G8R8UnormPack32,
279 vk::Format::eB5G6R5UnormPack16, 389 vk::Format::eA8B8G8R8SnormPack32,
280 vk::Format::eA2B10G10R10UnormPack32, 390 vk::Format::eA8B8G8R8SrgbPack32,
281 vk::Format::eR32G32B32A32Sfloat, 391 vk::Format::eB5G6R5UnormPack16,
282 vk::Format::eR16G16Unorm, 392 vk::Format::eA2B10G10R10UnormPack32,
283 vk::Format::eR16G16Snorm, 393 vk::Format::eR32G32B32A32Sfloat,
284 vk::Format::eR8G8B8A8Srgb, 394 vk::Format::eR16G16B16A16Uint,
285 vk::Format::eR8Unorm, 395 vk::Format::eR16G16Unorm,
286 vk::Format::eB10G11R11UfloatPack32, 396 vk::Format::eR16G16Snorm,
287 vk::Format::eR32Sfloat, 397 vk::Format::eR16G16Sfloat,
288 vk::Format::eR16Sfloat, 398 vk::Format::eR16Unorm,
289 vk::Format::eR16G16B16A16Sfloat, 399 vk::Format::eR8G8B8A8Srgb,
290 vk::Format::eD32Sfloat, 400 vk::Format::eR8G8Unorm,
291 vk::Format::eD16Unorm, 401 vk::Format::eR8G8Snorm,
292 vk::Format::eD16UnormS8Uint, 402 vk::Format::eR8Unorm,
293 vk::Format::eD24UnormS8Uint, 403 vk::Format::eB10G11R11UfloatPack32,
294 vk::Format::eD32SfloatS8Uint, 404 vk::Format::eR32Sfloat,
295 vk::Format::eBc1RgbaUnormBlock, 405 vk::Format::eR16Sfloat,
296 vk::Format::eBc2UnormBlock, 406 vk::Format::eR16G16B16A16Sfloat,
297 vk::Format::eBc3UnormBlock, 407 vk::Format::eB8G8R8A8Unorm,
298 vk::Format::eBc4UnormBlock, 408 vk::Format::eD32Sfloat,
299 vk::Format::eBc5UnormBlock, 409 vk::Format::eD16Unorm,
300 vk::Format::eBc5SnormBlock, 410 vk::Format::eD16UnormS8Uint,
301 vk::Format::eBc7UnormBlock, 411 vk::Format::eD24UnormS8Uint,
302 vk::Format::eAstc4x4UnormBlock, 412 vk::Format::eD32SfloatS8Uint,
303 vk::Format::eAstc4x4SrgbBlock, 413 vk::Format::eBc1RgbaUnormBlock,
304 vk::Format::eAstc8x8SrgbBlock, 414 vk::Format::eBc2UnormBlock,
305 vk::Format::eAstc8x6SrgbBlock, 415 vk::Format::eBc3UnormBlock,
306 vk::Format::eAstc5x4SrgbBlock, 416 vk::Format::eBc4UnormBlock,
307 vk::Format::eAstc5x5UnormBlock, 417 vk::Format::eBc5UnormBlock,
308 vk::Format::eAstc5x5SrgbBlock, 418 vk::Format::eBc5SnormBlock,
309 vk::Format::eAstc10x8UnormBlock, 419 vk::Format::eBc7UnormBlock,
310 vk::Format::eAstc10x8SrgbBlock}; 420 vk::Format::eBc1RgbaSrgbBlock,
311 std::map<vk::Format, vk::FormatProperties> format_properties; 421 vk::Format::eBc3SrgbBlock,
422 vk::Format::eBc7SrgbBlock,
423 vk::Format::eAstc4x4UnormBlock,
424 vk::Format::eAstc4x4SrgbBlock,
425 vk::Format::eAstc8x8SrgbBlock,
426 vk::Format::eAstc8x6SrgbBlock,
427 vk::Format::eAstc5x4SrgbBlock,
428 vk::Format::eAstc5x5UnormBlock,
429 vk::Format::eAstc5x5SrgbBlock,
430 vk::Format::eAstc10x8UnormBlock,
431 vk::Format::eAstc10x8SrgbBlock};
432 std::unordered_map<vk::Format, vk::FormatProperties> format_properties;
312 for (const auto format : formats) { 433 for (const auto format : formats) {
313 format_properties.emplace(format, physical.getFormatProperties(format, dldi)); 434 format_properties.emplace(format, physical.getFormatProperties(format, dldi));
314 } 435 }
diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h
index 537825d8b..010d4c3d6 100644
--- a/src/video_core/renderer_vulkan/vk_device.h
+++ b/src/video_core/renderer_vulkan/vk_device.h
@@ -4,7 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <map> 7#include <unordered_map>
8#include <vector> 8#include <vector>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/renderer_vulkan/declarations.h" 10#include "video_core/renderer_vulkan/declarations.h"
@@ -69,16 +69,26 @@ public:
69 return present_family; 69 return present_family;
70 } 70 }
71 71
72 /// Returns if the device is integrated with the host CPU. 72 /// Returns true if the device is integrated with the host CPU.
73 bool IsIntegrated() const { 73 bool IsIntegrated() const {
74 return device_type == vk::PhysicalDeviceType::eIntegratedGpu; 74 return device_type == vk::PhysicalDeviceType::eIntegratedGpu;
75 } 75 }
76 76
77 /// Returns the driver ID.
78 vk::DriverIdKHR GetDriverID() const {
79 return driver_id;
80 }
81
77 /// Returns uniform buffer alignment requeriment. 82 /// Returns uniform buffer alignment requeriment.
78 u64 GetUniformBufferAlignment() const { 83 u64 GetUniformBufferAlignment() const {
79 return uniform_buffer_alignment; 84 return uniform_buffer_alignment;
80 } 85 }
81 86
87 /// Returns storage alignment requeriment.
88 u64 GetStorageBufferAlignment() const {
89 return storage_buffer_alignment;
90 }
91
82 /// Returns the maximum range for storage buffers. 92 /// Returns the maximum range for storage buffers.
83 u64 GetMaxStorageBufferRange() const { 93 u64 GetMaxStorageBufferRange() const {
84 return max_storage_buffer_range; 94 return max_storage_buffer_range;
@@ -89,9 +99,19 @@ public:
89 return is_optimal_astc_supported; 99 return is_optimal_astc_supported;
90 } 100 }
91 101
102 /// Returns true if the device supports float16 natively
103 bool IsFloat16Supported() const {
104 return is_float16_supported;
105 }
106
92 /// Returns true if the device supports VK_EXT_scalar_block_layout. 107 /// Returns true if the device supports VK_EXT_scalar_block_layout.
93 bool IsExtScalarBlockLayoutSupported() const { 108 bool IsKhrUniformBufferStandardLayoutSupported() const {
94 return ext_scalar_block_layout; 109 return khr_uniform_buffer_standard_layout;
110 }
111
112 /// Returns true if the device supports VK_EXT_index_type_uint8.
113 bool IsExtIndexTypeUint8Supported() const {
114 return ext_index_type_uint8;
95 } 115 }
96 116
97 /// Checks if the physical device is suitable. 117 /// Checks if the physical device is suitable.
@@ -123,22 +143,28 @@ private:
123 FormatType format_type) const; 143 FormatType format_type) const;
124 144
125 /// Returns the device properties for Vulkan formats. 145 /// Returns the device properties for Vulkan formats.
126 static std::map<vk::Format, vk::FormatProperties> GetFormatProperties( 146 static std::unordered_map<vk::Format, vk::FormatProperties> GetFormatProperties(
127 const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical); 147 const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical);
128 148
129 const vk::PhysicalDevice physical; ///< Physical device. 149 const vk::PhysicalDevice physical; ///< Physical device.
130 vk::DispatchLoaderDynamic dld; ///< Device function pointers. 150 vk::DispatchLoaderDynamic dld; ///< Device function pointers.
131 UniqueDevice logical; ///< Logical device. 151 UniqueDevice logical; ///< Logical device.
132 vk::Queue graphics_queue; ///< Main graphics queue. 152 vk::Queue graphics_queue; ///< Main graphics queue.
133 vk::Queue present_queue; ///< Main present queue. 153 vk::Queue present_queue; ///< Main present queue.
134 u32 graphics_family{}; ///< Main graphics queue family index. 154 u32 graphics_family{}; ///< Main graphics queue family index.
135 u32 present_family{}; ///< Main present queue family index. 155 u32 present_family{}; ///< Main present queue family index.
136 vk::PhysicalDeviceType device_type; ///< Physical device type. 156 vk::PhysicalDeviceType device_type; ///< Physical device type.
137 u64 uniform_buffer_alignment{}; ///< Uniform buffer alignment requeriment. 157 vk::DriverIdKHR driver_id{}; ///< Driver ID.
138 u64 max_storage_buffer_range{}; ///< Max storage buffer size. 158 u64 uniform_buffer_alignment{}; ///< Uniform buffer alignment requeriment.
139 bool is_optimal_astc_supported{}; ///< Support for native ASTC. 159 u64 storage_buffer_alignment{}; ///< Storage buffer alignment requeriment.
140 bool ext_scalar_block_layout{}; ///< Support for VK_EXT_scalar_block_layout. 160 u64 max_storage_buffer_range{}; ///< Max storage buffer size.
141 std::map<vk::Format, vk::FormatProperties> format_properties; ///< Format properties dictionary. 161 bool is_optimal_astc_supported{}; ///< Support for native ASTC.
162 bool is_float16_supported{}; ///< Support for float16 arithmetics.
163 bool khr_uniform_buffer_standard_layout{}; ///< Support for std430 on UBOs.
164 bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8.
165 bool khr_driver_properties{}; ///< Support for VK_KHR_driver_properties.
166 std::unordered_map<vk::Format, vk::FormatProperties>
167 format_properties; ///< Format properties dictionary.
142}; 168};
143 169
144} // namespace Vulkan 170} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index a35b45c9c..f7fbbb6e4 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -370,8 +370,8 @@ private:
370 u32 binding = const_buffers_base_binding; 370 u32 binding = const_buffers_base_binding;
371 for (const auto& entry : ir.GetConstantBuffers()) { 371 for (const auto& entry : ir.GetConstantBuffers()) {
372 const auto [index, size] = entry; 372 const auto [index, size] = entry;
373 const Id type = 373 const Id type = device.IsKhrUniformBufferStandardLayoutSupported() ? t_cbuf_scalar_ubo
374 device.IsExtScalarBlockLayoutSupported() ? t_cbuf_scalar_ubo : t_cbuf_std140_ubo; 374 : t_cbuf_std140_ubo;
375 const Id id = OpVariable(type, spv::StorageClass::Uniform); 375 const Id id = OpVariable(type, spv::StorageClass::Uniform);
376 AddGlobalVariable(Name(id, fmt::format("cbuf_{}", index))); 376 AddGlobalVariable(Name(id, fmt::format("cbuf_{}", index)));
377 377
@@ -565,7 +565,7 @@ private:
565 const Id buffer_id = constant_buffers.at(cbuf->GetIndex()); 565 const Id buffer_id = constant_buffers.at(cbuf->GetIndex());
566 566
567 Id pointer{}; 567 Id pointer{};
568 if (device.IsExtScalarBlockLayoutSupported()) { 568 if (device.IsKhrUniformBufferStandardLayoutSupported()) {
569 const Id buffer_offset = Emit(OpShiftRightLogical( 569 const Id buffer_offset = Emit(OpShiftRightLogical(
570 t_uint, BitcastTo<Type::Uint>(Visit(offset)), Constant(t_uint, 2u))); 570 t_uint, BitcastTo<Type::Uint>(Visit(offset)), Constant(t_uint, 2u)));
571 pointer = Emit( 571 pointer = Emit(
@@ -944,6 +944,41 @@ private:
944 return {}; 944 return {};
945 } 945 }
946 946
947 Id AtomicImageAdd(Operation operation) {
948 UNIMPLEMENTED();
949 return {};
950 }
951
952 Id AtomicImageMin(Operation operation) {
953 UNIMPLEMENTED();
954 return {};
955 }
956
957 Id AtomicImageMax(Operation operation) {
958 UNIMPLEMENTED();
959 return {};
960 }
961
962 Id AtomicImageAnd(Operation operation) {
963 UNIMPLEMENTED();
964 return {};
965 }
966
967 Id AtomicImageOr(Operation operation) {
968 UNIMPLEMENTED();
969 return {};
970 }
971
972 Id AtomicImageXor(Operation operation) {
973 UNIMPLEMENTED();
974 return {};
975 }
976
977 Id AtomicImageExchange(Operation operation) {
978 UNIMPLEMENTED();
979 return {};
980 }
981
947 Id Branch(Operation operation) { 982 Id Branch(Operation operation) {
948 const auto target = std::get_if<ImmediateNode>(&*operation[0]); 983 const auto target = std::get_if<ImmediateNode>(&*operation[0]);
949 UNIMPLEMENTED_IF(!target); 984 UNIMPLEMENTED_IF(!target);
@@ -1092,6 +1127,46 @@ private:
1092 return {}; 1127 return {};
1093 } 1128 }
1094 1129
1130 Id ShuffleIndexed(Operation) {
1131 UNIMPLEMENTED();
1132 return {};
1133 }
1134
1135 Id ShuffleUp(Operation) {
1136 UNIMPLEMENTED();
1137 return {};
1138 }
1139
1140 Id ShuffleDown(Operation) {
1141 UNIMPLEMENTED();
1142 return {};
1143 }
1144
1145 Id ShuffleButterfly(Operation) {
1146 UNIMPLEMENTED();
1147 return {};
1148 }
1149
1150 Id InRangeShuffleIndexed(Operation) {
1151 UNIMPLEMENTED();
1152 return {};
1153 }
1154
1155 Id InRangeShuffleUp(Operation) {
1156 UNIMPLEMENTED();
1157 return {};
1158 }
1159
1160 Id InRangeShuffleDown(Operation) {
1161 UNIMPLEMENTED();
1162 return {};
1163 }
1164
1165 Id InRangeShuffleButterfly(Operation) {
1166 UNIMPLEMENTED();
1167 return {};
1168 }
1169
1095 Id DeclareBuiltIn(spv::BuiltIn builtin, spv::StorageClass storage, Id type, 1170 Id DeclareBuiltIn(spv::BuiltIn builtin, spv::StorageClass storage, Id type,
1096 const std::string& name) { 1171 const std::string& name) {
1097 const Id id = OpVariable(type, storage); 1172 const Id id = OpVariable(type, storage);
@@ -1366,6 +1441,13 @@ private:
1366 &SPIRVDecompiler::TexelFetch, 1441 &SPIRVDecompiler::TexelFetch,
1367 1442
1368 &SPIRVDecompiler::ImageStore, 1443 &SPIRVDecompiler::ImageStore,
1444 &SPIRVDecompiler::AtomicImageAdd,
1445 &SPIRVDecompiler::AtomicImageMin,
1446 &SPIRVDecompiler::AtomicImageMax,
1447 &SPIRVDecompiler::AtomicImageAnd,
1448 &SPIRVDecompiler::AtomicImageOr,
1449 &SPIRVDecompiler::AtomicImageXor,
1450 &SPIRVDecompiler::AtomicImageExchange,
1369 1451
1370 &SPIRVDecompiler::Branch, 1452 &SPIRVDecompiler::Branch,
1371 &SPIRVDecompiler::BranchIndirect, 1453 &SPIRVDecompiler::BranchIndirect,
@@ -1389,6 +1471,16 @@ private:
1389 &SPIRVDecompiler::VoteAll, 1471 &SPIRVDecompiler::VoteAll,
1390 &SPIRVDecompiler::VoteAny, 1472 &SPIRVDecompiler::VoteAny,
1391 &SPIRVDecompiler::VoteEqual, 1473 &SPIRVDecompiler::VoteEqual,
1474
1475 &SPIRVDecompiler::ShuffleIndexed,
1476 &SPIRVDecompiler::ShuffleUp,
1477 &SPIRVDecompiler::ShuffleDown,
1478 &SPIRVDecompiler::ShuffleButterfly,
1479
1480 &SPIRVDecompiler::InRangeShuffleIndexed,
1481 &SPIRVDecompiler::InRangeShuffleUp,
1482 &SPIRVDecompiler::InRangeShuffleDown,
1483 &SPIRVDecompiler::InRangeShuffleButterfly,
1392 }; 1484 };
1393 static_assert(operation_decompilers.size() == static_cast<std::size_t>(OperationCode::Amount)); 1485 static_assert(operation_decompilers.size() == static_cast<std::size_t>(OperationCode::Amount));
1394 1486
diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp
index 77151a24b..d54fb88c9 100644
--- a/src/video_core/shader/decode/image.cpp
+++ b/src/video_core/shader/decode/image.cpp
@@ -44,7 +44,6 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
44 switch (opcode->get().GetId()) { 44 switch (opcode->get().GetId()) {
45 case OpCode::Id::SUST: { 45 case OpCode::Id::SUST: {
46 UNIMPLEMENTED_IF(instr.sust.mode != Tegra::Shader::SurfaceDataMode::P); 46 UNIMPLEMENTED_IF(instr.sust.mode != Tegra::Shader::SurfaceDataMode::P);
47 UNIMPLEMENTED_IF(instr.sust.image_type == Tegra::Shader::ImageType::TextureBuffer);
48 UNIMPLEMENTED_IF(instr.sust.out_of_bounds_store != Tegra::Shader::OutOfBoundsStore::Ignore); 47 UNIMPLEMENTED_IF(instr.sust.out_of_bounds_store != Tegra::Shader::OutOfBoundsStore::Ignore);
49 UNIMPLEMENTED_IF(instr.sust.component_mask_selector != 0xf); // Ensure we have an RGBA store 48 UNIMPLEMENTED_IF(instr.sust.component_mask_selector != 0xf); // Ensure we have an RGBA store
50 49
@@ -61,56 +60,105 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
61 } 60 }
62 61
63 const auto type{instr.sust.image_type}; 62 const auto type{instr.sust.image_type};
64 const auto& image{instr.sust.is_immediate ? GetImage(instr.image, type) 63 auto& image{instr.sust.is_immediate ? GetImage(instr.image, type)
65 : GetBindlessImage(instr.gpr39, type)}; 64 : GetBindlessImage(instr.gpr39, type)};
65 image.MarkWrite();
66
66 MetaImage meta{image, values}; 67 MetaImage meta{image, values};
67 const Node store{Operation(OperationCode::ImageStore, meta, std::move(coords))}; 68 bb.push_back(Operation(OperationCode::ImageStore, meta, std::move(coords)));
68 bb.push_back(store); 69 break;
70 }
71 case OpCode::Id::SUATOM: {
72 UNIMPLEMENTED_IF(instr.suatom_d.is_ba != 0);
73
74 Node value = GetRegister(instr.gpr0);
75
76 std::vector<Node> coords;
77 const std::size_t num_coords{GetImageTypeNumCoordinates(instr.sust.image_type)};
78 for (std::size_t i = 0; i < num_coords; ++i) {
79 coords.push_back(GetRegister(instr.gpr8.Value() + i));
80 }
81
82 const OperationCode operation_code = [instr] {
83 switch (instr.suatom_d.operation) {
84 case Tegra::Shader::ImageAtomicOperation::Add:
85 return OperationCode::AtomicImageAdd;
86 case Tegra::Shader::ImageAtomicOperation::Min:
87 return OperationCode::AtomicImageMin;
88 case Tegra::Shader::ImageAtomicOperation::Max:
89 return OperationCode::AtomicImageMax;
90 case Tegra::Shader::ImageAtomicOperation::And:
91 return OperationCode::AtomicImageAnd;
92 case Tegra::Shader::ImageAtomicOperation::Or:
93 return OperationCode::AtomicImageOr;
94 case Tegra::Shader::ImageAtomicOperation::Xor:
95 return OperationCode::AtomicImageXor;
96 case Tegra::Shader::ImageAtomicOperation::Exch:
97 return OperationCode::AtomicImageExchange;
98 default:
99 UNIMPLEMENTED_MSG("Unimplemented operation={}",
100 static_cast<u32>(instr.suatom_d.operation.Value()));
101 return OperationCode::AtomicImageAdd;
102 }
103 }();
104
105 const auto& image{GetImage(instr.image, instr.suatom_d.image_type, instr.suatom_d.size)};
106 MetaImage meta{image, {std::move(value)}};
107 SetRegister(bb, instr.gpr0, Operation(operation_code, meta, std::move(coords)));
69 break; 108 break;
70 } 109 }
71 default: 110 default:
72 UNIMPLEMENTED_MSG("Unhandled conversion instruction: {}", opcode->get().GetName()); 111 UNIMPLEMENTED_MSG("Unhandled image instruction: {}", opcode->get().GetName());
73 } 112 }
74 113
75 return pc; 114 return pc;
76} 115}
77 116
78const Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) { 117Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type,
118 std::optional<Tegra::Shader::ImageAtomicSize> size) {
79 const auto offset{static_cast<std::size_t>(image.index.Value())}; 119 const auto offset{static_cast<std::size_t>(image.index.Value())};
80 120 if (const auto image = TryUseExistingImage(offset, type, size)) {
81 // If this image has already been used, return the existing mapping. 121 return *image;
82 const auto itr{std::find_if(used_images.begin(), used_images.end(),
83 [=](const Image& entry) { return entry.GetOffset() == offset; })};
84 if (itr != used_images.end()) {
85 ASSERT(itr->GetType() == type);
86 return *itr;
87 } 122 }
88 123
89 // Otherwise create a new mapping for this image.
90 const std::size_t next_index{used_images.size()}; 124 const std::size_t next_index{used_images.size()};
91 const Image entry{offset, next_index, type}; 125 return used_images.emplace(offset, Image{offset, next_index, type, size}).first->second;
92 return *used_images.emplace(entry).first;
93} 126}
94 127
95const Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, 128Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type,
96 Tegra::Shader::ImageType type) { 129 std::optional<Tegra::Shader::ImageAtomicSize> size) {
97 const Node image_register{GetRegister(reg)}; 130 const Node image_register{GetRegister(reg)};
98 const auto [base_image, cbuf_index, cbuf_offset]{ 131 const auto [base_image, cbuf_index, cbuf_offset]{
99 TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))}; 132 TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))};
100 const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)}; 133 const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)};
101 134
102 // If this image has already been used, return the existing mapping. 135 if (const auto image = TryUseExistingImage(cbuf_key, type, size)) {
103 const auto itr{std::find_if(used_images.begin(), used_images.end(), 136 return *image;
104 [=](const Image& entry) { return entry.GetOffset() == cbuf_key; })};
105 if (itr != used_images.end()) {
106 ASSERT(itr->GetType() == type);
107 return *itr;
108 } 137 }
109 138
110 // Otherwise create a new mapping for this image.
111 const std::size_t next_index{used_images.size()}; 139 const std::size_t next_index{used_images.size()};
112 const Image entry{cbuf_index, cbuf_offset, next_index, type}; 140 return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type, size})
113 return *used_images.emplace(entry).first; 141 .first->second;
142}
143
144Image* ShaderIR::TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type,
145 std::optional<Tegra::Shader::ImageAtomicSize> size) {
146 auto it = used_images.find(offset);
147 if (it == used_images.end()) {
148 return nullptr;
149 }
150 auto& image = it->second;
151 ASSERT(image.GetType() == type);
152
153 if (size) {
154 // We know the size, if it's known it has to be the same as before, otherwise we can set it.
155 if (image.IsSizeKnown()) {
156 ASSERT(image.GetSize() == size);
157 } else {
158 image.SetSize(*size);
159 }
160 }
161 return &image;
114} 162}
115 163
116} // namespace VideoCommon::Shader 164} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp
index ed108bea8..7923d4d69 100644
--- a/src/video_core/shader/decode/memory.cpp
+++ b/src/video_core/shader/decode/memory.cpp
@@ -35,7 +35,7 @@ u32 GetUniformTypeElementsCount(Tegra::Shader::UniformType uniform_type) {
35 return 1; 35 return 1;
36 } 36 }
37} 37}
38} // namespace 38} // Anonymous namespace
39 39
40u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { 40u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
41 const Instruction instr = {program_code[pc]}; 41 const Instruction instr = {program_code[pc]};
@@ -106,16 +106,17 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
106 } 106 }
107 break; 107 break;
108 } 108 }
109 case OpCode::Id::LD_L: { 109 case OpCode::Id::LD_L:
110 LOG_DEBUG(HW_GPU, "LD_L cache management mode: {}", 110 LOG_DEBUG(HW_GPU, "LD_L cache management mode: {}", static_cast<u64>(instr.ld_l.unknown));
111 static_cast<u64>(instr.ld_l.unknown.Value())); 111 [[fallthrough]];
112 112 case OpCode::Id::LD_S: {
113 const auto GetLmem = [&](s32 offset) { 113 const auto GetMemory = [&](s32 offset) {
114 ASSERT(offset % 4 == 0); 114 ASSERT(offset % 4 == 0);
115 const Node immediate_offset = Immediate(static_cast<s32>(instr.smem_imm) + offset); 115 const Node immediate_offset = Immediate(static_cast<s32>(instr.smem_imm) + offset);
116 const Node address = Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8), 116 const Node address = Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8),
117 immediate_offset); 117 immediate_offset);
118 return GetLocalMemory(address); 118 return opcode->get().GetId() == OpCode::Id::LD_S ? GetSharedMemory(address)
119 : GetLocalMemory(address);
119 }; 120 };
120 121
121 switch (instr.ldst_sl.type.Value()) { 122 switch (instr.ldst_sl.type.Value()) {
@@ -135,14 +136,16 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
135 return 0; 136 return 0;
136 } 137 }
137 }(); 138 }();
138 for (u32 i = 0; i < count; ++i) 139 for (u32 i = 0; i < count; ++i) {
139 SetTemporary(bb, i, GetLmem(i * 4)); 140 SetTemporary(bb, i, GetMemory(i * 4));
140 for (u32 i = 0; i < count; ++i) 141 }
142 for (u32 i = 0; i < count; ++i) {
141 SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i)); 143 SetRegister(bb, instr.gpr0.Value() + i, GetTemporary(i));
144 }
142 break; 145 break;
143 } 146 }
144 default: 147 default:
145 UNIMPLEMENTED_MSG("LD_L Unhandled type: {}", 148 UNIMPLEMENTED_MSG("{} Unhandled type: {}", opcode->get().GetName(),
146 static_cast<u32>(instr.ldst_sl.type.Value())); 149 static_cast<u32>(instr.ldst_sl.type.Value()));
147 } 150 }
148 break; 151 break;
@@ -209,27 +212,34 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
209 212
210 break; 213 break;
211 } 214 }
212 case OpCode::Id::ST_L: { 215 case OpCode::Id::ST_L:
213 LOG_DEBUG(HW_GPU, "ST_L cache management mode: {}", 216 LOG_DEBUG(HW_GPU, "ST_L cache management mode: {}",
214 static_cast<u64>(instr.st_l.cache_management.Value())); 217 static_cast<u64>(instr.st_l.cache_management.Value()));
215 218 [[fallthrough]];
216 const auto GetLmemAddr = [&](s32 offset) { 219 case OpCode::Id::ST_S: {
220 const auto GetAddress = [&](s32 offset) {
217 ASSERT(offset % 4 == 0); 221 ASSERT(offset % 4 == 0);
218 const Node immediate = Immediate(static_cast<s32>(instr.smem_imm) + offset); 222 const Node immediate = Immediate(static_cast<s32>(instr.smem_imm) + offset);
219 return Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8), immediate); 223 return Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8), immediate);
220 }; 224 };
221 225
226 const auto set_memory = opcode->get().GetId() == OpCode::Id::ST_L
227 ? &ShaderIR::SetLocalMemory
228 : &ShaderIR::SetSharedMemory;
229
222 switch (instr.ldst_sl.type.Value()) { 230 switch (instr.ldst_sl.type.Value()) {
223 case Tegra::Shader::StoreType::Bits128: 231 case Tegra::Shader::StoreType::Bits128:
224 SetLocalMemory(bb, GetLmemAddr(12), GetRegister(instr.gpr0.Value() + 3)); 232 (this->*set_memory)(bb, GetAddress(12), GetRegister(instr.gpr0.Value() + 3));
225 SetLocalMemory(bb, GetLmemAddr(8), GetRegister(instr.gpr0.Value() + 2)); 233 (this->*set_memory)(bb, GetAddress(8), GetRegister(instr.gpr0.Value() + 2));
234 [[fallthrough]];
226 case Tegra::Shader::StoreType::Bits64: 235 case Tegra::Shader::StoreType::Bits64:
227 SetLocalMemory(bb, GetLmemAddr(4), GetRegister(instr.gpr0.Value() + 1)); 236 (this->*set_memory)(bb, GetAddress(4), GetRegister(instr.gpr0.Value() + 1));
237 [[fallthrough]];
228 case Tegra::Shader::StoreType::Bits32: 238 case Tegra::Shader::StoreType::Bits32:
229 SetLocalMemory(bb, GetLmemAddr(0), GetRegister(instr.gpr0)); 239 (this->*set_memory)(bb, GetAddress(0), GetRegister(instr.gpr0));
230 break; 240 break;
231 default: 241 default:
232 UNIMPLEMENTED_MSG("ST_L Unhandled type: {}", 242 UNIMPLEMENTED_MSG("{} unhandled type: {}", opcode->get().GetName(),
233 static_cast<u32>(instr.ldst_sl.type.Value())); 243 static_cast<u32>(instr.ldst_sl.type.Value()));
234 } 244 }
235 break; 245 break;
diff --git a/src/video_core/shader/decode/shift.cpp b/src/video_core/shader/decode/shift.cpp
index 2ac16eeb0..f6ee68a54 100644
--- a/src/video_core/shader/decode/shift.cpp
+++ b/src/video_core/shader/decode/shift.cpp
@@ -17,8 +17,8 @@ u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) {
17 const Instruction instr = {program_code[pc]}; 17 const Instruction instr = {program_code[pc]};
18 const auto opcode = OpCode::Decode(instr); 18 const auto opcode = OpCode::Decode(instr);
19 19
20 const Node op_a = GetRegister(instr.gpr8); 20 Node op_a = GetRegister(instr.gpr8);
21 const Node op_b = [&]() { 21 Node op_b = [&]() {
22 if (instr.is_b_imm) { 22 if (instr.is_b_imm) {
23 return Immediate(instr.alu.GetSignedImm20_20()); 23 return Immediate(instr.alu.GetSignedImm20_20());
24 } else if (instr.is_b_gpr) { 24 } else if (instr.is_b_gpr) {
@@ -32,16 +32,23 @@ u32 ShaderIR::DecodeShift(NodeBlock& bb, u32 pc) {
32 case OpCode::Id::SHR_C: 32 case OpCode::Id::SHR_C:
33 case OpCode::Id::SHR_R: 33 case OpCode::Id::SHR_R:
34 case OpCode::Id::SHR_IMM: { 34 case OpCode::Id::SHR_IMM: {
35 const Node value = SignedOperation(OperationCode::IArithmeticShiftRight, 35 if (instr.shr.wrap) {
36 instr.shift.is_signed, PRECISE, op_a, op_b); 36 op_b = Operation(OperationCode::UBitwiseAnd, std::move(op_b), Immediate(0x1f));
37 } else {
38 op_b = Operation(OperationCode::IMax, std::move(op_b), Immediate(0));
39 op_b = Operation(OperationCode::IMin, std::move(op_b), Immediate(31));
40 }
41
42 Node value = SignedOperation(OperationCode::IArithmeticShiftRight, instr.shift.is_signed,
43 std::move(op_a), std::move(op_b));
37 SetInternalFlagsFromInteger(bb, value, instr.generates_cc); 44 SetInternalFlagsFromInteger(bb, value, instr.generates_cc);
38 SetRegister(bb, instr.gpr0, value); 45 SetRegister(bb, instr.gpr0, std::move(value));
39 break; 46 break;
40 } 47 }
41 case OpCode::Id::SHL_C: 48 case OpCode::Id::SHL_C:
42 case OpCode::Id::SHL_R: 49 case OpCode::Id::SHL_R:
43 case OpCode::Id::SHL_IMM: { 50 case OpCode::Id::SHL_IMM: {
44 const Node value = Operation(OperationCode::ILogicalShiftLeft, PRECISE, op_a, op_b); 51 const Node value = Operation(OperationCode::ILogicalShiftLeft, op_a, op_b);
45 SetInternalFlagsFromInteger(bb, value, instr.generates_cc); 52 SetInternalFlagsFromInteger(bb, value, instr.generates_cc);
46 SetRegister(bb, instr.gpr0, value); 53 SetRegister(bb, instr.gpr0, value);
47 break; 54 break;
diff --git a/src/video_core/shader/decode/warp.cpp b/src/video_core/shader/decode/warp.cpp
index 04ca74f46..a8e481b3c 100644
--- a/src/video_core/shader/decode/warp.cpp
+++ b/src/video_core/shader/decode/warp.cpp
@@ -13,6 +13,7 @@ namespace VideoCommon::Shader {
13using Tegra::Shader::Instruction; 13using Tegra::Shader::Instruction;
14using Tegra::Shader::OpCode; 14using Tegra::Shader::OpCode;
15using Tegra::Shader::Pred; 15using Tegra::Shader::Pred;
16using Tegra::Shader::ShuffleOperation;
16using Tegra::Shader::VoteOperation; 17using Tegra::Shader::VoteOperation;
17 18
18namespace { 19namespace {
@@ -44,6 +45,52 @@ u32 ShaderIR::DecodeWarp(NodeBlock& bb, u32 pc) {
44 SetPredicate(bb, instr.vote.dest_pred, vote); 45 SetPredicate(bb, instr.vote.dest_pred, vote);
45 break; 46 break;
46 } 47 }
48 case OpCode::Id::SHFL: {
49 Node mask = instr.shfl.is_mask_imm ? Immediate(static_cast<u32>(instr.shfl.mask_imm))
50 : GetRegister(instr.gpr39);
51 Node width = [&] {
52 // Convert the obscure SHFL mask back into GL_NV_shader_thread_shuffle's width. This has
53 // been done reversing Nvidia's math. It won't work on all cases due to SHFL having
54 // different parameters that don't properly map to GLSL's interface, but it should work
55 // for cases emitted by Nvidia's compiler.
56 if (instr.shfl.operation == ShuffleOperation::Up) {
57 return Operation(
58 OperationCode::ILogicalShiftRight,
59 Operation(OperationCode::IAdd, std::move(mask), Immediate(-0x2000)),
60 Immediate(8));
61 } else {
62 return Operation(OperationCode::ILogicalShiftRight,
63 Operation(OperationCode::IAdd, Immediate(0x201F),
64 Operation(OperationCode::INegate, std::move(mask))),
65 Immediate(8));
66 }
67 }();
68
69 const auto [operation, in_range] = [instr]() -> std::pair<OperationCode, OperationCode> {
70 switch (instr.shfl.operation) {
71 case ShuffleOperation::Idx:
72 return {OperationCode::ShuffleIndexed, OperationCode::InRangeShuffleIndexed};
73 case ShuffleOperation::Up:
74 return {OperationCode::ShuffleUp, OperationCode::InRangeShuffleUp};
75 case ShuffleOperation::Down:
76 return {OperationCode::ShuffleDown, OperationCode::InRangeShuffleDown};
77 case ShuffleOperation::Bfly:
78 return {OperationCode::ShuffleButterfly, OperationCode::InRangeShuffleButterfly};
79 }
80 UNREACHABLE_MSG("Invalid SHFL operation: {}",
81 static_cast<u64>(instr.shfl.operation.Value()));
82 return {};
83 }();
84
85 // Setting the predicate before the register is intentional to avoid overwriting.
86 Node index = instr.shfl.is_index_imm ? Immediate(static_cast<u32>(instr.shfl.index_imm))
87 : GetRegister(instr.gpr20);
88 SetPredicate(bb, instr.shfl.pred48, Operation(in_range, index, width));
89 SetRegister(
90 bb, instr.gpr0,
91 Operation(operation, GetRegister(instr.gpr8), std::move(index), std::move(width)));
92 break;
93 }
47 default: 94 default:
48 UNIMPLEMENTED_MSG("Unhandled warp instruction: {}", opcode->get().GetName()); 95 UNIMPLEMENTED_MSG("Unhandled warp instruction: {}", opcode->get().GetName());
49 break; 96 break;
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index 5db9313c4..abf2cb1ab 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -7,6 +7,7 @@
7#include <array> 7#include <array>
8#include <cstddef> 8#include <cstddef>
9#include <memory> 9#include <memory>
10#include <optional>
10#include <string> 11#include <string>
11#include <tuple> 12#include <tuple>
12#include <utility> 13#include <utility>
@@ -148,7 +149,14 @@ enum class OperationCode {
148 TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4 149 TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4
149 TexelFetch, /// (MetaTexture, int[N], int) -> float4 150 TexelFetch, /// (MetaTexture, int[N], int) -> float4
150 151
151 ImageStore, /// (MetaImage, float[N] coords) -> void 152 ImageStore, /// (MetaImage, int[N] values) -> void
153 AtomicImageAdd, /// (MetaImage, int[N] coords) -> void
154 AtomicImageMin, /// (MetaImage, int[N] coords) -> void
155 AtomicImageMax, /// (MetaImage, int[N] coords) -> void
156 AtomicImageAnd, /// (MetaImage, int[N] coords) -> void
157 AtomicImageOr, /// (MetaImage, int[N] coords) -> void
158 AtomicImageXor, /// (MetaImage, int[N] coords) -> void
159 AtomicImageExchange, /// (MetaImage, int[N] coords) -> void
152 160
153 Branch, /// (uint branch_target) -> void 161 Branch, /// (uint branch_target) -> void
154 BranchIndirect, /// (uint branch_target) -> void 162 BranchIndirect, /// (uint branch_target) -> void
@@ -173,6 +181,16 @@ enum class OperationCode {
173 VoteAny, /// (bool) -> bool 181 VoteAny, /// (bool) -> bool
174 VoteEqual, /// (bool) -> bool 182 VoteEqual, /// (bool) -> bool
175 183
184 ShuffleIndexed, /// (uint value, uint index, uint width) -> uint
185 ShuffleUp, /// (uint value, uint index, uint width) -> uint
186 ShuffleDown, /// (uint value, uint index, uint width) -> uint
187 ShuffleButterfly, /// (uint value, uint index, uint width) -> uint
188
189 InRangeShuffleIndexed, /// (uint index, uint width) -> bool
190 InRangeShuffleUp, /// (uint index, uint width) -> bool
191 InRangeShuffleDown, /// (uint index, uint width) -> bool
192 InRangeShuffleButterfly, /// (uint index, uint width) -> bool
193
176 Amount, 194 Amount,
177}; 195};
178 196
@@ -198,12 +216,13 @@ class PredicateNode;
198class AbufNode; 216class AbufNode;
199class CbufNode; 217class CbufNode;
200class LmemNode; 218class LmemNode;
219class SmemNode;
201class GmemNode; 220class GmemNode;
202class CommentNode; 221class CommentNode;
203 222
204using NodeData = 223using NodeData =
205 std::variant<OperationNode, ConditionalNode, GprNode, ImmediateNode, InternalFlagNode, 224 std::variant<OperationNode, ConditionalNode, GprNode, ImmediateNode, InternalFlagNode,
206 PredicateNode, AbufNode, CbufNode, LmemNode, GmemNode, CommentNode>; 225 PredicateNode, AbufNode, CbufNode, LmemNode, SmemNode, GmemNode, CommentNode>;
207using Node = std::shared_ptr<NodeData>; 226using Node = std::shared_ptr<NodeData>;
208using Node4 = std::array<Node, 4>; 227using Node4 = std::array<Node, 4>;
209using NodeBlock = std::vector<Node>; 228using NodeBlock = std::vector<Node>;
@@ -273,46 +292,85 @@ private:
273 bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not. 292 bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not.
274}; 293};
275 294
276class Image { 295class Image final {
277public: 296public:
278 explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type) 297 constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
279 : offset{offset}, index{index}, type{type}, is_bindless{false} {} 298 std::optional<Tegra::Shader::ImageAtomicSize> size)
299 : offset{offset}, index{index}, type{type}, is_bindless{false}, size{size} {}
280 300
281 explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index, 301 constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
282 Tegra::Shader::ImageType type) 302 Tegra::Shader::ImageType type,
303 std::optional<Tegra::Shader::ImageAtomicSize> size)
283 : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type}, 304 : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type},
284 is_bindless{true} {} 305 is_bindless{true}, size{size} {}
285 306
286 explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, 307 constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
287 bool is_bindless) 308 bool is_bindless, bool is_written, bool is_read,
288 : offset{offset}, index{index}, type{type}, is_bindless{is_bindless} {} 309 std::optional<Tegra::Shader::ImageAtomicSize> size)
310 : offset{offset}, index{index}, type{type}, is_bindless{is_bindless},
311 is_written{is_written}, is_read{is_read}, size{size} {}
289 312
290 std::size_t GetOffset() const { 313 void MarkWrite() {
314 is_written = true;
315 }
316
317 void MarkRead() {
318 is_read = true;
319 }
320
321 void SetSize(Tegra::Shader::ImageAtomicSize size_) {
322 size = size_;
323 }
324
325 constexpr std::size_t GetOffset() const {
291 return offset; 326 return offset;
292 } 327 }
293 328
294 std::size_t GetIndex() const { 329 constexpr std::size_t GetIndex() const {
295 return index; 330 return index;
296 } 331 }
297 332
298 Tegra::Shader::ImageType GetType() const { 333 constexpr Tegra::Shader::ImageType GetType() const {
299 return type; 334 return type;
300 } 335 }
301 336
302 bool IsBindless() const { 337 constexpr bool IsBindless() const {
303 return is_bindless; 338 return is_bindless;
304 } 339 }
305 340
306 bool operator<(const Image& rhs) const { 341 constexpr bool IsWritten() const {
307 return std::tie(offset, index, type, is_bindless) < 342 return is_written;
308 std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_bindless); 343 }
344
345 constexpr bool IsRead() const {
346 return is_read;
347 }
348
349 constexpr std::pair<u32, u32> GetBindlessCBuf() const {
350 return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)};
351 }
352
353 constexpr bool IsSizeKnown() const {
354 return size.has_value();
355 }
356
357 constexpr Tegra::Shader::ImageAtomicSize GetSize() const {
358 return size.value();
359 }
360
361 constexpr bool operator<(const Image& rhs) const {
362 return std::tie(offset, index, type, size, is_bindless) <
363 std::tie(rhs.offset, rhs.index, rhs.type, rhs.size, rhs.is_bindless);
309 } 364 }
310 365
311private: 366private:
312 std::size_t offset{}; 367 u64 offset{};
313 std::size_t index{}; 368 std::size_t index{};
314 Tegra::Shader::ImageType type{}; 369 Tegra::Shader::ImageType type{};
315 bool is_bindless{}; 370 bool is_bindless{};
371 bool is_written{};
372 bool is_read{};
373 std::optional<Tegra::Shader::ImageAtomicSize> size{};
316}; 374};
317 375
318struct GlobalMemoryBase { 376struct GlobalMemoryBase {
@@ -536,6 +594,19 @@ private:
536 Node address; 594 Node address;
537}; 595};
538 596
597/// Shared memory node
598class SmemNode final {
599public:
600 explicit SmemNode(Node address) : address{std::move(address)} {}
601
602 const Node& GetAddress() const {
603 return address;
604 }
605
606private:
607 Node address;
608};
609
539/// Global memory node 610/// Global memory node
540class GmemNode final { 611class GmemNode final {
541public: 612public:
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp
index 1e5c7f660..bbbab0bca 100644
--- a/src/video_core/shader/shader_ir.cpp
+++ b/src/video_core/shader/shader_ir.cpp
@@ -137,6 +137,10 @@ Node ShaderIR::GetLocalMemory(Node address) {
137 return MakeNode<LmemNode>(std::move(address)); 137 return MakeNode<LmemNode>(std::move(address));
138} 138}
139 139
140Node ShaderIR::GetSharedMemory(Node address) {
141 return MakeNode<SmemNode>(std::move(address));
142}
143
140Node ShaderIR::GetTemporary(u32 id) { 144Node ShaderIR::GetTemporary(u32 id) {
141 return GetRegister(Register::ZeroIndex + 1 + id); 145 return GetRegister(Register::ZeroIndex + 1 + id);
142} 146}
@@ -378,6 +382,11 @@ void ShaderIR::SetLocalMemory(NodeBlock& bb, Node address, Node value) {
378 Operation(OperationCode::Assign, GetLocalMemory(std::move(address)), std::move(value))); 382 Operation(OperationCode::Assign, GetLocalMemory(std::move(address)), std::move(value)));
379} 383}
380 384
385void ShaderIR::SetSharedMemory(NodeBlock& bb, Node address, Node value) {
386 bb.push_back(
387 Operation(OperationCode::Assign, GetSharedMemory(std::move(address)), std::move(value)));
388}
389
381void ShaderIR::SetTemporary(NodeBlock& bb, u32 id, Node value) { 390void ShaderIR::SetTemporary(NodeBlock& bb, u32 id, Node value) {
382 SetRegister(bb, Register::ZeroIndex + 1 + id, std::move(value)); 391 SetRegister(bb, Register::ZeroIndex + 1 + id, std::move(value));
383} 392}
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index bcc9b79b6..6aed9bb84 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -95,7 +95,7 @@ public:
95 return used_samplers; 95 return used_samplers;
96 } 96 }
97 97
98 const std::set<Image>& GetImages() const { 98 const std::map<u64, Image>& GetImages() const {
99 return used_images; 99 return used_images;
100 } 100 }
101 101
@@ -208,6 +208,8 @@ private:
208 Node GetInternalFlag(InternalFlag flag, bool negated = false); 208 Node GetInternalFlag(InternalFlag flag, bool negated = false);
209 /// Generates a node representing a local memory address 209 /// Generates a node representing a local memory address
210 Node GetLocalMemory(Node address); 210 Node GetLocalMemory(Node address);
211 /// Generates a node representing a shared memory address
212 Node GetSharedMemory(Node address);
211 /// Generates a temporary, internally it uses a post-RZ register 213 /// Generates a temporary, internally it uses a post-RZ register
212 Node GetTemporary(u32 id); 214 Node GetTemporary(u32 id);
213 215
@@ -217,8 +219,10 @@ private:
217 void SetPredicate(NodeBlock& bb, u64 dest, Node src); 219 void SetPredicate(NodeBlock& bb, u64 dest, Node src);
218 /// Sets an internal flag. src value must be a bool-evaluated node 220 /// Sets an internal flag. src value must be a bool-evaluated node
219 void SetInternalFlag(NodeBlock& bb, InternalFlag flag, Node value); 221 void SetInternalFlag(NodeBlock& bb, InternalFlag flag, Node value);
220 /// Sets a local memory address. address and value must be a number-evaluated node 222 /// Sets a local memory address with a value.
221 void SetLocalMemory(NodeBlock& bb, Node address, Node value); 223 void SetLocalMemory(NodeBlock& bb, Node address, Node value);
224 /// Sets a shared memory address with a value.
225 void SetSharedMemory(NodeBlock& bb, Node address, Node value);
222 /// Sets a temporary. Internally it uses a post-RZ register 226 /// Sets a temporary. Internally it uses a post-RZ register
223 void SetTemporary(NodeBlock& bb, u32 id, Node value); 227 void SetTemporary(NodeBlock& bb, u32 id, Node value);
224 228
@@ -272,10 +276,16 @@ private:
272 bool is_shadow); 276 bool is_shadow);
273 277
274 /// Accesses an image. 278 /// Accesses an image.
275 const Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type); 279 Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type,
280 std::optional<Tegra::Shader::ImageAtomicSize> size = {});
276 281
277 /// Access a bindless image sampler. 282 /// Access a bindless image sampler.
278 const Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type); 283 Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type,
284 std::optional<Tegra::Shader::ImageAtomicSize> size = {});
285
286 /// Tries to access an existing image, updating it's state as needed
287 Image* TryUseExistingImage(u64 offset, Tegra::Shader::ImageType type,
288 std::optional<Tegra::Shader::ImageAtomicSize> size);
279 289
280 /// Extracts a sequence of bits from a node 290 /// Extracts a sequence of bits from a node
281 Node BitfieldExtract(Node value, u32 offset, u32 bits); 291 Node BitfieldExtract(Node value, u32 offset, u32 bits);
@@ -356,7 +366,7 @@ private:
356 std::set<Tegra::Shader::Attribute::Index> used_output_attributes; 366 std::set<Tegra::Shader::Attribute::Index> used_output_attributes;
357 std::map<u32, ConstBuffer> used_cbufs; 367 std::map<u32, ConstBuffer> used_cbufs;
358 std::set<Sampler> used_samplers; 368 std::set<Sampler> used_samplers;
359 std::set<Image> used_images; 369 std::map<u64, Image> used_images;
360 std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; 370 std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{};
361 std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory; 371 std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory;
362 bool uses_layer{}; 372 bool uses_layer{};
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index 4ceb219be..53d0142cb 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -513,6 +513,26 @@ bool IsPixelFormatASTC(PixelFormat format) {
513 } 513 }
514} 514}
515 515
516bool IsPixelFormatSRGB(PixelFormat format) {
517 switch (format) {
518 case PixelFormat::RGBA8_SRGB:
519 case PixelFormat::BGRA8_SRGB:
520 case PixelFormat::DXT1_SRGB:
521 case PixelFormat::DXT23_SRGB:
522 case PixelFormat::DXT45_SRGB:
523 case PixelFormat::BC7U_SRGB:
524 case PixelFormat::ASTC_2D_4X4_SRGB:
525 case PixelFormat::ASTC_2D_8X8_SRGB:
526 case PixelFormat::ASTC_2D_8X5_SRGB:
527 case PixelFormat::ASTC_2D_5X4_SRGB:
528 case PixelFormat::ASTC_2D_5X5_SRGB:
529 case PixelFormat::ASTC_2D_10X8_SRGB:
530 return true;
531 default:
532 return false;
533 }
534}
535
516std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) { 536std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
517 return {GetDefaultBlockWidth(format), GetDefaultBlockHeight(format)}; 537 return {GetDefaultBlockWidth(format), GetDefaultBlockHeight(format)};
518} 538}
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 83f31c12c..19268b7cd 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -547,6 +547,8 @@ SurfaceType GetFormatType(PixelFormat pixel_format);
547 547
548bool IsPixelFormatASTC(PixelFormat format); 548bool IsPixelFormatASTC(PixelFormat format);
549 549
550bool IsPixelFormatSRGB(PixelFormat format);
551
550std::pair<u32, u32> GetASTCBlockSize(PixelFormat format); 552std::pair<u32, u32> GetASTCBlockSize(PixelFormat format);
551 553
552/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN 554/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h
index bcce8d863..5e497e49f 100644
--- a/src/video_core/texture_cache/surface_base.h
+++ b/src/video_core/texture_cache/surface_base.h
@@ -195,18 +195,18 @@ public:
195 195
196 virtual void DownloadTexture(std::vector<u8>& staging_buffer) = 0; 196 virtual void DownloadTexture(std::vector<u8>& staging_buffer) = 0;
197 197
198 void MarkAsModified(const bool is_modified_, const u64 tick) { 198 void MarkAsModified(bool is_modified_, u64 tick) {
199 is_modified = is_modified_ || is_target; 199 is_modified = is_modified_ || is_target;
200 modification_tick = tick; 200 modification_tick = tick;
201 } 201 }
202 202
203 void MarkAsRenderTarget(const bool is_target, const u32 index) { 203 void MarkAsRenderTarget(bool is_target_, u32 index_) {
204 this->is_target = is_target; 204 is_target = is_target_;
205 this->index = index; 205 index = index_;
206 } 206 }
207 207
208 void MarkAsPicked(const bool is_picked) { 208 void MarkAsPicked(bool is_picked_) {
209 this->is_picked = is_picked; 209 is_picked = is_picked_;
210 } 210 }
211 211
212 bool IsModified() const { 212 bool IsModified() const {
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp
index fd5472451..1e4d3fb79 100644
--- a/src/video_core/texture_cache/surface_params.cpp
+++ b/src/video_core/texture_cache/surface_params.cpp
@@ -24,55 +24,62 @@ using VideoCore::Surface::SurfaceTarget;
24using VideoCore::Surface::SurfaceTargetFromTextureType; 24using VideoCore::Surface::SurfaceTargetFromTextureType;
25using VideoCore::Surface::SurfaceType; 25using VideoCore::Surface::SurfaceType;
26 26
27SurfaceTarget TextureType2SurfaceTarget(Tegra::Shader::TextureType type, bool is_array) { 27namespace {
28
29SurfaceTarget TextureTypeToSurfaceTarget(Tegra::Shader::TextureType type, bool is_array) {
28 switch (type) { 30 switch (type) {
29 case Tegra::Shader::TextureType::Texture1D: { 31 case Tegra::Shader::TextureType::Texture1D:
30 if (is_array) 32 return is_array ? SurfaceTarget::Texture1DArray : SurfaceTarget::Texture1D;
31 return SurfaceTarget::Texture1DArray; 33 case Tegra::Shader::TextureType::Texture2D:
32 else 34 return is_array ? SurfaceTarget::Texture2DArray : SurfaceTarget::Texture2D;
33 return SurfaceTarget::Texture1D; 35 case Tegra::Shader::TextureType::Texture3D:
34 }
35 case Tegra::Shader::TextureType::Texture2D: {
36 if (is_array)
37 return SurfaceTarget::Texture2DArray;
38 else
39 return SurfaceTarget::Texture2D;
40 }
41 case Tegra::Shader::TextureType::Texture3D: {
42 ASSERT(!is_array); 36 ASSERT(!is_array);
43 return SurfaceTarget::Texture3D; 37 return SurfaceTarget::Texture3D;
44 } 38 case Tegra::Shader::TextureType::TextureCube:
45 case Tegra::Shader::TextureType::TextureCube: { 39 return is_array ? SurfaceTarget::TextureCubeArray : SurfaceTarget::TextureCubemap;
46 if (is_array) 40 default:
47 return SurfaceTarget::TextureCubeArray;
48 else
49 return SurfaceTarget::TextureCubemap;
50 }
51 default: {
52 UNREACHABLE(); 41 UNREACHABLE();
53 return SurfaceTarget::Texture2D; 42 return SurfaceTarget::Texture2D;
54 } 43 }
44}
45
46SurfaceTarget ImageTypeToSurfaceTarget(Tegra::Shader::ImageType type) {
47 switch (type) {
48 case Tegra::Shader::ImageType::Texture1D:
49 return SurfaceTarget::Texture1D;
50 case Tegra::Shader::ImageType::TextureBuffer:
51 return SurfaceTarget::TextureBuffer;
52 case Tegra::Shader::ImageType::Texture1DArray:
53 return SurfaceTarget::Texture1DArray;
54 case Tegra::Shader::ImageType::Texture2D:
55 return SurfaceTarget::Texture2D;
56 case Tegra::Shader::ImageType::Texture2DArray:
57 return SurfaceTarget::Texture2DArray;
58 case Tegra::Shader::ImageType::Texture3D:
59 return SurfaceTarget::Texture3D;
60 default:
61 UNREACHABLE();
62 return SurfaceTarget::Texture2D;
55 } 63 }
56} 64}
57 65
58namespace {
59constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) { 66constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) {
60 return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile); 67 return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile);
61} 68}
69
62} // Anonymous namespace 70} // Anonymous namespace
63 71
64SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, 72SurfaceParams SurfaceParams::CreateForTexture(const Tegra::Texture::TICEntry& tic,
65 const Tegra::Texture::FullTextureInfo& config,
66 const VideoCommon::Shader::Sampler& entry) { 73 const VideoCommon::Shader::Sampler& entry) {
67 SurfaceParams params; 74 SurfaceParams params;
68 params.is_tiled = config.tic.IsTiled(); 75 params.is_tiled = tic.IsTiled();
69 params.srgb_conversion = config.tic.IsSrgbConversionEnabled(); 76 params.srgb_conversion = tic.IsSrgbConversionEnabled();
70 params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0, 77 params.block_width = params.is_tiled ? tic.BlockWidth() : 0,
71 params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0, 78 params.block_height = params.is_tiled ? tic.BlockHeight() : 0,
72 params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0, 79 params.block_depth = params.is_tiled ? tic.BlockDepth() : 0,
73 params.tile_width_spacing = params.is_tiled ? (1 << config.tic.tile_width_spacing.Value()) : 1; 80 params.tile_width_spacing = params.is_tiled ? (1 << tic.tile_width_spacing.Value()) : 1;
74 params.pixel_format = PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(), 81 params.pixel_format =
75 params.srgb_conversion); 82 PixelFormatFromTextureFormat(tic.format, tic.r_type.Value(), params.srgb_conversion);
76 params.type = GetFormatType(params.pixel_format); 83 params.type = GetFormatType(params.pixel_format);
77 if (entry.IsShadow() && params.type == SurfaceType::ColorTexture) { 84 if (entry.IsShadow() && params.type == SurfaceType::ColorTexture) {
78 switch (params.pixel_format) { 85 switch (params.pixel_format) {
@@ -92,31 +99,72 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
92 } 99 }
93 params.type = GetFormatType(params.pixel_format); 100 params.type = GetFormatType(params.pixel_format);
94 } 101 }
95 params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value()); 102 params.component_type = ComponentTypeFromTexture(tic.r_type.Value());
96 params.type = GetFormatType(params.pixel_format); 103 params.type = GetFormatType(params.pixel_format);
97 // TODO: on 1DBuffer we should use the tic info. 104 // TODO: on 1DBuffer we should use the tic info.
98 if (!config.tic.IsBuffer()) { 105 if (tic.IsBuffer()) {
99 params.target = TextureType2SurfaceTarget(entry.GetType(), entry.IsArray()); 106 params.target = SurfaceTarget::TextureBuffer;
100 params.width = config.tic.Width(); 107 params.width = tic.Width();
101 params.height = config.tic.Height(); 108 params.pitch = params.width * params.GetBytesPerPixel();
102 params.depth = config.tic.Depth(); 109 params.height = 1;
103 params.pitch = params.is_tiled ? 0 : config.tic.Pitch(); 110 params.depth = 1;
111 params.num_levels = 1;
112 params.emulated_levels = 1;
113 params.is_layered = false;
114 } else {
115 params.target = TextureTypeToSurfaceTarget(entry.GetType(), entry.IsArray());
116 params.width = tic.Width();
117 params.height = tic.Height();
118 params.depth = tic.Depth();
119 params.pitch = params.is_tiled ? 0 : tic.Pitch();
104 if (params.target == SurfaceTarget::TextureCubemap || 120 if (params.target == SurfaceTarget::TextureCubemap ||
105 params.target == SurfaceTarget::TextureCubeArray) { 121 params.target == SurfaceTarget::TextureCubeArray) {
106 params.depth *= 6; 122 params.depth *= 6;
107 } 123 }
108 params.num_levels = config.tic.max_mip_level + 1; 124 params.num_levels = tic.max_mip_level + 1;
109 params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap()); 125 params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap());
110 params.is_layered = params.IsLayered(); 126 params.is_layered = params.IsLayered();
111 } else { 127 }
128 return params;
129}
130
131SurfaceParams SurfaceParams::CreateForImage(const Tegra::Texture::TICEntry& tic,
132 const VideoCommon::Shader::Image& entry) {
133 SurfaceParams params;
134 params.is_tiled = tic.IsTiled();
135 params.srgb_conversion = tic.IsSrgbConversionEnabled();
136 params.block_width = params.is_tiled ? tic.BlockWidth() : 0,
137 params.block_height = params.is_tiled ? tic.BlockHeight() : 0,
138 params.block_depth = params.is_tiled ? tic.BlockDepth() : 0,
139 params.tile_width_spacing = params.is_tiled ? (1 << tic.tile_width_spacing.Value()) : 1;
140 params.pixel_format =
141 PixelFormatFromTextureFormat(tic.format, tic.r_type.Value(), params.srgb_conversion);
142 params.type = GetFormatType(params.pixel_format);
143 params.component_type = ComponentTypeFromTexture(tic.r_type.Value());
144 params.type = GetFormatType(params.pixel_format);
145 params.target = ImageTypeToSurfaceTarget(entry.GetType());
146 // TODO: on 1DBuffer we should use the tic info.
147 if (tic.IsBuffer()) {
112 params.target = SurfaceTarget::TextureBuffer; 148 params.target = SurfaceTarget::TextureBuffer;
113 params.width = config.tic.Width(); 149 params.width = tic.Width();
114 params.pitch = params.width * params.GetBytesPerPixel(); 150 params.pitch = params.width * params.GetBytesPerPixel();
115 params.height = 1; 151 params.height = 1;
116 params.depth = 1; 152 params.depth = 1;
117 params.num_levels = 1; 153 params.num_levels = 1;
118 params.emulated_levels = 1; 154 params.emulated_levels = 1;
119 params.is_layered = false; 155 params.is_layered = false;
156 } else {
157 params.width = tic.Width();
158 params.height = tic.Height();
159 params.depth = tic.Depth();
160 params.pitch = params.is_tiled ? 0 : tic.Pitch();
161 if (params.target == SurfaceTarget::TextureCubemap ||
162 params.target == SurfaceTarget::TextureCubeArray) {
163 params.depth *= 6;
164 }
165 params.num_levels = tic.max_mip_level + 1;
166 params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap());
167 params.is_layered = params.IsLayered();
120 } 168 }
121 return params; 169 return params;
122} 170}
diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h
index e7ef66ee2..c58e7f8a4 100644
--- a/src/video_core/texture_cache/surface_params.h
+++ b/src/video_core/texture_cache/surface_params.h
@@ -4,8 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <map>
8
9#include "common/alignment.h" 7#include "common/alignment.h"
10#include "common/bit_util.h" 8#include "common/bit_util.h"
11#include "common/cityhash.h" 9#include "common/cityhash.h"
@@ -23,10 +21,13 @@ using VideoCore::Surface::SurfaceCompression;
23class SurfaceParams { 21class SurfaceParams {
24public: 22public:
25 /// Creates SurfaceCachedParams from a texture configuration. 23 /// Creates SurfaceCachedParams from a texture configuration.
26 static SurfaceParams CreateForTexture(Core::System& system, 24 static SurfaceParams CreateForTexture(const Tegra::Texture::TICEntry& tic,
27 const Tegra::Texture::FullTextureInfo& config,
28 const VideoCommon::Shader::Sampler& entry); 25 const VideoCommon::Shader::Sampler& entry);
29 26
27 /// Creates SurfaceCachedParams from an image configuration.
28 static SurfaceParams CreateForImage(const Tegra::Texture::TICEntry& tic,
29 const VideoCommon::Shader::Image& entry);
30
30 /// Creates SurfaceCachedParams for a depth buffer configuration. 31 /// Creates SurfaceCachedParams for a depth buffer configuration.
31 static SurfaceParams CreateForDepthBuffer( 32 static SurfaceParams CreateForDepthBuffer(
32 Core::System& system, u32 zeta_width, u32 zeta_height, Tegra::DepthFormat format, 33 Core::System& system, u32 zeta_width, u32 zeta_height, Tegra::DepthFormat format,
diff --git a/src/video_core/texture_cache/surface_view.cpp b/src/video_core/texture_cache/surface_view.cpp
index 467696a4c..57a1f5803 100644
--- a/src/video_core/texture_cache/surface_view.cpp
+++ b/src/video_core/texture_cache/surface_view.cpp
@@ -10,7 +10,7 @@
10namespace VideoCommon { 10namespace VideoCommon {
11 11
12std::size_t ViewParams::Hash() const { 12std::size_t ViewParams::Hash() const {
13 return static_cast<std::size_t>(base_layer) ^ static_cast<std::size_t>(num_layers << 16) ^ 13 return static_cast<std::size_t>(base_layer) ^ (static_cast<std::size_t>(num_layers) << 16) ^
14 (static_cast<std::size_t>(base_level) << 24) ^ 14 (static_cast<std::size_t>(base_level) << 24) ^
15 (static_cast<std::size_t>(num_levels) << 32) ^ (static_cast<std::size_t>(target) << 36); 15 (static_cast<std::size_t>(num_levels) << 32) ^ (static_cast<std::size_t>(target) << 36);
16} 16}
diff --git a/src/video_core/texture_cache/surface_view.h b/src/video_core/texture_cache/surface_view.h
index 04ca5639b..b17fd11a9 100644
--- a/src/video_core/texture_cache/surface_view.h
+++ b/src/video_core/texture_cache/surface_view.h
@@ -13,8 +13,8 @@
13namespace VideoCommon { 13namespace VideoCommon {
14 14
15struct ViewParams { 15struct ViewParams {
16 ViewParams(VideoCore::Surface::SurfaceTarget target, u32 base_layer, u32 num_layers, 16 constexpr explicit ViewParams(VideoCore::Surface::SurfaceTarget target, u32 base_layer,
17 u32 base_level, u32 num_levels) 17 u32 num_layers, u32 base_level, u32 num_levels)
18 : target{target}, base_layer{base_layer}, num_layers{num_layers}, base_level{base_level}, 18 : target{target}, base_layer{base_layer}, num_layers{num_layers}, base_level{base_level},
19 num_levels{num_levels} {} 19 num_levels{num_levels} {}
20 20
@@ -22,12 +22,6 @@ struct ViewParams {
22 22
23 bool operator==(const ViewParams& rhs) const; 23 bool operator==(const ViewParams& rhs) const;
24 24
25 VideoCore::Surface::SurfaceTarget target{};
26 u32 base_layer{};
27 u32 num_layers{};
28 u32 base_level{};
29 u32 num_levels{};
30
31 bool IsLayered() const { 25 bool IsLayered() const {
32 switch (target) { 26 switch (target) {
33 case VideoCore::Surface::SurfaceTarget::Texture1DArray: 27 case VideoCore::Surface::SurfaceTarget::Texture1DArray:
@@ -39,13 +33,19 @@ struct ViewParams {
39 return false; 33 return false;
40 } 34 }
41 } 35 }
36
37 VideoCore::Surface::SurfaceTarget target{};
38 u32 base_layer{};
39 u32 num_layers{};
40 u32 base_level{};
41 u32 num_levels{};
42}; 42};
43 43
44class ViewBase { 44class ViewBase {
45public: 45public:
46 ViewBase(const ViewParams& params) : params{params} {} 46 constexpr explicit ViewBase(const ViewParams& params) : params{params} {}
47 47
48 const ViewParams& GetViewParams() const { 48 constexpr const ViewParams& GetViewParams() const {
49 return params; 49 return params;
50 } 50 }
51 51
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 2ec0203d1..877c6635d 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -89,14 +89,29 @@ public:
89 } 89 }
90 } 90 }
91 91
92 TView GetTextureSurface(const Tegra::Texture::FullTextureInfo& config, 92 TView GetTextureSurface(const Tegra::Texture::TICEntry& tic,
93 const VideoCommon::Shader::Sampler& entry) { 93 const VideoCommon::Shader::Sampler& entry) {
94 std::lock_guard lock{mutex}; 94 std::lock_guard lock{mutex};
95 const auto gpu_addr{config.tic.Address()}; 95 const auto gpu_addr{tic.Address()};
96 if (!gpu_addr) { 96 if (!gpu_addr) {
97 return {}; 97 return {};
98 } 98 }
99 const auto params{SurfaceParams::CreateForTexture(system, config, entry)}; 99 const auto params{SurfaceParams::CreateForTexture(tic, entry)};
100 const auto [surface, view] = GetSurface(gpu_addr, params, true, false);
101 if (guard_samplers) {
102 sampled_textures.push_back(surface);
103 }
104 return view;
105 }
106
107 TView GetImageSurface(const Tegra::Texture::TICEntry& tic,
108 const VideoCommon::Shader::Image& entry) {
109 std::lock_guard lock{mutex};
110 const auto gpu_addr{tic.Address()};
111 if (!gpu_addr) {
112 return {};
113 }
114 const auto params{SurfaceParams::CreateForImage(tic, entry)};
100 const auto [surface, view] = GetSurface(gpu_addr, params, true, false); 115 const auto [surface, view] = GetSurface(gpu_addr, params, true, false);
101 if (guard_samplers) { 116 if (guard_samplers) {
102 sampled_textures.push_back(surface); 117 sampled_textures.push_back(surface);