9 changed files with 238 additions and 95 deletions
-
1src/common/CMakeLists.txt
-
139src/common/range_map.h
-
1src/tests/CMakeLists.txt
-
70src/tests/common/range_map.cpp
-
3src/video_core/dma_pusher.cpp
-
15src/video_core/engines/maxwell_3d.cpp
-
2src/video_core/engines/maxwell_3d.h
-
91src/video_core/memory_manager.cpp
-
11src/video_core/memory_manager.h
@ -0,0 +1,139 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project |
||||
|
// SPDX-License-Identifier: GPL-3.0-or-later |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <map> |
||||
|
#include <type_traits> |
||||
|
|
||||
|
#include "common/common_types.h" |
||||
|
|
||||
|
namespace Common { |
||||
|
|
||||
|
template <typename KeyTBase, typename ValueT> |
||||
|
class RangeMap { |
||||
|
private: |
||||
|
using KeyT = std::conditional_t<std::is_signed_v<KeyTBase>, typename KeyTBase, |
||||
|
std::make_signed_t<KeyTBase>>; |
||||
|
|
||||
|
public: |
||||
|
explicit RangeMap(ValueT null_value_) : null_value{null_value_} { |
||||
|
container.emplace(std::numeric_limits<KeyT>::min(), null_value); |
||||
|
}; |
||||
|
~RangeMap() = default; |
||||
|
|
||||
|
void Map(KeyTBase address, KeyTBase address_end, ValueT value) { |
||||
|
KeyT new_address = static_cast<KeyT>(address); |
||||
|
KeyT new_address_end = static_cast<KeyT>(address_end); |
||||
|
if (new_address < 0) { |
||||
|
new_address = 0; |
||||
|
} |
||||
|
if (new_address_end < 0) { |
||||
|
new_address_end = 0; |
||||
|
} |
||||
|
InternalMap(new_address, new_address_end, value); |
||||
|
} |
||||
|
|
||||
|
void Unmap(KeyTBase address, KeyTBase address_end) { |
||||
|
Map(address, address_end, null_value); |
||||
|
} |
||||
|
|
||||
|
[[nodiscard]] size_t GetContinousSizeFrom(KeyTBase address) const { |
||||
|
const KeyT new_address = static_cast<KeyT>(address); |
||||
|
if (new_address < 0) { |
||||
|
return 0; |
||||
|
} |
||||
|
return ContinousSizeInternal(new_address); |
||||
|
} |
||||
|
|
||||
|
[[nodiscard]] ValueT GetValueAt(KeyT address) const { |
||||
|
const KeyT new_address = static_cast<KeyT>(address); |
||||
|
if (new_address < 0) { |
||||
|
return null_value; |
||||
|
} |
||||
|
return GetValueInternal(new_address); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
using MapType = std::map<KeyT, ValueT>; |
||||
|
using IteratorType = MapType::iterator; |
||||
|
using ConstIteratorType = MapType::const_iterator; |
||||
|
|
||||
|
size_t ContinousSizeInternal(KeyT address) const { |
||||
|
const auto it = GetFirstElemnentBeforeOrOn(address); |
||||
|
if (it == container.end() || it->second == null_value) { |
||||
|
return 0; |
||||
|
} |
||||
|
const auto it_end = std::next(it); |
||||
|
if (it_end == container.end()) { |
||||
|
return std::numeric_limits<KeyT>::max() - address; |
||||
|
} |
||||
|
return it_end->first - address; |
||||
|
} |
||||
|
|
||||
|
ValueT GetValueInternal(KeyT address) const { |
||||
|
const auto it = GetFirstElemnentBeforeOrOn(address); |
||||
|
if (it == container.end()) { |
||||
|
return null_value; |
||||
|
} |
||||
|
return it->second; |
||||
|
} |
||||
|
|
||||
|
ConstIteratorType GetFirstElemnentBeforeOrOn(KeyT address) const { |
||||
|
auto it = container.lower_bound(address); |
||||
|
if (it == container.begin()) { |
||||
|
return it; |
||||
|
} |
||||
|
if (it != container.end() && (it->first == address)) { |
||||
|
return it; |
||||
|
} |
||||
|
--it; |
||||
|
return it; |
||||
|
} |
||||
|
|
||||
|
ValueT GetFirstValueWithin(KeyT address) { |
||||
|
auto it = container.lower_bound(address); |
||||
|
if (it == container.begin()) { |
||||
|
return it->second; |
||||
|
} |
||||
|
if (it == container.end()) [[unlikely]] { // this would be a bug |
||||
|
return null_value; |
||||
|
} |
||||
|
--it; |
||||
|
return it->second; |
||||
|
} |
||||
|
|
||||
|
ValueT GetLastValueWithin(KeyT address) { |
||||
|
auto it = container.upper_bound(address); |
||||
|
if (it == container.end()) { |
||||
|
return null_value; |
||||
|
} |
||||
|
if (it == container.begin()) [[unlikely]] { // this would be a bug |
||||
|
return it->second; |
||||
|
} |
||||
|
--it; |
||||
|
return it->second; |
||||
|
} |
||||
|
|
||||
|
void InternalMap(KeyT address, KeyT address_end, ValueT value) { |
||||
|
const bool must_add_start = GetFirstValueWithin(address) != value; |
||||
|
const ValueT last_value = GetLastValueWithin(address_end); |
||||
|
const bool must_add_end = last_value != value; |
||||
|
auto it = container.lower_bound(address); |
||||
|
const auto it_end = container.upper_bound(address_end); |
||||
|
while (it != it_end) { |
||||
|
it = container.erase(it); |
||||
|
} |
||||
|
if (must_add_start) { |
||||
|
container.emplace(address, value); |
||||
|
} |
||||
|
if (must_add_end) { |
||||
|
container.emplace(address_end, last_value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
ValueT null_value; |
||||
|
MapType container; |
||||
|
}; |
||||
|
|
||||
|
} // namespace Common |
||||
@ -0,0 +1,70 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
|
||||
|
#include <stdexcept>
|
||||
|
|
||||
|
#include <catch2/catch.hpp>
|
||||
|
|
||||
|
#include "common/range_map.h"
|
||||
|
|
||||
|
enum class MappedEnum : u32 { |
||||
|
Invalid = 0, |
||||
|
Valid_1 = 1, |
||||
|
Valid_2 = 2, |
||||
|
Valid_3 = 3, |
||||
|
}; |
||||
|
|
||||
|
TEST_CASE("Range Map: Setup", "[video_core]") { |
||||
|
Common::RangeMap<u64, MappedEnum> my_map(MappedEnum::Invalid); |
||||
|
my_map.Map(3000, 3500, MappedEnum::Valid_1); |
||||
|
my_map.Unmap(3200, 3600); |
||||
|
my_map.Map(4000, 4500, MappedEnum::Valid_2); |
||||
|
my_map.Map(4200, 4400, MappedEnum::Valid_2); |
||||
|
my_map.Map(4200, 4400, MappedEnum::Valid_1); |
||||
|
REQUIRE(my_map.GetContinousSizeFrom(4200) == 200); |
||||
|
REQUIRE(my_map.GetContinousSizeFrom(3000) == 200); |
||||
|
REQUIRE(my_map.GetContinousSizeFrom(2900) == 0); |
||||
|
|
||||
|
REQUIRE(my_map.GetValueAt(2900) == MappedEnum::Invalid); |
||||
|
REQUIRE(my_map.GetValueAt(3100) == MappedEnum::Valid_1); |
||||
|
REQUIRE(my_map.GetValueAt(3000) == MappedEnum::Valid_1); |
||||
|
REQUIRE(my_map.GetValueAt(3200) == MappedEnum::Invalid); |
||||
|
|
||||
|
REQUIRE(my_map.GetValueAt(4199) == MappedEnum::Valid_2); |
||||
|
REQUIRE(my_map.GetValueAt(4200) == MappedEnum::Valid_1); |
||||
|
REQUIRE(my_map.GetValueAt(4400) == MappedEnum::Valid_2); |
||||
|
REQUIRE(my_map.GetValueAt(4500) == MappedEnum::Invalid); |
||||
|
REQUIRE(my_map.GetValueAt(4600) == MappedEnum::Invalid); |
||||
|
|
||||
|
my_map.Unmap(0, 6000); |
||||
|
for (u64 address = 0; address < 10000; address += 1000) { |
||||
|
REQUIRE(my_map.GetContinousSizeFrom(address) == 0); |
||||
|
} |
||||
|
|
||||
|
my_map.Map(1000, 3000, MappedEnum::Valid_1); |
||||
|
my_map.Map(4000, 5000, MappedEnum::Valid_1); |
||||
|
my_map.Map(2500, 4100, MappedEnum::Valid_1); |
||||
|
REQUIRE(my_map.GetContinousSizeFrom(1000) == 4000); |
||||
|
|
||||
|
my_map.Map(1000, 3000, MappedEnum::Valid_1); |
||||
|
my_map.Map(4000, 5000, MappedEnum::Valid_2); |
||||
|
my_map.Map(2500, 4100, MappedEnum::Valid_3); |
||||
|
REQUIRE(my_map.GetContinousSizeFrom(1000) == 1500); |
||||
|
REQUIRE(my_map.GetContinousSizeFrom(2500) == 1600); |
||||
|
REQUIRE(my_map.GetContinousSizeFrom(4100) == 900); |
||||
|
REQUIRE(my_map.GetValueAt(900) == MappedEnum::Invalid); |
||||
|
REQUIRE(my_map.GetValueAt(1000) == MappedEnum::Valid_1); |
||||
|
REQUIRE(my_map.GetValueAt(2500) == MappedEnum::Valid_3); |
||||
|
REQUIRE(my_map.GetValueAt(4100) == MappedEnum::Valid_2); |
||||
|
REQUIRE(my_map.GetValueAt(5000) == MappedEnum::Invalid); |
||||
|
|
||||
|
my_map.Map(2000, 6000, MappedEnum::Valid_3); |
||||
|
REQUIRE(my_map.GetContinousSizeFrom(1000) == 1000); |
||||
|
REQUIRE(my_map.GetContinousSizeFrom(3000) == 3000); |
||||
|
REQUIRE(my_map.GetValueAt(1000) == MappedEnum::Valid_1); |
||||
|
REQUIRE(my_map.GetValueAt(1999) == MappedEnum::Valid_1); |
||||
|
REQUIRE(my_map.GetValueAt(1500) == MappedEnum::Valid_1); |
||||
|
REQUIRE(my_map.GetValueAt(2001) == MappedEnum::Valid_3); |
||||
|
REQUIRE(my_map.GetValueAt(5999) == MappedEnum::Valid_3); |
||||
|
REQUIRE(my_map.GetValueAt(6000) == MappedEnum::Invalid); |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue