jabyengine/include/PSX/GPU/Primitives/linked_elements.hpp

113 lines
3.5 KiB
C++

#pragma once
#include "../../Auxiliary/bits.hpp"
#include "../../Auxiliary/type_traits.hpp"
#include "../../System/IOPorts/gpu_io.hpp"
namespace JabyEngine {
namespace GPU {
struct Link {
static constexpr auto AdrRange = BitRange::from_to(0, 23);
static constexpr auto SizeRange = BitRange::from_to(24, 31);
static constexpr uint32_t TerminationValue = 0x00FFFFFF;
static constexpr uint32_t default_link_value(size_t size) {
return SizeRange.as_value(size >> 2) | TerminationValue;
}
uint32_t link_value;
constexpr void set_link_identitiy(size_t size) {
this->link_value = default_link_value(size);
}
void set_adr(const void* adr) {
this->link_value = bit::value::set_normalized(this->link_value, AdrRange.with(reinterpret_cast<uint32_t>(adr)));
}
void* get_adr() const {
return reinterpret_cast<void*>(bit::value::get_normalized(this->link_value, AdrRange));
}
template<typename T>
T& insert_after(T& obj) {
const auto adr = Link::get_adr();
Link::set_adr(&obj);
obj.set_adr(adr);
return obj;
}
template<typename T>
enable_if<!is_pointer<T>::value, Link&>::type concat(T& obj) {
Link::set_adr(&obj);
return *this;
}
template<typename T>
enable_if<!is_pointer<T>::value, const Link&>::type concat(const T& obj) {
return concat(const_cast<Link&>(obj));
}
constexpr void terminate() {
this->link_value |= TerminationValue;
}
};
template<typename T>
struct LinkedElement : public Link {
T element;
static constexpr LinkedElement create(const T& element) {
LinkedElement new_element;
new_element.element = element;
new_element.set_link_identitiy();
return new_element;
}
constexpr void set_link_identitiy() {
Link::set_link_identitiy(sizeof(T));
}
constexpr const T* operator->() const {
return &this->element;
}
constexpr T* operator->() {
return &this->element;
}
static_assert((sizeof(T) >> 2) <= GPU_IO::FIFOWordSize);
};
namespace internal {
template<typename T>
struct LinkedElementCreator {
typedef LinkedElement<T> Linked;
constexpr LinkedElement<T> linked() {
return LinkedElement<T>::create(*static_cast<T*>(this));
}
};
}
namespace LinkHelper {
template<typename T>
static Link* link_array(Link* last_prim, T* elements, size_t length) {
for(size_t n = 0; n < length; n++) {
last_prim->concat(elements[n]);
last_prim = &elements[n];
}
last_prim->terminate();
return last_prim;
}
template<typename T, size_t N>
static Link* link_array(Link* last_prim, T(&elements)[N]) {
return link_array(last_prim, elements, N);
}
}
}
}