Vulkan BDA debugging force m_BufferAddresses to be sorted

The implementation usage of m_BufferAddresses assumes the container is sorted and requires the use of lower_bound() API

Added rdcsortedflatmap subclass of rdcflatmap
Only expose upper_bound(), lower_bound() APIs in rdcsortedflatmap
The upper/lower bound APIs require a sorted container
This commit is contained in:
Jake Turner
2024-02-13 13:56:02 +00:00
parent 52cfb0e083
commit a62634717e
4 changed files with 111 additions and 68 deletions
+91 -53
View File
@@ -1,3 +1,27 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2019-2024 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#pragma once
#include <algorithm>
@@ -126,35 +150,6 @@ struct rdcflatmap
return {(begin() + idx), inserted};
}
iterator upper_bound(const Key &key)
{
if(!sorted)
sort();
size_t idx = lower_bound_idx(key);
// almost the same behaviour as lower_bound, except if we actually have the key, return the next
// element.
if(idx < size() && storage.at(idx).first == key)
return begin() + idx + 1;
return begin() + idx;
}
const_iterator upper_bound(const Key &key) const
{
size_t idx = lower_bound_idx(key);
// almost the same behaviour as lower_bound, except if we actually have the key, return the next
// element.
if(idx < size() && storage.at(idx).first == key)
return begin() + idx + 1;
return begin() + idx;
}
iterator lower_bound(const Key &key) { return begin() + lower_bound_idx(key); }
const_iterator lower_bound(const Key &key) const { return begin() + lower_bound_idx(key); }
iterator begin() { return storage.begin(); }
iterator end() { return storage.end(); }
const_iterator begin() const { return storage.begin(); }
@@ -167,8 +162,33 @@ struct rdcflatmap
storage.swap(other.storage);
}
void clear() { storage.clear(); }
private:
protected:
rdcarray<rdcpair<Key, Value>> storage;
size_t lower_bound_idx(const Key &id) const
{
// start looking at the whole range
size_t start = 0, sz = size();
// continue iterating until the range is empty
while(sz > 0)
{
const size_t halfsz = sz / 2;
const size_t mid = start + halfsz;
const Key comp = storage.at(mid).first;
if(comp < id)
{
start = mid + 1;
sz -= halfsz + 1;
}
else
{
sz = halfsz;
}
}
return start;
}
private:
bool sorted = (SortThreshold == 0);
void sort()
@@ -216,29 +236,6 @@ private:
return (begin() + idx)->second;
}
size_t lower_bound_idx(const Key &id) const
{
// start looking at the whole range
size_t start = 0, sz = size();
// continue iterating until the range is empty
while(sz > 0)
{
const size_t halfsz = sz / 2;
const size_t mid = start + halfsz;
const Key comp = storage.at(mid).first;
if(comp < id)
{
start = mid + 1;
sz -= halfsz + 1;
}
else
{
sz = halfsz;
}
}
return start;
}
iterator unsorted_find(const Key &id)
{
for(auto it = begin(); it != end(); ++it)
@@ -277,3 +274,44 @@ private:
return storage.back().second;
}
};
// a version of rdcflatmap which is guaranteed to be sorted
// adds upper_bound and lower_bound APIs
template <typename Key, typename Value>
struct rdcsortedflatmap : rdcflatmap<Key, Value, 0>
{
using iterator = rdcpair<Key, Value> *;
using const_iterator = const rdcpair<Key, Value> *;
using rdcflatmap<Key, Value, 0>::begin;
using rdcflatmap<Key, Value, 0>::size;
using rdcflatmap<Key, Value, 0>::storage;
using rdcflatmap<Key, Value, 0>::lower_bound_idx;
iterator upper_bound(const Key &key)
{
size_t idx = lower_bound_idx(key);
// almost the same behaviour as lower_bound, except if we actually have the key, return the next
// element.
if(idx < size() && storage.at(idx).first == key)
return begin() + idx + 1;
return begin() + idx;
}
const_iterator upper_bound(const Key &key) const
{
size_t idx = lower_bound_idx(key);
// almost the same behaviour as lower_bound, except if we actually have the key, return the next
// element.
if(idx < size() && storage.at(idx).first == key)
return begin() + idx + 1;
return begin() + idx;
}
iterator lower_bound(const Key &key) { return begin() + lower_bound_idx(key); }
const_iterator lower_bound(const Key &key) const { return begin() + lower_bound_idx(key); }
};
+1 -1
View File
@@ -162,7 +162,7 @@ template <typename T>
struct Intervals
{
public:
using MapType = rdcflatmap<uint64_t, T, 0>;
using MapType = rdcsortedflatmap<uint64_t, T>;
typedef IntervalRef<T, MapType, typename MapType::iterator> interval;
typedef IntervalsIter<T, MapType, typename MapType::iterator, interval> iterator;
+1 -1
View File
@@ -626,7 +626,7 @@ struct VulkanCreationInfo
VkMemoryRequirements mrq;
};
std::unordered_map<ResourceId, Buffer> m_Buffer;
rdcflatmap<uint64_t, ResourceId> m_BufferAddresses;
rdcsortedflatmap<uint64_t, ResourceId> m_BufferAddresses;
struct BufferView
{
+18 -13
View File
@@ -2243,10 +2243,23 @@ TEST_CASE("Test flatmap type", "[basictypes][flatmap]")
CHECK(test.find(5)->second == "foo");
};
SECTION("empty_map")
{
rdcflatmap<uint32_t, uint32_t> unsorted;
CHECK(unsorted.begin() == unsorted.end());
CHECK(unsorted.find(0) == unsorted.end());
rdcflatmap<uint32_t, uint32_t, 0> sorted;
CHECK(sorted.begin() == sorted.end());
CHECK(sorted.find(0) == sorted.end());
}
}
TEST_CASE("Test sorted flatmap type", "[basictypes][sortedflatmap]")
{
SECTION("upper_bound")
{
// set SortThreshold to 0 to force sorted semantics always
rdcflatmap<uint32_t, rdcstr, 0> test;
rdcsortedflatmap<uint32_t, rdcstr> test;
test[5] = "foo";
test[7] = "bar";
@@ -2292,17 +2305,9 @@ TEST_CASE("Test flatmap type", "[basictypes][flatmap]")
SECTION("empty_map")
{
rdcflatmap<uint32_t, uint32_t> unsorted;
CHECK(unsorted.begin() == unsorted.end());
CHECK(unsorted.find(0) == unsorted.end());
CHECK(unsorted.lower_bound(1) == 0);
CHECK(unsorted.upper_bound(2) == 0);
rdcflatmap<uint32_t, uint32_t, 0> sorted;
CHECK(sorted.begin() == sorted.end());
CHECK(sorted.find(0) == sorted.end());
CHECK(sorted.lower_bound(1) == 0);
CHECK(sorted.upper_bound(2) == 0);
rdcsortedflatmap<uint32_t, uint32_t> sortedflatmap;
CHECK(sortedflatmap.lower_bound(1) == 0);
CHECK(sortedflatmap.upper_bound(2) == 0);
}
};