summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/range_map.h139
-rw-r--r--src/tests/CMakeLists.txt1
-rw-r--r--src/tests/common/range_map.cpp70
-rw-r--r--src/video_core/dma_pusher.cpp3
-rw-r--r--src/video_core/engines/maxwell_3d.cpp15
-rw-r--r--src/video_core/engines/maxwell_3d.h2
-rw-r--r--src/video_core/memory_manager.cpp91
-rw-r--r--src/video_core/memory_manager.h11
9 files changed, 238 insertions, 95 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index eb05e46a8..45332cf95 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -97,6 +97,7 @@ add_library(common STATIC
97 point.h 97 point.h
98 precompiled_headers.h 98 precompiled_headers.h
99 quaternion.h 99 quaternion.h
100 range_map.h
100 reader_writer_queue.h 101 reader_writer_queue.h
101 ring_buffer.h 102 ring_buffer.h
102 ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp 103 ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp
diff --git a/src/common/range_map.h b/src/common/range_map.h
new file mode 100644
index 000000000..993e21643
--- /dev/null
+++ b/src/common/range_map.h
@@ -0,0 +1,139 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <map>
7#include <type_traits>
8
9#include "common/common_types.h"
10
11namespace Common {
12
13template <typename KeyTBase, typename ValueT>
14class RangeMap {
15private:
16 using KeyT = std::conditional_t<std::is_signed_v<KeyTBase>, typename KeyTBase,
17 std::make_signed_t<KeyTBase>>;
18
19public:
20 explicit RangeMap(ValueT null_value_) : null_value{null_value_} {
21 container.emplace(std::numeric_limits<KeyT>::min(), null_value);
22 };
23 ~RangeMap() = default;
24
25 void Map(KeyTBase address, KeyTBase address_end, ValueT value) {
26 KeyT new_address = static_cast<KeyT>(address);
27 KeyT new_address_end = static_cast<KeyT>(address_end);
28 if (new_address < 0) {
29 new_address = 0;
30 }
31 if (new_address_end < 0) {
32 new_address_end = 0;
33 }
34 InternalMap(new_address, new_address_end, value);
35 }
36
37 void Unmap(KeyTBase address, KeyTBase address_end) {
38 Map(address, address_end, null_value);
39 }
40
41 [[nodiscard]] size_t GetContinousSizeFrom(KeyTBase address) const {
42 const KeyT new_address = static_cast<KeyT>(address);
43 if (new_address < 0) {
44 return 0;
45 }
46 return ContinousSizeInternal(new_address);
47 }
48
49 [[nodiscard]] ValueT GetValueAt(KeyT address) const {
50 const KeyT new_address = static_cast<KeyT>(address);
51 if (new_address < 0) {
52 return null_value;
53 }
54 return GetValueInternal(new_address);
55 }
56
57private:
58 using MapType = std::map<KeyT, ValueT>;
59 using IteratorType = MapType::iterator;
60 using ConstIteratorType = MapType::const_iterator;
61
62 size_t ContinousSizeInternal(KeyT address) const {
63 const auto it = GetFirstElemnentBeforeOrOn(address);
64 if (it == container.end() || it->second == null_value) {
65 return 0;
66 }
67 const auto it_end = std::next(it);
68 if (it_end == container.end()) {
69 return std::numeric_limits<KeyT>::max() - address;
70 }
71 return it_end->first - address;
72 }
73
74 ValueT GetValueInternal(KeyT address) const {
75 const auto it = GetFirstElemnentBeforeOrOn(address);
76 if (it == container.end()) {
77 return null_value;
78 }
79 return it->second;
80 }
81
82 ConstIteratorType GetFirstElemnentBeforeOrOn(KeyT address) const {
83 auto it = container.lower_bound(address);
84 if (it == container.begin()) {
85 return it;
86 }
87 if (it != container.end() && (it->first == address)) {
88 return it;
89 }
90 --it;
91 return it;
92 }
93
94 ValueT GetFirstValueWithin(KeyT address) {
95 auto it = container.lower_bound(address);
96 if (it == container.begin()) {
97 return it->second;
98 }
99 if (it == container.end()) [[unlikely]] { // this would be a bug
100 return null_value;
101 }
102 --it;
103 return it->second;
104 }
105
106 ValueT GetLastValueWithin(KeyT address) {
107 auto it = container.upper_bound(address);
108 if (it == container.end()) {
109 return null_value;
110 }
111 if (it == container.begin()) [[unlikely]] { // this would be a bug
112 return it->second;
113 }
114 --it;
115 return it->second;
116 }
117
118 void InternalMap(KeyT address, KeyT address_end, ValueT value) {
119 const bool must_add_start = GetFirstValueWithin(address) != value;
120 const ValueT last_value = GetLastValueWithin(address_end);
121 const bool must_add_end = last_value != value;
122 auto it = container.lower_bound(address);
123 const auto it_end = container.upper_bound(address_end);
124 while (it != it_end) {
125 it = container.erase(it);
126 }
127 if (must_add_start) {
128 container.emplace(address, value);
129 }
130 if (must_add_end) {
131 container.emplace(address_end, last_value);
132 }
133 }
134
135 ValueT null_value;
136 MapType container;
137};
138
139} // namespace Common
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 6a4022e45..9b65e79cb 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -7,6 +7,7 @@ add_executable(tests
7 common/fibers.cpp 7 common/fibers.cpp
8 common/host_memory.cpp 8 common/host_memory.cpp
9 common/param_package.cpp 9 common/param_package.cpp
10 common/range_map.cpp
10 common/ring_buffer.cpp 11 common/ring_buffer.cpp
11 common/scratch_buffer.cpp 12 common/scratch_buffer.cpp
12 common/unique_function.cpp 13 common/unique_function.cpp
diff --git a/src/tests/common/range_map.cpp b/src/tests/common/range_map.cpp
new file mode 100644
index 000000000..5a4630a38
--- /dev/null
+++ b/src/tests/common/range_map.cpp
@@ -0,0 +1,70 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <stdexcept>
5
6#include <catch2/catch.hpp>
7
8#include "common/range_map.h"
9
10enum class MappedEnum : u32 {
11 Invalid = 0,
12 Valid_1 = 1,
13 Valid_2 = 2,
14 Valid_3 = 3,
15};
16
17TEST_CASE("Range Map: Setup", "[video_core]") {
18 Common::RangeMap<u64, MappedEnum> my_map(MappedEnum::Invalid);
19 my_map.Map(3000, 3500, MappedEnum::Valid_1);
20 my_map.Unmap(3200, 3600);
21 my_map.Map(4000, 4500, MappedEnum::Valid_2);
22 my_map.Map(4200, 4400, MappedEnum::Valid_2);
23 my_map.Map(4200, 4400, MappedEnum::Valid_1);
24 REQUIRE(my_map.GetContinousSizeFrom(4200) == 200);
25 REQUIRE(my_map.GetContinousSizeFrom(3000) == 200);
26 REQUIRE(my_map.GetContinousSizeFrom(2900) == 0);
27
28 REQUIRE(my_map.GetValueAt(2900) == MappedEnum::Invalid);
29 REQUIRE(my_map.GetValueAt(3100) == MappedEnum::Valid_1);
30 REQUIRE(my_map.GetValueAt(3000) == MappedEnum::Valid_1);
31 REQUIRE(my_map.GetValueAt(3200) == MappedEnum::Invalid);
32
33 REQUIRE(my_map.GetValueAt(4199) == MappedEnum::Valid_2);
34 REQUIRE(my_map.GetValueAt(4200) == MappedEnum::Valid_1);
35 REQUIRE(my_map.GetValueAt(4400) == MappedEnum::Valid_2);
36 REQUIRE(my_map.GetValueAt(4500) == MappedEnum::Invalid);
37 REQUIRE(my_map.GetValueAt(4600) == MappedEnum::Invalid);
38
39 my_map.Unmap(0, 6000);
40 for (u64 address = 0; address < 10000; address += 1000) {
41 REQUIRE(my_map.GetContinousSizeFrom(address) == 0);
42 }
43
44 my_map.Map(1000, 3000, MappedEnum::Valid_1);
45 my_map.Map(4000, 5000, MappedEnum::Valid_1);
46 my_map.Map(2500, 4100, MappedEnum::Valid_1);
47 REQUIRE(my_map.GetContinousSizeFrom(1000) == 4000);
48
49 my_map.Map(1000, 3000, MappedEnum::Valid_1);
50 my_map.Map(4000, 5000, MappedEnum::Valid_2);
51 my_map.Map(2500, 4100, MappedEnum::Valid_3);
52 REQUIRE(my_map.GetContinousSizeFrom(1000) == 1500);
53 REQUIRE(my_map.GetContinousSizeFrom(2500) == 1600);
54 REQUIRE(my_map.GetContinousSizeFrom(4100) == 900);
55 REQUIRE(my_map.GetValueAt(900) == MappedEnum::Invalid);
56 REQUIRE(my_map.GetValueAt(1000) == MappedEnum::Valid_1);
57 REQUIRE(my_map.GetValueAt(2500) == MappedEnum::Valid_3);
58 REQUIRE(my_map.GetValueAt(4100) == MappedEnum::Valid_2);
59 REQUIRE(my_map.GetValueAt(5000) == MappedEnum::Invalid);
60
61 my_map.Map(2000, 6000, MappedEnum::Valid_3);
62 REQUIRE(my_map.GetContinousSizeFrom(1000) == 1000);
63 REQUIRE(my_map.GetContinousSizeFrom(3000) == 3000);
64 REQUIRE(my_map.GetValueAt(1000) == MappedEnum::Valid_1);
65 REQUIRE(my_map.GetValueAt(1999) == MappedEnum::Valid_1);
66 REQUIRE(my_map.GetValueAt(1500) == MappedEnum::Valid_1);
67 REQUIRE(my_map.GetValueAt(2001) == MappedEnum::Valid_3);
68 REQUIRE(my_map.GetValueAt(5999) == MappedEnum::Valid_3);
69 REQUIRE(my_map.GetValueAt(6000) == MappedEnum::Invalid);
70}
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp
index 5ad40abaa..7a82355da 100644
--- a/src/video_core/dma_pusher.cpp
+++ b/src/video_core/dma_pusher.cpp
@@ -75,7 +75,8 @@ bool DmaPusher::Step() {
75 75
76 // Push buffer non-empty, read a word 76 // Push buffer non-empty, read a word
77 command_headers.resize_destructive(command_list_header.size); 77 command_headers.resize_destructive(command_list_header.size);
78 if (Settings::IsGPULevelExtreme()) { 78 constexpr u32 MacroRegistersStart = 0xE00;
79 if (dma_state.method < MacroRegistersStart) {
79 memory_manager.ReadBlock(dma_state.dma_get, command_headers.data(), 80 memory_manager.ReadBlock(dma_state.dma_get, command_headers.data(),
80 command_list_header.size * sizeof(u32)); 81 command_list_header.size * sizeof(u32));
81 } else { 82 } else {
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 50d8a94b1..a9fd6d960 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -157,6 +157,21 @@ void Maxwell3D::RefreshParameters() {
157 } 157 }
158} 158}
159 159
160bool Maxwell3D::AnyParametersDirty() {
161 size_t current_index = 0;
162 for (auto& segment : macro_segments) {
163 if (segment.first == 0) {
164 current_index += segment.second;
165 continue;
166 }
167 if (memory_manager.IsMemoryDirty(segment.first, sizeof(u32) * segment.second)) {
168 return true;
169 }
170 current_index += segment.second;
171 }
172 return false;
173}
174
160u32 Maxwell3D::GetMaxCurrentVertices() { 175u32 Maxwell3D::GetMaxCurrentVertices() {
161 u32 num_vertices = 0; 176 u32 num_vertices = 0;
162 for (size_t index = 0; index < Regs::NumVertexArrays; ++index) { 177 for (size_t index = 0; index < Regs::NumVertexArrays; ++index) {
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 397e88f67..cd996413c 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -3092,6 +3092,8 @@ public:
3092 3092
3093 void RefreshParameters(); 3093 void RefreshParameters();
3094 3094
3095 bool AnyParametersDirty();
3096
3095 u32 GetMaxCurrentVertices(); 3097 u32 GetMaxCurrentVertices();
3096 3098
3097 size_t EstimateIndexBufferSize(); 3099 size_t EstimateIndexBufferSize();
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 11e7d225e..4fcae9909 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -25,7 +25,8 @@ MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, u64
25 address_space_bits{address_space_bits_}, page_bits{page_bits_}, big_page_bits{big_page_bits_}, 25 address_space_bits{address_space_bits_}, page_bits{page_bits_}, big_page_bits{big_page_bits_},
26 entries{}, big_entries{}, page_table{address_space_bits, address_space_bits + page_bits - 38, 26 entries{}, big_entries{}, page_table{address_space_bits, address_space_bits + page_bits - 38,
27 page_bits != big_page_bits ? page_bits : 0}, 27 page_bits != big_page_bits ? page_bits : 0},
28 unique_identifier{unique_identifier_generator.fetch_add(1, std::memory_order_acq_rel)} { 28 kind_map{PTEKind::INVALID}, unique_identifier{unique_identifier_generator.fetch_add(
29 1, std::memory_order_acq_rel)} {
29 address_space_size = 1ULL << address_space_bits; 30 address_space_size = 1ULL << address_space_bits;
30 page_size = 1ULL << page_bits; 31 page_size = 1ULL << page_bits;
31 page_mask = page_size - 1ULL; 32 page_mask = page_size - 1ULL;
@@ -41,11 +42,7 @@ MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, u64
41 big_entries.resize(big_page_table_size / 32, 0); 42 big_entries.resize(big_page_table_size / 32, 0);
42 big_page_table_cpu.resize(big_page_table_size); 43 big_page_table_cpu.resize(big_page_table_size);
43 big_page_continous.resize(big_page_table_size / continous_bits, 0); 44 big_page_continous.resize(big_page_table_size / continous_bits, 0);
44 std::array<PTEKind, 32> kind_valus;
45 kind_valus.fill(PTEKind::INVALID);
46 big_kinds.resize(big_page_table_size / 32, kind_valus);
47 entries.resize(page_table_size / 32, 0); 45 entries.resize(page_table_size / 32, 0);
48 kinds.resize(page_table_size / 32, kind_valus);
49} 46}
50 47
51MemoryManager::~MemoryManager() = default; 48MemoryManager::~MemoryManager() = default;
@@ -83,38 +80,7 @@ void MemoryManager::SetEntry(size_t position, MemoryManager::EntryType entry) {
83} 80}
84 81
85PTEKind MemoryManager::GetPageKind(GPUVAddr gpu_addr) const { 82PTEKind MemoryManager::GetPageKind(GPUVAddr gpu_addr) const {
86 auto entry = GetEntry<true>(gpu_addr); 83 return kind_map.GetValueAt(gpu_addr);
87 if (entry == EntryType::Mapped || entry == EntryType::Reserved) [[likely]] {
88 return GetKind<true>(gpu_addr);
89 } else {
90 return GetKind<false>(gpu_addr);
91 }
92}
93
94template <bool is_big_page>
95PTEKind MemoryManager::GetKind(size_t position) const {
96 if constexpr (is_big_page) {
97 position = position >> big_page_bits;
98 const size_t sub_index = position % 32;
99 return big_kinds[position / 32][sub_index];
100 } else {
101 position = position >> page_bits;
102 const size_t sub_index = position % 32;
103 return kinds[position / 32][sub_index];
104 }
105}
106
107template <bool is_big_page>
108void MemoryManager::SetKind(size_t position, PTEKind kind) {
109 if constexpr (is_big_page) {
110 position = position >> big_page_bits;
111 const size_t sub_index = position % 32;
112 big_kinds[position / 32][sub_index] = kind;
113 } else {
114 position = position >> page_bits;
115 const size_t sub_index = position % 32;
116 kinds[position / 32][sub_index] = kind;
117 }
118} 84}
119 85
120inline bool MemoryManager::IsBigPageContinous(size_t big_page_index) const { 86inline bool MemoryManager::IsBigPageContinous(size_t big_page_index) const {
@@ -141,7 +107,6 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cp
141 const GPUVAddr current_gpu_addr = gpu_addr + offset; 107 const GPUVAddr current_gpu_addr = gpu_addr + offset;
142 [[maybe_unused]] const auto current_entry_type = GetEntry<false>(current_gpu_addr); 108 [[maybe_unused]] const auto current_entry_type = GetEntry<false>(current_gpu_addr);
143 SetEntry<false>(current_gpu_addr, entry_type); 109 SetEntry<false>(current_gpu_addr, entry_type);
144 SetKind<false>(current_gpu_addr, kind);
145 if (current_entry_type != entry_type) { 110 if (current_entry_type != entry_type) {
146 rasterizer->ModifyGPUMemory(unique_identifier, gpu_addr, page_size); 111 rasterizer->ModifyGPUMemory(unique_identifier, gpu_addr, page_size);
147 } 112 }
@@ -153,6 +118,7 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cp
153 } 118 }
154 remaining_size -= page_size; 119 remaining_size -= page_size;
155 } 120 }
121 kind_map.Map(gpu_addr, gpu_addr + size, kind);
156 return gpu_addr; 122 return gpu_addr;
157} 123}
158 124
@@ -164,7 +130,6 @@ GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr
164 const GPUVAddr current_gpu_addr = gpu_addr + offset; 130 const GPUVAddr current_gpu_addr = gpu_addr + offset;
165 [[maybe_unused]] const auto current_entry_type = GetEntry<true>(current_gpu_addr); 131 [[maybe_unused]] const auto current_entry_type = GetEntry<true>(current_gpu_addr);
166 SetEntry<true>(current_gpu_addr, entry_type); 132 SetEntry<true>(current_gpu_addr, entry_type);
167 SetKind<true>(current_gpu_addr, kind);
168 if (current_entry_type != entry_type) { 133 if (current_entry_type != entry_type) {
169 rasterizer->ModifyGPUMemory(unique_identifier, gpu_addr, big_page_size); 134 rasterizer->ModifyGPUMemory(unique_identifier, gpu_addr, big_page_size);
170 } 135 }
@@ -193,6 +158,7 @@ GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr
193 } 158 }
194 remaining_size -= big_page_size; 159 remaining_size -= big_page_size;
195 } 160 }
161 kind_map.Map(gpu_addr, gpu_addr + size, kind);
196 return gpu_addr; 162 return gpu_addr;
197} 163}
198 164
@@ -578,52 +544,7 @@ size_t MemoryManager::MaxContinousRange(GPUVAddr gpu_addr, size_t size) const {
578} 544}
579 545
580size_t MemoryManager::GetMemoryLayoutSize(GPUVAddr gpu_addr, size_t max_size) const { 546size_t MemoryManager::GetMemoryLayoutSize(GPUVAddr gpu_addr, size_t max_size) const {
581 PTEKind base_kind = GetPageKind(gpu_addr); 547 return kind_map.GetContinousSizeFrom(gpu_addr);
582 if (base_kind == PTEKind::INVALID) {
583 return 0;
584 }
585 size_t range_so_far = 0;
586 bool result{false};
587 auto fail = [&]([[maybe_unused]] std::size_t page_index, [[maybe_unused]] std::size_t offset,
588 std::size_t copy_amount) {
589 result = true;
590 return true;
591 };
592 auto short_check = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
593 PTEKind base_kind_other = GetKind<false>((page_index << page_bits) + offset);
594 if (base_kind != base_kind_other) {
595 result = true;
596 return true;
597 }
598 range_so_far += copy_amount;
599 if (range_so_far >= max_size) {
600 result = true;
601 return true;
602 }
603 return false;
604 };
605 auto big_check = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
606 PTEKind base_kind_other = GetKind<true>((page_index << big_page_bits) + offset);
607 if (base_kind != base_kind_other) {
608 result = true;
609 return true;
610 }
611 range_so_far += copy_amount;
612 if (range_so_far >= max_size) {
613 result = true;
614 return true;
615 }
616 return false;
617 };
618 auto check_short_pages = [&](std::size_t page_index, std::size_t offset,
619 std::size_t copy_amount) {
620 GPUVAddr base = (page_index << big_page_bits) + offset;
621 MemoryOperation<false>(base, copy_amount, short_check, fail, fail);
622 return result;
623 };
624 MemoryOperation<true>(gpu_addr, address_space_size - gpu_addr, big_check, fail,
625 check_short_pages);
626 return range_so_far;
627} 548}
628 549
629void MemoryManager::InvalidateRegion(GPUVAddr gpu_addr, size_t size) const { 550void MemoryManager::InvalidateRegion(GPUVAddr gpu_addr, size_t size) const {
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index ca22520d7..50043a8ae 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -10,6 +10,7 @@
10 10
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/multi_level_page_table.h" 12#include "common/multi_level_page_table.h"
13#include "common/range_map.h"
13#include "common/virtual_buffer.h" 14#include "common/virtual_buffer.h"
14#include "video_core/pte_kind.h" 15#include "video_core/pte_kind.h"
15 16
@@ -186,16 +187,8 @@ private:
186 template <bool is_big_page> 187 template <bool is_big_page>
187 inline void SetEntry(size_t position, EntryType entry); 188 inline void SetEntry(size_t position, EntryType entry);
188 189
189 std::vector<std::array<PTEKind, 32>> kinds;
190 std::vector<std::array<PTEKind, 32>> big_kinds;
191
192 template <bool is_big_page>
193 inline PTEKind GetKind(size_t position) const;
194
195 template <bool is_big_page>
196 inline void SetKind(size_t position, PTEKind kind);
197
198 Common::MultiLevelPageTable<u32> page_table; 190 Common::MultiLevelPageTable<u32> page_table;
191 Common::RangeMap<GPUVAddr, PTEKind> kind_map;
199 Common::VirtualBuffer<u32> big_page_table_cpu; 192 Common::VirtualBuffer<u32> big_page_table_cpu;
200 193
201 std::vector<u64> big_page_continous; 194 std::vector<u64> big_page_continous;