Browse Source

simplify the storage of subfaces

V2-integral-fix
Zhicheng Wang 3 days ago
parent
commit
6b218f9c53
  1. 4
      primitive_process/interface/data/data_center.hpp
  2. 6
      primitive_process/interface/data/data_type.hpp
  3. 4
      primitive_process/src/base/subface.cpp
  4. 16
      primitive_process/src/data/data_center.cpp
  5. 4597
      shared_module/container/detail/hive_detail.hpp
  6. 49
      shared_module/container/detail/refcount_hive/aligned_struct.hpp
  7. 27
      shared_module/container/detail/refcount_hive/misc.hpp
  8. 4490
      shared_module/container/detail/refcount_hive_detail.hpp
  9. 132
      shared_module/container/hashed_refcount_hive.hpp
  10. 71
      shared_module/container/wrapper/object_map.hpp
  11. 12
      shared_module/utils/pointer_wrapper.hpp

4
primitive_process/interface/data/data_center.hpp

@ -6,7 +6,7 @@
#include "primitive/simple/cylinder.hpp" #include "primitive/simple/cylinder.hpp"
template <typename Surface, typename Tag> template <typename Surface, typename Tag>
using surface_container_t = tagged_hashed_refcount_hive_mp<internal::paired_model_matrix_ptr_t, Surface, Tag>; using surface_container_t = tagged_flat_object_map_mp<internal::paired_model_matrix_ptr_t, Surface, Tag>;
using plane_container_t = surface_container_t<internal::plane_t, detail::plane_surface_tag>; using plane_container_t = surface_container_t<internal::plane_t, detail::plane_surface_tag>;
using sphere_container_t = surface_container_t<internal::sphere_face_t, detail::sphere_surface_tag>; using sphere_container_t = surface_container_t<internal::sphere_face_t, detail::sphere_surface_tag>;
@ -16,7 +16,7 @@ EXTERN_C struct PE_API primitive_data_center_t {
primitive_data_center_t() noexcept; primitive_data_center_t() noexcept;
~primitive_data_center_t() noexcept; ~primitive_data_center_t() noexcept;
hashed_refcount_hive_mp<internal::paired_model_matrix, internal::paired_model_matrix> transform_blocks{}; flat_object_map_mp<internal::paired_model_matrix, internal::paired_model_matrix> transform_blocks{};
// all other data depend on cached transform_blocks // all other data depend on cached transform_blocks
using surface_containers = std::variant<plane_container_t, sphere_container_t, cylinder_container_t>; using surface_containers = std::variant<plane_container_t, sphere_container_t, cylinder_container_t>;
std::array<surface_containers, static_cast<uint8_t>(surface_type::max_count)> surfaces{}; std::array<surface_containers, static_cast<uint8_t>(surface_type::max_count)> surfaces{};

6
primitive_process/interface/data/data_type.hpp

@ -1,9 +1,8 @@
#pragma once #pragma once
#include <math/eigen_alias.hpp> #include <math/eigen_alias.hpp>
#include <container/hashed_refcount_hive.hpp> #include <container/wrapper/object_map.hpp>
#include <utils/hash_ext.hpp> #include <utils/hash_ext.hpp>
#include <utils/pointer_wrapper.hpp>
namespace internal namespace internal
{ {
@ -60,9 +59,6 @@ const auto plane_to_z_pos_1_model_matrix_ptr = make_pointer_wrapper(hidden::plan
const auto plane_to_z_model_matrix_ptr = make_pointer_wrapper(hidden::plane_to_z_model_matrix); const auto plane_to_z_model_matrix_ptr = make_pointer_wrapper(hidden::plane_to_z_model_matrix);
const auto plane_to_z_neg_1_model_matrix_ptr = make_pointer_wrapper(hidden::plane_to_z_neg_1_model_matrix); const auto plane_to_z_neg_1_model_matrix_ptr = make_pointer_wrapper(hidden::plane_to_z_neg_1_model_matrix);
template <typename T>
using primitive_data_iterator = typename hive_mp<T>::iterator;
enum class transform_type : uint8_t { scale, rotation, translation }; enum class transform_type : uint8_t { scale, rotation, translation };
} // namespace internal } // namespace internal

4
primitive_process/src/base/subface.cpp

@ -38,6 +38,6 @@ internal::paired_model_matrix_ptr_t subface::apply_transform(internal::transform
default: throw std::invalid_argument("Invalid transform type"); default: throw std::invalid_argument("Invalid transform type");
} }
auto [iter, _] = data_center->transform_blocks.acquire(temp); auto [ptr, _] = data_center->transform_blocks.acquire(temp);
return make_pointer_wrapper(iter.operator->()); return ptr;
} }

16
primitive_process/src/data/data_center.cpp

@ -23,8 +23,8 @@ primitive_data_center_t::~primitive_data_center_t() noexcept
auto primitive_data_center_t::require_transform_block(const internal::paired_model_matrix& matrix) auto primitive_data_center_t::require_transform_block(const internal::paired_model_matrix& matrix)
-> internal::paired_model_matrix_ptr_t -> internal::paired_model_matrix_ptr_t
{ {
auto [iter, _] = this->transform_blocks.acquire(matrix); auto [ptr, _] = this->transform_blocks.acquire(matrix);
return make_pointer_wrapper(iter.operator->()); return ptr;
} }
void primitive_data_center_t::require_surface(surface_type type, void primitive_data_center_t::require_surface(surface_type type,
@ -34,22 +34,22 @@ void primitive_data_center_t::require_surface(surface_type
require_transform_block(matrix); require_transform_block(matrix);
switch (type) { switch (type) {
case surface_type::plane: { case surface_type::plane: {
auto [iter, is_new] = std::get<plane_container_t>(this->surfaces[static_cast<uint8_t>(type)]).acquire(matrix); auto [ptr, is_new] = std::get<plane_container_t>(this->surfaces[static_cast<uint8_t>(type)]).acquire(matrix);
subface.set_ptr(iter.operator->()); subface.set_ptr(ptr.raw());
subface.set_mark(false); subface.set_mark(false);
if (is_new) subface.get_ptr()->data_center = make_pointer_wrapper(this); if (is_new) subface.get_ptr()->data_center = make_pointer_wrapper(this);
break; break;
} }
case surface_type::sphere: { case surface_type::sphere: {
auto [iter, is_new] = std::get<sphere_container_t>(this->surfaces[static_cast<uint8_t>(type)]).acquire(matrix); auto [ptr, is_new] = std::get<sphere_container_t>(this->surfaces[static_cast<uint8_t>(type)]).acquire(matrix);
subface.set_ptr(iter.operator->()); subface.set_ptr(ptr.raw());
subface.set_mark(false); subface.set_mark(false);
if (is_new) subface.get_ptr()->data_center = make_pointer_wrapper(this); if (is_new) subface.get_ptr()->data_center = make_pointer_wrapper(this);
break; break;
} }
case surface_type::cylinder: { case surface_type::cylinder: {
auto [iter, is_new] = std::get<cylinder_container_t>(this->surfaces[static_cast<uint8_t>(type)]).acquire(matrix); auto [ptr, is_new] = std::get<cylinder_container_t>(this->surfaces[static_cast<uint8_t>(type)]).acquire(matrix);
subface.set_ptr(iter.operator->()); subface.set_ptr(ptr.raw());
subface.set_mark(false); subface.set_mark(false);
if (is_new) subface.get_ptr()->data_center = make_pointer_wrapper(this); if (is_new) subface.get_ptr()->data_center = make_pointer_wrapper(this);
break; break;

4597
shared_module/container/detail/hive_detail.hpp

File diff suppressed because it is too large

49
shared_module/container/detail/refcount_hive/aligned_struct.hpp

@ -1,49 +0,0 @@
#pragma once
namespace detail::refcount_hive
{
// The element as allocated in memory needs to be at-least 2*skipfield_type width in order to support free list indexes in
// erased element memory space, so: make the size of this struct the larger of alignof(T), sizeof(T) or 2*skipfield_type
// (the latter is only relevant for type char/uchar), and make the alignment alignof(T). This type is used mainly for
// correct pointer arithmetic while iterating over elements in memory.
template <typename element_type, typename skipfield_type, typename refcount_type>
struct alignas(alignof(element_type)) aligned_element_struct {
// Using char as sizeof is always guaranteed to be 1 byte regardless of the number of bits in a byte on given computer,
// whereas for example, uint8_t would fail on machines where there are more than 8 bits in a byte eg. Texas Instruments
// C54x DSPs.
char
data[(sizeof(element_type) < (sizeof(skipfield_type) * 2))
? ((sizeof(skipfield_type) * 2) < alignof(element_type) ? alignof(element_type) : (sizeof(skipfield_type) * 2))
: ((sizeof(element_type) < alignof(element_type)) ? alignof(element_type) : sizeof(element_type))];
};
// We combine the allocation of elements and skipfield into one allocation to save performance. This memory must be
// allocated as an aligned type with the same alignment as T in order for the elements to align with memory boundaries
// correctly (which won't happen if we allocate as char or uint_8). But the larger the sizeof in the type we use for
// allocation, the greater the chance of creating a lot of unused memory in the skipfield portion of the allocated block. So
// we create a type that is sizeof(alignof(T)), as in most cases alignof(T) < sizeof(T). If alignof(t) >= sizeof(t) this
// makes no difference.
template <typename element_type>
struct alignas(alignof(element_type)) aligned_allocation_struct {
char data[alignof(element_type)];
};
// Calculate the capacity of a group's elements+skipfield memory block when expressed in multiples of the value_type's
// alignment (rounding up).
template <typename element_type, typename skipfield_type, typename refcount_type>
static size_t get_aligned_block_capacity(const skipfield_type elements_per_group)
{
using aligned_element_struct = aligned_element_struct<element_type, skipfield_type, refcount_type>;
using aligned_allocation_struct = aligned_allocation_struct<element_type>;
return ((elements_per_group * (sizeof(aligned_element_struct) + sizeof(skipfield_type))) + sizeof(skipfield_type)
+ sizeof(aligned_allocation_struct) - 1)
/ sizeof(aligned_allocation_struct);
}
// To enable conversion when allocator supplies non-raw pointers:
template <class destination_pointer_type, class source_pointer_type>
static constexpr destination_pointer_type pointer_cast(const source_pointer_type source_pointer) noexcept
{
return destination_pointer_type(&*source_pointer);
}
} // namespace detail::refcount_hive

27
shared_module/container/detail/refcount_hive/misc.hpp

@ -1,27 +0,0 @@
#pragma once
#include <memory>
namespace detail::refcount_hive
{
// To enable conversion to void * when allocator supplies non-raw pointers:
template <class source_pointer_type>
static constexpr void *void_cast(const source_pointer_type source_pointer) noexcept
{
return static_cast<void *>(&*source_pointer);
}
template <class iterator_type>
static constexpr std::move_iterator<iterator_type> make_move_iterator(iterator_type it)
{
return std::move_iterator<iterator_type>(std::move(it));
}
enum class priority { performance = 1, memory_use = 4 };
struct limits {
size_t min, max;
constexpr limits(const size_t minimum, const size_t maximum) noexcept : min(minimum), max(maximum) {}
};
} // namespace detail::refcount_hive

4490
shared_module/container/detail/refcount_hive_detail.hpp

File diff suppressed because it is too large

132
shared_module/container/hashed_refcount_hive.hpp

@ -1,132 +0,0 @@
#pragma once
#include "hive.hpp"
#include "hashmap.hpp"
namespace detail
{
template <typename K>
struct hasher {
size_t operator()(const K& k) const;
};
// template <typename K>
// struct eq_compare
// {
// bool operator()(const K& lhs, const K& rhs) const;
// };
template <typename K, typename V>
struct default_elem_ctor {
V operator()(const K& k) const;
};
template <typename K, typename V, typename Allocator = std::allocator<V>>
struct hashed_refcount_hive {
using iterator = typename hive<V, Allocator>::iterator;
public:
std::pair<iterator, bool> acquire(const K& key)
{
size_t hash_key = hasher<K>()(key);
auto iter = refcount_data_map.find(hash_key);
if (iter == refcount_data_map.end()) {
auto data_iter = data.emplace(default_elem_ctor<K, V>{}(key));
refcount_data_map.emplace(hash_key, std::make_pair(1, data_iter));
return {data_iter, true};
} else {
iter->second.first += 1;
return {iter->second.second, false};
}
}
void release(const K& key)
{
size_t hash_key = hasher<K>()(key);
auto iter = refcount_data_map.find(hash_key);
if (iter == refcount_data_map.end()) throw std::runtime_error("Key not found in refcount map.");
if (--iter->second.first == 0) {
data.erase(iter->second.second);
refcount_data_map.erase(iter);
}
}
void release(const iterator& ptr)
{
for (auto iter = refcount_data_map.begin(); iter != refcount_data_map.end(); ++iter) {
if (iter->second.second == ptr) {
if (--iter->second.first == 0) {
data.erase(iter->second.second);
refcount_data_map.erase(iter);
}
return;
}
}
throw std::runtime_error("Pointer not found in refcount map.");
}
protected:
hive<V, Allocator> data{};
// manually calculate hash for the key, so that we do not need to store the key
flat_hash_map<size_t, std::pair<size_t, iterator>> refcount_data_map{};
};
template <typename T, typename Tag>
struct tagged_hasher;
template <typename K, typename V, typename Tag, typename Allocator = std::allocator<V>>
struct tagged_hashed_refcount_hive {
using iterator = typename hive<V, Allocator>::iterator;
public:
std::pair<iterator, bool> acquire(const K& key)
{
size_t hash_key = tagged_hasher<K, Tag>()(key);
auto iter = refcount_data_map.find(hash_key);
if (iter == refcount_data_map.end()) {
auto data_iter = data.emplace(default_elem_ctor<K, V>{}(key));
refcount_data_map.emplace(hash_key, std::make_pair(1, data_iter));
return {data_iter, true};
} else {
iter->second.first += 1;
return {iter->second.second, false};
}
}
void release(const K& key)
{
size_t hash_key = tagged_hasher<K, Tag>()(key);
auto iter = refcount_data_map.find(hash_key);
if (iter == refcount_data_map.end()) throw std::runtime_error("Key not found in refcount map.");
if (--iter->second.first == 0) {
data.erase(iter->second.second);
refcount_data_map.erase(iter);
}
}
void release(const iterator& ptr)
{
for (auto iter = refcount_data_map.begin(); iter != refcount_data_map.end(); ++iter) {
if (iter->second.second == ptr) {
if (--iter->second.first == 0) {
data.erase(iter->second.second);
refcount_data_map.erase(iter);
}
return;
}
}
throw std::runtime_error("Pointer not found in refcount map.");
}
protected:
hive<V, Allocator> data{};
// manually calculate hash for the key, so that we do not need to store the key
flat_hash_map<size_t, std::pair<size_t, iterator>> refcount_data_map{};
};
} // namespace detail
template <typename K, typename V>
using hashed_refcount_hive_mp = detail::hashed_refcount_hive<K, V, mi_stl_allocator<V>>;
template <typename K, typename V, typename Tag>
using tagged_hashed_refcount_hive_mp = detail::tagged_hashed_refcount_hive<K, V, Tag, mi_stl_allocator<V>>;

71
shared_module/container/wrapper/object_map.hpp

@ -0,0 +1,71 @@
#include <container/hashmap.hpp>
#include <utils/pointer_wrapper.hpp>
namespace detail
{
template <typename K>
struct hasher {
size_t operator()(const K& k) const;
};
template <typename K, typename Tag>
struct tagged_hasher {
size_t operator()(const K& k) const;
};
template <typename K>
struct eq_compare {
bool operator()(const K& lhs, const K& rhs) const { return lhs == rhs; }
};
template <typename K, typename V>
struct default_elem_ctor {
V operator()(const K& k) const;
};
template <typename K, typename V, typename Hasher = hasher<K>, template <typename> typename Allocator = std::allocator>
struct flat_object_map {
using value_pointer_t = pointer_wrapper<V>;
std::pair<value_pointer_t, bool> acquire(const K& key)
{
auto [iter, is_new] = data.try_emplace(key, object_with_refcount{});
auto& value = iter->second;
if (is_new) {
value.refcount = 1;
value.object_pointer = mi_aligned_alloc(alignof(V), sizeof(V));
if constexpr (std::is_same_v<V, K>)
*value.object_pointer = key;
else
*value.object_pointer = std::move(default_elem_ctor<K, V>{}(key));
return {value.object_pointer, true};
} else {
value.refcount++;
return {value.object_pointer, false};
}
}
void release(const K& key)
{
if (auto iter = data.find(key); iter == data.end()) {
throw std::runtime_error("Key not found in refcount map.");
} else if (--iter->second.refcount == 0) {
data.erase(iter);
}
}
protected:
struct object_with_refcount {
size_t refcount{};
value_pointer_t object_pointer{};
};
flat_hash_map<K, object_with_refcount, Hasher, eq_compare<K>, Allocator<std::pair<const K, V>>> data{};
};
} // namespace detail
template <typename K, typename V>
using flat_object_map_mp = detail::flat_object_map<K, V, detail::hasher<K>, mi_stl_allocator>;
template <typename K, typename V, typename Tag>
using tagged_flat_object_map_mp = detail::flat_object_map<K, V, detail::tagged_hasher<K, Tag>, mi_stl_allocator>;

12
shared_module/utils/pointer_wrapper.hpp

@ -3,31 +3,39 @@
#include <type_traits> #include <type_traits>
template <typename T> template <typename T>
struct pointer_wrapper{ struct alignas(8) pointer_wrapper {
static_assert(std::is_object_v<T>, "T must be an object type"); static_assert(std::is_object_v<T>, "T must be an object type");
pointer_wrapper() noexcept = default; pointer_wrapper() noexcept = default;
explicit pointer_wrapper(T* p) noexcept : ptr(p) {} explicit pointer_wrapper(T* p) noexcept : ptr(p) {}
explicit pointer_wrapper(T&& x) noexcept explicit pointer_wrapper(T&& x) noexcept
{ {
T& ref = std::forward<T&&>(x); T& ref = std::forward<T&&>(x);
ptr = std::addressof(ref); ptr = std::addressof(ref);
} }
T& get() const noexcept { return *ptr; } T& get() const noexcept { return *ptr; }
auto operator->() const noexcept { return ptr; } auto operator->() const noexcept { return ptr; }
operator T&() const noexcept { return *ptr; } operator T&() const noexcept { return *ptr; }
auto operator*() const noexcept { return *ptr; } auto operator*() const noexcept { return *ptr; }
auto operator*() noexcept { return *ptr; } auto operator*() noexcept { return *ptr; }
T copy() const noexcept { return *ptr; } T copy() const noexcept { return *ptr; }
auto raw() const noexcept -> T* { return ptr; } auto raw() const noexcept -> T* { return ptr; }
operator bool() const noexcept { return ptr != nullptr; } operator bool() const noexcept { return ptr != nullptr; }
void clear() noexcept { ptr = nullptr; } void clear() noexcept { ptr = nullptr; }
bool operator==(const pointer_wrapper<T>& other) const noexcept { return ptr == other.ptr; } bool operator==(const pointer_wrapper<T>& other) const noexcept { return ptr == other.ptr; }
bool operator!=(const pointer_wrapper<T>& other) const noexcept { return ptr != other.ptr; } bool operator!=(const pointer_wrapper<T>& other) const noexcept { return ptr != other.ptr; }
private: private:

Loading…
Cancel
Save