summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2018-11-07 00:14:36 -0800
committerGravatar GitHub2018-11-07 00:14:36 -0800
commit81ff9e2473125c78ac07e15b64bf26d49d2472d9 (patch)
treeaae94a4ae674cbc47f1e1f4e4681f77dadbac2fc
parentMerge pull request #1635 from Tinob/master (diff)
parentmemory_manager: Do not MapBufferEx over already in use memory. (diff)
downloadyuzu-81ff9e2473125c78ac07e15b64bf26d49d2472d9.tar.gz
yuzu-81ff9e2473125c78ac07e15b64bf26d49d2472d9.tar.xz
yuzu-81ff9e2473125c78ac07e15b64bf26d49d2472d9.zip
Merge pull request #1630 from bunnei/fix-mapbufferex
memory_manager: Do not MapBufferEx over already in use memory.
-rw-r--r--src/video_core/memory_manager.cpp75
-rw-r--r--src/video_core/memory_manager.h8
2 files changed, 52 insertions, 31 deletions
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 90a8e825d..77a20bb84 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -4,18 +4,21 @@
4 4
5#include "common/alignment.h" 5#include "common/alignment.h"
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/logging/log.h"
7#include "video_core/memory_manager.h" 8#include "video_core/memory_manager.h"
8 9
9namespace Tegra { 10namespace Tegra {
10 11
11GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) { 12GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
12 std::optional<GPUVAddr> gpu_addr = FindFreeBlock(size, align); 13 const std::optional<GPUVAddr> gpu_addr{FindFreeBlock(0, size, align, PageStatus::Unmapped)};
13 ASSERT(gpu_addr);
14 14
15 for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { 15 ASSERT_MSG(gpu_addr, "unable to find available GPU memory");
16 VAddr& slot = PageSlot(*gpu_addr + offset); 16
17 for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
18 VAddr& slot{PageSlot(*gpu_addr + offset)};
17 19
18 ASSERT(slot == static_cast<u64>(PageStatus::Unmapped)); 20 ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
21
19 slot = static_cast<u64>(PageStatus::Allocated); 22 slot = static_cast<u64>(PageStatus::Allocated);
20 } 23 }
21 24
@@ -23,10 +26,11 @@ GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
23} 26}
24 27
25GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) { 28GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) {
26 for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { 29 for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
27 VAddr& slot = PageSlot(gpu_addr + offset); 30 VAddr& slot{PageSlot(gpu_addr + offset)};
28 31
29 ASSERT(slot == static_cast<u64>(PageStatus::Unmapped)); 32 ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
33
30 slot = static_cast<u64>(PageStatus::Allocated); 34 slot = static_cast<u64>(PageStatus::Allocated);
31 } 35 }
32 36
@@ -34,17 +38,19 @@ GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) {
34} 38}
35 39
36GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) { 40GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) {
37 std::optional<GPUVAddr> gpu_addr = FindFreeBlock(size, PAGE_SIZE); 41 const std::optional<GPUVAddr> gpu_addr{FindFreeBlock(0, size, PAGE_SIZE, PageStatus::Unmapped)};
38 ASSERT(gpu_addr); 42
43 ASSERT_MSG(gpu_addr, "unable to find available GPU memory");
39 44
40 for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { 45 for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
41 VAddr& slot = PageSlot(*gpu_addr + offset); 46 VAddr& slot{PageSlot(*gpu_addr + offset)};
42 47
43 ASSERT(slot == static_cast<u64>(PageStatus::Unmapped)); 48 ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
49
44 slot = cpu_addr + offset; 50 slot = cpu_addr + offset;
45 } 51 }
46 52
47 MappedRegion region{cpu_addr, *gpu_addr, size}; 53 const MappedRegion region{cpu_addr, *gpu_addr, size};
48 mapped_regions.push_back(region); 54 mapped_regions.push_back(region);
49 55
50 return *gpu_addr; 56 return *gpu_addr;
@@ -53,14 +59,31 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) {
53GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size) { 59GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size) {
54 ASSERT((gpu_addr & PAGE_MASK) == 0); 60 ASSERT((gpu_addr & PAGE_MASK) == 0);
55 61
56 for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { 62 if (PageSlot(gpu_addr) != static_cast<u64>(PageStatus::Allocated)) {
57 VAddr& slot = PageSlot(gpu_addr + offset); 63 // Page has been already mapped. In this case, we must find a new area of memory to use that
64 // is different than the specified one. Super Mario Odyssey hits this scenario when changing
65 // areas, but we do not want to overwrite the old pages.
66 // TODO(bunnei): We need to write a hardware test to confirm this behavior.
67
68 LOG_ERROR(HW_GPU, "attempting to map addr 0x{:016X}, which is not available!", gpu_addr);
69
70 const std::optional<GPUVAddr> new_gpu_addr{
71 FindFreeBlock(gpu_addr, size, PAGE_SIZE, PageStatus::Allocated)};
72
73 ASSERT_MSG(new_gpu_addr, "unable to find available GPU memory");
74
75 gpu_addr = *new_gpu_addr;
76 }
77
78 for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
79 VAddr& slot{PageSlot(gpu_addr + offset)};
58 80
59 ASSERT(slot == static_cast<u64>(PageStatus::Allocated)); 81 ASSERT(slot == static_cast<u64>(PageStatus::Allocated));
82
60 slot = cpu_addr + offset; 83 slot = cpu_addr + offset;
61 } 84 }
62 85
63 MappedRegion region{cpu_addr, gpu_addr, size}; 86 const MappedRegion region{cpu_addr, gpu_addr, size};
64 mapped_regions.push_back(region); 87 mapped_regions.push_back(region);
65 88
66 return gpu_addr; 89 return gpu_addr;
@@ -69,11 +92,12 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size)
69GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) { 92GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
70 ASSERT((gpu_addr & PAGE_MASK) == 0); 93 ASSERT((gpu_addr & PAGE_MASK) == 0);
71 94
72 for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { 95 for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
73 VAddr& slot = PageSlot(gpu_addr + offset); 96 VAddr& slot{PageSlot(gpu_addr + offset)};
74 97
75 ASSERT(slot != static_cast<u64>(PageStatus::Allocated) && 98 ASSERT(slot != static_cast<u64>(PageStatus::Allocated) &&
76 slot != static_cast<u64>(PageStatus::Unmapped)); 99 slot != static_cast<u64>(PageStatus::Unmapped));
100
77 slot = static_cast<u64>(PageStatus::Unmapped); 101 slot = static_cast<u64>(PageStatus::Unmapped);
78 } 102 }
79 103
@@ -97,13 +121,14 @@ GPUVAddr MemoryManager::GetRegionEnd(GPUVAddr region_start) const {
97 return {}; 121 return {};
98} 122}
99 123
100std::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) { 124std::optional<GPUVAddr> MemoryManager::FindFreeBlock(GPUVAddr region_start, u64 size, u64 align,
101 GPUVAddr gpu_addr = 0; 125 PageStatus status) {
102 u64 free_space = 0; 126 GPUVAddr gpu_addr{region_start};
127 u64 free_space{};
103 align = (align + PAGE_MASK) & ~PAGE_MASK; 128 align = (align + PAGE_MASK) & ~PAGE_MASK;
104 129
105 while (gpu_addr + free_space < MAX_ADDRESS) { 130 while (gpu_addr + free_space < MAX_ADDRESS) {
106 if (!IsPageMapped(gpu_addr + free_space)) { 131 if (PageSlot(gpu_addr + free_space) == static_cast<u64>(status)) {
107 free_space += PAGE_SIZE; 132 free_space += PAGE_SIZE;
108 if (free_space >= size) { 133 if (free_space >= size) {
109 return gpu_addr; 134 return gpu_addr;
@@ -119,7 +144,7 @@ std::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
119} 144}
120 145
121std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) { 146std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) {
122 VAddr base_addr = PageSlot(gpu_addr); 147 const VAddr base_addr{PageSlot(gpu_addr)};
123 148
124 if (base_addr == static_cast<u64>(PageStatus::Allocated) || 149 if (base_addr == static_cast<u64>(PageStatus::Allocated) ||
125 base_addr == static_cast<u64>(PageStatus::Unmapped)) { 150 base_addr == static_cast<u64>(PageStatus::Unmapped)) {
@@ -133,19 +158,15 @@ std::vector<GPUVAddr> MemoryManager::CpuToGpuAddress(VAddr cpu_addr) const {
133 std::vector<GPUVAddr> results; 158 std::vector<GPUVAddr> results;
134 for (const auto& region : mapped_regions) { 159 for (const auto& region : mapped_regions) {
135 if (cpu_addr >= region.cpu_addr && cpu_addr < (region.cpu_addr + region.size)) { 160 if (cpu_addr >= region.cpu_addr && cpu_addr < (region.cpu_addr + region.size)) {
136 u64 offset = cpu_addr - region.cpu_addr; 161 const u64 offset{cpu_addr - region.cpu_addr};
137 results.push_back(region.gpu_addr + offset); 162 results.push_back(region.gpu_addr + offset);
138 } 163 }
139 } 164 }
140 return results; 165 return results;
141} 166}
142 167
143bool MemoryManager::IsPageMapped(GPUVAddr gpu_addr) {
144 return PageSlot(gpu_addr) != static_cast<u64>(PageStatus::Unmapped);
145}
146
147VAddr& MemoryManager::PageSlot(GPUVAddr gpu_addr) { 168VAddr& MemoryManager::PageSlot(GPUVAddr gpu_addr) {
148 auto& block = page_table[(gpu_addr >> (PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK]; 169 auto& block{page_table[(gpu_addr >> (PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK]};
149 if (!block) { 170 if (!block) {
150 block = std::make_unique<PageBlock>(); 171 block = std::make_unique<PageBlock>();
151 block->fill(static_cast<VAddr>(PageStatus::Unmapped)); 172 block->fill(static_cast<VAddr>(PageStatus::Unmapped));
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index b1255fd56..4eb338aa2 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -34,15 +34,15 @@ public:
34 static constexpr u64 PAGE_MASK = PAGE_SIZE - 1; 34 static constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
35 35
36private: 36private:
37 std::optional<GPUVAddr> FindFreeBlock(u64 size, u64 align = 1);
38 bool IsPageMapped(GPUVAddr gpu_addr);
39 VAddr& PageSlot(GPUVAddr gpu_addr);
40
41 enum class PageStatus : u64 { 37 enum class PageStatus : u64 {
42 Unmapped = 0xFFFFFFFFFFFFFFFFULL, 38 Unmapped = 0xFFFFFFFFFFFFFFFFULL,
43 Allocated = 0xFFFFFFFFFFFFFFFEULL, 39 Allocated = 0xFFFFFFFFFFFFFFFEULL,
44 }; 40 };
45 41
42 std::optional<GPUVAddr> FindFreeBlock(GPUVAddr region_start, u64 size, u64 align,
43 PageStatus status);
44 VAddr& PageSlot(GPUVAddr gpu_addr);
45
46 static constexpr u64 MAX_ADDRESS{0x10000000000ULL}; 46 static constexpr u64 MAX_ADDRESS{0x10000000000ULL};
47 static constexpr u64 PAGE_TABLE_BITS{10}; 47 static constexpr u64 PAGE_TABLE_BITS{10};
48 static constexpr u64 PAGE_TABLE_SIZE{1 << PAGE_TABLE_BITS}; 48 static constexpr u64 PAGE_TABLE_SIZE{1 << PAGE_TABLE_BITS};