Works, but with memory leaks
This commit is contained in:
Vendored
+5
-5
@@ -12,7 +12,7 @@
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceRoot}/bin/Debug",
|
||||
"console": "internalConsole",
|
||||
"console": "integratedTerminal",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"setupCommands": [
|
||||
@@ -31,7 +31,7 @@
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceRoot}/bin/Debug",
|
||||
"console": "internalConsole",
|
||||
"console": "integratedTerminal",
|
||||
"environment": [],
|
||||
"symbolSearchPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.25.28610\\lib\\x64",
|
||||
"requireExactSource": false,
|
||||
@@ -51,7 +51,7 @@
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceRoot}/bin/Release",
|
||||
"console": "internalConsole",
|
||||
"console": "integratedTerminal",
|
||||
"environment": [],
|
||||
"symbolSearchPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.25.28610\\lib\\x64",
|
||||
"requireExactSource": false,
|
||||
@@ -70,7 +70,7 @@
|
||||
"program": "${workspaceRoot}/bin/Debug/Seele_unit_tests",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"console": "internalConsole",
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceRoot}/bin/Debug",
|
||||
"environment": [],
|
||||
},
|
||||
@@ -81,7 +81,7 @@
|
||||
"program": "${workspaceRoot}/bin/Debug/Seele_unit_tests.exe",
|
||||
"args": ["--detect_memory_leaks=15533"],
|
||||
"stopAtEntry": false,
|
||||
"console": "internalConsole",
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceRoot}/bin/Debug",
|
||||
"visualizerFile": "${workspaceRoot}/Seele.natvis",
|
||||
"environment": [],
|
||||
|
||||
+1
-1
@@ -111,7 +111,7 @@ add_subdirectory(src/)
|
||||
|
||||
if(MSVC)
|
||||
set(_CRT_SECURE_NO_WARNINGS)
|
||||
target_compile_options(Engine PRIVATE /Zi /MP)
|
||||
target_compile_options(Engine PRIVATE /Zi /MP /DEBUG:FASTLINK)
|
||||
else()
|
||||
target_compile_options(Engine PRIVATE -g -Wall -Wextra -Wno-delete-incomplete -pedantic -fcoroutines)
|
||||
endif()
|
||||
|
||||
@@ -33,13 +33,6 @@
|
||||
"settings": {
|
||||
"CMAKE_PLATFORM": "x64"
|
||||
}
|
||||
},
|
||||
"x86": {
|
||||
"short": "x86",
|
||||
"long": "x86 platform",
|
||||
"settings": {
|
||||
"CMAKE_PLATFORM": "x86"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,414 @@
|
||||
#pragma once
|
||||
#include "MinimalEngine.h"
|
||||
#include "Array.h"
|
||||
|
||||
namespace Seele
|
||||
{
|
||||
template<typename T, Allocator = std::pmr::polymorphic_allocator<T>>
|
||||
class RingBuffer
|
||||
{
|
||||
public:
|
||||
template <typename X>
|
||||
class IteratorBase
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using value_type = X;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using reference = X&;
|
||||
using pointer = X*;
|
||||
|
||||
IteratorBase(Array<T>& arr, size_t index)
|
||||
: arr(arr)
|
||||
, index(index)
|
||||
{
|
||||
}
|
||||
reference operator*() const
|
||||
{
|
||||
return arr[index];
|
||||
}
|
||||
pointer operator->() const
|
||||
{
|
||||
return &arr[index];
|
||||
}
|
||||
inline bool operator!=(const IteratorBase &other) const
|
||||
{
|
||||
return arr != other.arr && index != other.index;
|
||||
}
|
||||
inline bool operator==(const IteratorBase &other) const
|
||||
{
|
||||
return arr == other.arr && index == other.index;
|
||||
}
|
||||
inline int operator-(const IteratorBase &other) const
|
||||
{
|
||||
return (int)(index - other.index);
|
||||
}
|
||||
IteratorBase &operator++()
|
||||
{
|
||||
index = (index + 1) % arr.size();
|
||||
return *this;
|
||||
}
|
||||
IteratorBase &operator--()
|
||||
{
|
||||
index = (index + 1) % arr.size();
|
||||
return *this;
|
||||
}
|
||||
IteratorBase operator++(int)
|
||||
{
|
||||
IteratorBase tmp(*this);
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
IteratorBase operator--(int)
|
||||
{
|
||||
IteratorBase tmp(*this);
|
||||
--*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
Array<T, Allocator>& arr;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
using value_type = T;
|
||||
using allocator_type = Allocator;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
|
||||
using Iterator = IteratorBase<T>;
|
||||
using ConstIterator = IteratorBase<const T>;
|
||||
using iterator = Iterator;
|
||||
using const_iterator = ConstIterator;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
constexpr RingBuffer() noexcept(noexcept(Allocator()))
|
||||
{
|
||||
refreshIterators();
|
||||
}
|
||||
|
||||
constexpr explicit RingBuffer(const allocator_type& alloc)
|
||||
: data(alloc)
|
||||
{
|
||||
refreshIterators();
|
||||
}
|
||||
constexpr RingBuffer(size_type size, const value_type& value, const allocator_type& alloc = allocator_type())
|
||||
: data(size, value, alloc)
|
||||
, end(size)
|
||||
{
|
||||
refreshIterators();
|
||||
}
|
||||
constexpr explicit RingBuffer(size_type size, const allocator_type& alloc = allocator_type())
|
||||
: arraySize(size)
|
||||
, allocated(size)
|
||||
, allocator(alloc)
|
||||
{
|
||||
_data = allocateRingBuffer(size);
|
||||
assert(_data != nullptr);
|
||||
for (size_type i = 0; i < size; ++i)
|
||||
{
|
||||
std::allocator_traits<allocator_type>::construct(allocator, &_data[i]);
|
||||
}
|
||||
markIteratorDirty();
|
||||
}
|
||||
constexpr RingBuffer(std::initializer_list<T> init, const allocator_type& alloc = allocator_type())
|
||||
: arraySize(init.size())
|
||||
, allocated(init.size())
|
||||
, allocator(alloc)
|
||||
{
|
||||
_data = allocateRingBuffer(init.size());
|
||||
assert(_data != nullptr);
|
||||
markIteratorDirty();
|
||||
std::uninitialized_copy(init.begin(), init.end(), begin());
|
||||
}
|
||||
RingBuffer(const RingBuffer &other)
|
||||
: arraySize(other.arraySize)
|
||||
, allocated(other.allocated)
|
||||
, allocator(std::allocator_traits<allocator_type>::select_on_container_copy_construction(other.allocator))
|
||||
{
|
||||
_data = allocateRingBuffer(other.allocated);
|
||||
assert(_data != nullptr);
|
||||
markIteratorDirty();
|
||||
std::uninitialized_copy(other.begin(), other.end(), begin());
|
||||
}
|
||||
RingBuffer(RingBuffer &&other) noexcept
|
||||
: arraySize(std::move(other.arraySize))
|
||||
, allocated(std::move(other.allocated))
|
||||
, allocator(std::move(other.allocator))
|
||||
{
|
||||
_data = other._data;
|
||||
other._data = nullptr;
|
||||
other.allocated = 0;
|
||||
other.arraySize = 0;
|
||||
markIteratorDirty();
|
||||
}
|
||||
RingBuffer &operator=(const RingBuffer &other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
if constexpr (std::allocator_traits<allocator_type>::propagate_on_container_copy_assignment::value )
|
||||
{
|
||||
if (!std::allocator_traits<allocator_type>::is_always_equal::value
|
||||
&& allocator != other.allocator)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
allocator = other.allocator;
|
||||
}
|
||||
if (other.arraySize > allocated)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
if(_data == nullptr)
|
||||
{
|
||||
_data = allocateRingBuffer(other.allocated);
|
||||
allocated = other.allocated;
|
||||
}
|
||||
arraySize = other.arraySize;
|
||||
markIteratorDirty();
|
||||
std::uninitialized_copy(other.begin(), other.end(), begin());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
RingBuffer &operator=(RingBuffer &&other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
if constexpr (std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value)
|
||||
{
|
||||
allocator = std::move(other.allocator);
|
||||
}
|
||||
if (_data != nullptr)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
allocated = std::move(other.allocated);
|
||||
arraySize = std::move(other.arraySize);
|
||||
_data = other._data;
|
||||
other._data = nullptr;
|
||||
markIteratorDirty();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
~RingBuffer()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
constexpr bool operator==(const RingBuffer &other)
|
||||
{
|
||||
return _data == other._data;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const RingBuffer &other)
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
constexpr iterator find(const value_type &item)
|
||||
{
|
||||
for (uint32 i = 0; i < arraySize; ++i)
|
||||
{
|
||||
if (_data[i] == item)
|
||||
{
|
||||
return iterator(&_data[i]);
|
||||
}
|
||||
}
|
||||
return endIt;
|
||||
}
|
||||
constexpr iterator find(value_type&& item)
|
||||
{
|
||||
for (uint32 i = 0; i < arraySize; ++i)
|
||||
{
|
||||
if (_data[i] == item)
|
||||
{
|
||||
return iterator(&_data[i]);
|
||||
}
|
||||
}
|
||||
return endIt;
|
||||
}
|
||||
constexpr allocator_type get_allocator() const
|
||||
{
|
||||
return allocator;
|
||||
}
|
||||
constexpr iterator begin() const
|
||||
{
|
||||
return beginIt;
|
||||
}
|
||||
constexpr iterator end() const
|
||||
{
|
||||
return endIt;
|
||||
}
|
||||
constexpr const_iterator cbegin() const
|
||||
{
|
||||
return beginIt;
|
||||
}
|
||||
constexpr const_iterator cend() const
|
||||
{
|
||||
return endIt;
|
||||
}
|
||||
constexpr reference add(const value_type &item = value_type())
|
||||
{
|
||||
return addInternal(item);
|
||||
}
|
||||
constexpr reference add(value_type&& item)
|
||||
{
|
||||
return addInternal(std::forward<T>(item));
|
||||
}
|
||||
constexpr void addAll(RingBuffer other)
|
||||
{
|
||||
for(auto value : other)
|
||||
{
|
||||
addInternal(value);
|
||||
}
|
||||
}
|
||||
constexpr reference addUnique(const value_type &item = value_type())
|
||||
{
|
||||
iterator it;
|
||||
if((it = std::move(find(item))) != endIt)
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
return addInternal(item);
|
||||
}
|
||||
template<typename... args>
|
||||
constexpr reference emplace(args... arguments)
|
||||
{
|
||||
if (arraySize == allocated)
|
||||
{
|
||||
size_type newSize = arraySize + 1;
|
||||
allocated = calculateGrowth(newSize);
|
||||
T *tempRingBuffer = allocateRingBuffer(allocated);
|
||||
assert(tempRingBuffer != nullptr);
|
||||
|
||||
std::uninitialized_move(begin(), end(), Iterator(tempRingBuffer));
|
||||
deallocateRingBuffer(_data, arraySize);
|
||||
_data = tempRingBuffer;
|
||||
}
|
||||
std::allocator_traits<allocator_type>::construct(allocator, &_data[arraySize++], arguments...);
|
||||
markIteratorDirty();
|
||||
return _data[arraySize - 1];
|
||||
}
|
||||
constexpr void remove(iterator it, bool keepOrder = true)
|
||||
{
|
||||
remove(it - beginIt, keepOrder);
|
||||
}
|
||||
constexpr void remove(size_type index, bool keepOrder = true)
|
||||
{
|
||||
if (keepOrder)
|
||||
{
|
||||
for(uint32 i = index; i < arraySize-1; ++i)
|
||||
{
|
||||
_data[i] = std::move(_data[i+1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_data[index] = std::move(_data[arraySize - 1]);
|
||||
}
|
||||
std::allocator_traits<allocator_type>::destroy(allocator, &_data[--arraySize]);
|
||||
markIteratorDirty();
|
||||
}
|
||||
constexpr void resize(size_type newSize)
|
||||
{
|
||||
resizeInternal(newSize, std::move(T()));
|
||||
}
|
||||
constexpr void resize(size_type newSize, const value_type& value)
|
||||
{
|
||||
resizeInternal(newSize, value);
|
||||
}
|
||||
constexpr void clear()
|
||||
{
|
||||
if(_data == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for(size_type i = 0; i < arraySize; ++i)
|
||||
{
|
||||
std::allocator_traits<allocator_type>::destroy(allocator, &_data[i]);
|
||||
}
|
||||
deallocateRingBuffer(_data, allocated);
|
||||
_data = nullptr;
|
||||
arraySize = 0;
|
||||
allocated = 0;
|
||||
markIteratorDirty();
|
||||
}
|
||||
inline size_type indexOf(iterator iterator)
|
||||
{
|
||||
return iterator - beginIt;
|
||||
}
|
||||
inline size_type indexOf(const_iterator iterator) const
|
||||
{
|
||||
return iterator.p - beginIt.p;
|
||||
}
|
||||
inline size_type indexOf(T& t)
|
||||
{
|
||||
return indexOf(find(t));
|
||||
}
|
||||
inline size_type indexOf(const T& t) const
|
||||
{
|
||||
return indexOf(find(t));
|
||||
}
|
||||
inline size_type size() const
|
||||
{
|
||||
return arraySize;
|
||||
}
|
||||
inline size_type empty() const
|
||||
{
|
||||
return arraySize == 0;
|
||||
}
|
||||
inline size_type capacity() const
|
||||
{
|
||||
return allocated;
|
||||
}
|
||||
inline pointer data() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
inline reference front() const
|
||||
{
|
||||
assert(arraySize > 0);
|
||||
return _data[0];
|
||||
}
|
||||
inline reference back() const
|
||||
{
|
||||
assert(arraySize > 0);
|
||||
return _data[arraySize - 1];
|
||||
}
|
||||
void pop()
|
||||
{
|
||||
std::allocator_traits<allocator_type>::destroy(allocator, &_data[--arraySize]);
|
||||
markIteratorDirty();
|
||||
}
|
||||
constexpr inline reference operator[](size_type index)
|
||||
{
|
||||
assert(index < arraySize);
|
||||
return _data[index];
|
||||
}
|
||||
constexpr inline const reference operator[](size_type index) const
|
||||
{
|
||||
assert(index < arraySize);
|
||||
return _data[index];
|
||||
}
|
||||
private:
|
||||
void refreshIterators()
|
||||
{
|
||||
beginIt = Iterator(data, begin);
|
||||
endIt = Iterator(data, end);
|
||||
}
|
||||
size_type begin = 0;
|
||||
size_type end = 0;
|
||||
iterator beginIt;
|
||||
iterator endIt;
|
||||
Array<T, Allocator> data;
|
||||
};
|
||||
class StaticRingBuffer
|
||||
{
|
||||
|
||||
};
|
||||
} // namespace Seele
|
||||
@@ -171,12 +171,6 @@ void CmdBuffer::waitForCommand(uint32 timeout)
|
||||
refreshFence();
|
||||
}
|
||||
|
||||
Event CmdBuffer::asyncWait() const
|
||||
{
|
||||
return fence->asyncWait();
|
||||
}
|
||||
|
||||
|
||||
PFence CmdBuffer::getFence()
|
||||
{
|
||||
return fence;
|
||||
|
||||
@@ -32,7 +32,10 @@ public:
|
||||
void addWaitSemaphore(VkPipelineStageFlags stages, PSemaphore waitSemaphore);
|
||||
void refreshFence();
|
||||
void waitForCommand(uint32 timeToWait = 1000000u);
|
||||
Event asyncWait() const;
|
||||
Fence* operator co_await()
|
||||
{
|
||||
return fence.getHandle();
|
||||
}
|
||||
PFence getFence();
|
||||
PCommandBufferManager getManager();
|
||||
enum State
|
||||
|
||||
@@ -80,11 +80,6 @@ void Fence::wait(uint32 timeout)
|
||||
break;
|
||||
}
|
||||
}
|
||||
Event Fence::asyncWait() const
|
||||
{
|
||||
return signaled;
|
||||
}
|
||||
|
||||
|
||||
VertexDeclaration::VertexDeclaration(const Array<Gfx::VertexElement>& elementList)
|
||||
: elementList(elementList)
|
||||
|
||||
@@ -43,7 +43,10 @@ public:
|
||||
return fence;
|
||||
}
|
||||
void wait(uint32 timeout);
|
||||
Event asyncWait() const;
|
||||
Event& operator co_await()
|
||||
{
|
||||
return signaled;
|
||||
}
|
||||
bool operator<(const Fence &other) const
|
||||
{
|
||||
return fence < other.fence;
|
||||
|
||||
@@ -146,15 +146,15 @@ Vector Transform::getScale() const
|
||||
|
||||
Vector Transform::getForward() const
|
||||
{
|
||||
return Vector(0, 0, 1) * rotation;
|
||||
return glm::normalize(Vector(0, 0, 1) * rotation);
|
||||
}
|
||||
Vector Transform::getRight() const
|
||||
{
|
||||
return Vector(1, 0, 0) * rotation;
|
||||
return glm::normalize(Vector(1, 0, 0) * rotation);
|
||||
}
|
||||
Vector Transform::getUp() const
|
||||
{
|
||||
return Vector(0, 1, 0) * rotation;
|
||||
return glm::normalize(Vector(0, 1, 0) * rotation);
|
||||
}
|
||||
|
||||
bool Transform::equals(const Transform &other, float tolerance)
|
||||
|
||||
@@ -14,6 +14,7 @@ CameraActor::CameraActor()
|
||||
cameraComponent->aspectRatio = 1.777778f;
|
||||
cameraComponent->setParent(sceneComponent);
|
||||
cameraComponent->setOwner(this);
|
||||
sceneComponent->addChildComponent(cameraComponent);
|
||||
}
|
||||
|
||||
CameraActor::~CameraActor()
|
||||
|
||||
@@ -13,8 +13,8 @@ CameraComponent::CameraComponent()
|
||||
, projectionMatrix(Matrix4())
|
||||
, viewMatrix(Matrix4())
|
||||
{
|
||||
rotationX = 0;
|
||||
rotationY = 0;
|
||||
yaw = 0;
|
||||
pitch = 0;
|
||||
setRelativeLocation(Vector(0, 10, -50));
|
||||
}
|
||||
|
||||
@@ -22,12 +22,16 @@ CameraComponent::~CameraComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void CameraComponent::mouseMove(float deltaX, float deltaY)
|
||||
void CameraComponent::mouseMove(float deltaYaw, float deltaPitch)
|
||||
{
|
||||
rotationX -= deltaX / 1000.f;
|
||||
rotationY += deltaY / 1000.f;
|
||||
//std::cout << "X:" << rotationX << " Y: " << rotationY << std::endl;
|
||||
setRelativeRotation(Vector(rotationY, rotationX, 0));
|
||||
yaw -= deltaYaw / 500.f;
|
||||
pitch += deltaPitch / 500.f;
|
||||
//std::cout << "Yaw: " << yaw << " Pitch: " << pitch << std::endl;
|
||||
Vector cameraDirection = glm::normalize(Vector(cos(yaw) * cos(pitch), sin(pitch), sin(yaw) * cos(pitch)));
|
||||
Vector xyz = glm::cross(cameraDirection, Vector(0, 0, 1));
|
||||
Quaternion result = Quaternion(glm::dot(cameraDirection, Vector(0, 0, 1)) + 1, xyz.x, xyz.y, xyz.z);
|
||||
//std::cout << "Result " << Vector(0, 0, 1) * glm::normalize(result) << " cameraDirection: " << cameraDirection << std::endl;
|
||||
setRelativeRotation(result);
|
||||
bNeedsViewBuild = true;
|
||||
}
|
||||
|
||||
@@ -51,9 +55,9 @@ void CameraComponent::moveY(float amount)
|
||||
|
||||
void CameraComponent::buildViewMatrix()
|
||||
{
|
||||
Vector eyePos = getTransform().getPosition();
|
||||
Vector lookAt = eyePos + getTransform().getForward();
|
||||
std::cout << "Eye: " << eyePos << " lookAt: " << lookAt << std::endl;
|
||||
Vector eyePos = getAbsoluteTransform().getPosition();
|
||||
Vector lookAt = eyePos + glm::normalize(Vector(cos(yaw) * cos(pitch), sin(pitch), sin(yaw) * cos(pitch)));
|
||||
//std::cout << "Eye: " << eyePos << " lookAt: " << lookAt << std::endl;
|
||||
viewMatrix = glm::lookAt(eyePos, lookAt, Vector(0, 1, 0));
|
||||
|
||||
bNeedsViewBuild = false;
|
||||
|
||||
@@ -45,8 +45,8 @@ private:
|
||||
//Transforms relative to actor
|
||||
Matrix4 viewMatrix;
|
||||
Matrix4 projectionMatrix;
|
||||
float rotationX;
|
||||
float rotationY;
|
||||
float yaw;
|
||||
float pitch;
|
||||
};
|
||||
DEFINE_REF(CameraComponent)
|
||||
} // namespace Seele
|
||||
|
||||
@@ -128,18 +128,22 @@ void Component::notifySceneAttach(PScene scene)
|
||||
void Component::setRelativeLocation(Vector location)
|
||||
{
|
||||
transform = Transform(location, transform.getRotation(), transform.getScale());
|
||||
propagateTransformUpdate();
|
||||
}
|
||||
void Component::setRelativeRotation(Vector rotation)
|
||||
{
|
||||
transform = Transform(transform.getPosition(), Quaternion(rotation), transform.getScale());
|
||||
propagateTransformUpdate();
|
||||
}
|
||||
void Component::setRelativeRotation(Quaternion rotation)
|
||||
{
|
||||
transform = Transform(transform.getPosition(), rotation, transform.getScale());
|
||||
propagateTransformUpdate();
|
||||
}
|
||||
void Component::setRelativeScale(Vector scale)
|
||||
{
|
||||
transform = Transform(transform.getPosition(), transform.getRotation(), scale);
|
||||
propagateTransformUpdate();
|
||||
}
|
||||
|
||||
//void Component::addAbsoluteTranslation(Vector translation)
|
||||
@@ -161,14 +165,17 @@ void Component::setRelativeScale(Vector scale)
|
||||
void Component::addRelativeLocation(Vector translation)
|
||||
{
|
||||
transform = Transform(transform.getPosition() + translation, transform.getRotation(), transform.getScale());
|
||||
propagateTransformUpdate();
|
||||
}
|
||||
void Component::addRelativeRotation(Vector rotation)
|
||||
{
|
||||
transform = Transform(transform.getPosition(), transform.getRotation() + Quaternion(rotation), transform.getScale());
|
||||
transform = Transform(transform.getPosition(), transform.getRotation() * Quaternion(rotation), transform.getScale());
|
||||
propagateTransformUpdate();
|
||||
}
|
||||
void Component::addRelativeRotation(Quaternion rotation)
|
||||
{
|
||||
transform = Transform(transform.getPosition(), transform.getRotation(), transform.getScale());
|
||||
transform = Transform(transform.getPosition(), transform.getRotation() * rotation, transform.getScale());
|
||||
propagateTransformUpdate();
|
||||
}
|
||||
|
||||
Transform Component::getTransform() const
|
||||
@@ -177,10 +184,22 @@ Transform Component::getTransform() const
|
||||
}
|
||||
|
||||
Transform Component::getAbsoluteTransform() const
|
||||
{
|
||||
return absoluteTransform;
|
||||
}
|
||||
|
||||
void Component::propagateTransformUpdate()
|
||||
{
|
||||
if(parent != nullptr)
|
||||
{
|
||||
return transform + parent->getAbsoluteTransform();
|
||||
absoluteTransform = transform + parent->getAbsoluteTransform();
|
||||
}
|
||||
else
|
||||
{
|
||||
absoluteTransform = transform;
|
||||
}
|
||||
for(auto child : children)
|
||||
{
|
||||
child->propagateTransformUpdate();
|
||||
}
|
||||
return transform;
|
||||
}
|
||||
@@ -74,7 +74,9 @@ private:
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
void propagateTransformUpdate();
|
||||
Transform transform;
|
||||
Transform absoluteTransform;
|
||||
PScene owningScene;
|
||||
PActor owner;
|
||||
PComponent parent;
|
||||
|
||||
+75
-94
@@ -3,55 +3,69 @@
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
|
||||
Event::Event()
|
||||
: flag(std::make_shared<StateStore>())
|
||||
{
|
||||
}
|
||||
std::mutex Seele::promisesLock;
|
||||
List<Promise*> Seele::promises;
|
||||
|
||||
Event::Event(nullptr_t)
|
||||
: flag(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Event::Event(const std::string &name)
|
||||
: flag(std::make_shared<StateStore>())
|
||||
Event::Event(const std::string &name, const std::source_location &location)
|
||||
: name(name)
|
||||
, location(location)
|
||||
{
|
||||
flag->name = name;
|
||||
}
|
||||
|
||||
|
||||
Event::Event(const std::source_location &location)
|
||||
: flag(std::make_shared<StateStore>())
|
||||
: name(location.function_name())
|
||||
, location(location)
|
||||
{
|
||||
flag->name = location.function_name();
|
||||
flag->location = location;
|
||||
}
|
||||
|
||||
|
||||
void Event::raise()
|
||||
{
|
||||
std::scoped_lock lock(flag->lock);
|
||||
flag->data = 1;
|
||||
getGlobalThreadPool().notify(*this);
|
||||
std::scoped_lock lock(eventLock);
|
||||
data = true;
|
||||
if(waitingJobs.size() > 0)
|
||||
{
|
||||
getGlobalThreadPool().scheduleBatch(waitingJobs);
|
||||
}
|
||||
if(waitingMainJobs.size() > 0)
|
||||
{
|
||||
getGlobalThreadPool().scheduleBatch(waitingMainJobs);
|
||||
}
|
||||
}
|
||||
void Event::reset()
|
||||
{
|
||||
std::scoped_lock lock(flag->lock);
|
||||
flag->data = 0;
|
||||
std::scoped_lock lock(eventLock);
|
||||
data = false;
|
||||
}
|
||||
|
||||
bool Event::await_ready()
|
||||
{
|
||||
flag->lock.lock();
|
||||
bool result = flag->data;
|
||||
eventLock.lock();
|
||||
bool result = data;
|
||||
if(result)
|
||||
{
|
||||
flag->lock.unlock();
|
||||
eventLock.unlock();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Event::await_suspend(std::coroutine_handle<JobPromiseBase<false>> h)
|
||||
{
|
||||
//h.promise().enqueue(this);
|
||||
waitingJobs.add(JobBase<false>(&h.promise()));
|
||||
eventLock.unlock();
|
||||
}
|
||||
|
||||
void Event::await_suspend(std::coroutine_handle<JobPromiseBase<true>> h)
|
||||
{
|
||||
//h.promise().enqueue(this);
|
||||
waitingMainJobs.add(JobBase<true>(&h.promise()));
|
||||
eventLock.unlock();
|
||||
}
|
||||
|
||||
ThreadPool::ThreadPool(uint32 threadCount)
|
||||
: workers(threadCount)
|
||||
{
|
||||
@@ -59,13 +73,24 @@ ThreadPool::ThreadPool(uint32 threadCount)
|
||||
for (uint32 i = 0; i < threadCount; ++i)
|
||||
{
|
||||
workers[i] = std::thread(&ThreadPool::threadLoop, this);
|
||||
workers[i].detach();
|
||||
}
|
||||
}
|
||||
|
||||
ThreadPool::~ThreadPool()
|
||||
{
|
||||
workers.clear();
|
||||
running.store(false);
|
||||
{
|
||||
std::unique_lock lock(mainJobLock);
|
||||
mainJobCV.notify_all();
|
||||
}
|
||||
{
|
||||
std::unique_lock lock(jobQueueLock);
|
||||
jobQueueCV.notify_all();
|
||||
}
|
||||
for(auto& worker : workers)
|
||||
{
|
||||
worker.join();
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::waitIdle()
|
||||
@@ -73,108 +98,63 @@ void ThreadPool::waitIdle()
|
||||
while(true)
|
||||
{
|
||||
std::unique_lock lock(numIdlingLock);
|
||||
numIdlingIncr.wait(lock);
|
||||
if(numIdling == workers.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
numIdlingIncr.wait(lock);
|
||||
}
|
||||
}
|
||||
void ThreadPool::enqueueWaiting(Event &event, Promise* job)
|
||||
void ThreadPool::scheduleJob(Job job)
|
||||
{
|
||||
assert(!job->done());
|
||||
std::scoped_lock lock(waitingLock);
|
||||
//std::cout << "Job " << job->finishedEvent.name << " waiting on event " << event.name << std::endl;
|
||||
waitingJobs[event].add(job);
|
||||
job->addRef();
|
||||
}
|
||||
void ThreadPool::enqueueWaiting(Event &event, MainPromise* job)
|
||||
{
|
||||
assert(!job->done());
|
||||
std::scoped_lock lock(waitingMainLock);
|
||||
//std::cout << job->finishedEvent.name << " waiting on event " << event.name << std::endl;
|
||||
waitingMainJobs[event].add(job);
|
||||
job->addRef();
|
||||
}
|
||||
void ThreadPool::scheduleJob(Promise* job)
|
||||
{
|
||||
assert(!job->done());
|
||||
assert(!job.done());
|
||||
std::scoped_lock lock(jobQueueLock);
|
||||
//std::cout << "Queueing job " << job->finishedEvent << std::endl;
|
||||
jobQueue.add(job);
|
||||
jobQueue.add(std::move(job));
|
||||
jobQueueCV.notify_one();
|
||||
job->addRef();
|
||||
}
|
||||
void ThreadPool::scheduleJob(MainPromise* job)
|
||||
void ThreadPool::scheduleJob(MainJob job)
|
||||
{
|
||||
assert(!job->done());
|
||||
assert(!job.done());
|
||||
std::scoped_lock lock(mainJobLock);
|
||||
//std::cout << "Queueing job " << job->finishedEvent << std::endl;
|
||||
mainJobs.add(job);
|
||||
mainJobs.add(std::move(job));
|
||||
mainJobCV.notify_one();
|
||||
job->addRef();
|
||||
}
|
||||
void ThreadPool::notify(Event &event)
|
||||
{
|
||||
//std::cout << "Event " << event.name << " raised" << std::endl;
|
||||
{
|
||||
std::scoped_lock lock(jobQueueLock, waitingLock);
|
||||
List<Promise*> jobs = std::move(waitingJobs[event]);
|
||||
waitingJobs.erase(event);
|
||||
for (auto &job : jobs)
|
||||
{
|
||||
//assert(job.id != -1ull);
|
||||
//std::cout << "Waking up " << job->finishedEvent.name << std::endl;
|
||||
job->state = Promise::State::SCHEDULED;
|
||||
jobQueue.add(job);
|
||||
jobQueueCV.notify_one();
|
||||
}
|
||||
}
|
||||
{
|
||||
std::scoped_lock lock(mainJobLock, waitingMainLock);
|
||||
List<MainPromise*> jobs = std::move(waitingMainJobs[event]);
|
||||
waitingMainJobs.erase(event);
|
||||
for (auto &job : jobs)
|
||||
{
|
||||
//assert(job.id != -1ull);
|
||||
//std::cout << "Waking up main " << job->finishedEvent.name << std::endl;
|
||||
job->state = MainPromise::State::SCHEDULED;
|
||||
mainJobs.add(job);
|
||||
mainJobCV.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::mainLoop()
|
||||
{
|
||||
while(true)
|
||||
while(running.load())
|
||||
{
|
||||
MainPromise* job;
|
||||
MainJob job;
|
||||
{
|
||||
std::unique_lock lock(mainJobLock);
|
||||
if(mainJobs.empty())
|
||||
{
|
||||
mainJobCV.wait(lock);
|
||||
}
|
||||
job = mainJobs.front();
|
||||
mainJobs.popFront();
|
||||
[[likely]]
|
||||
if(!mainJobs.empty())
|
||||
{
|
||||
job = mainJobs.front();
|
||||
mainJobs.popFront();
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
job->resume();
|
||||
job->removeRef();
|
||||
job.resume();
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::threadLoop()
|
||||
{
|
||||
List<Promise*> localQueue;
|
||||
while (true)
|
||||
List<Job> localQueue;
|
||||
while (running.load())
|
||||
{
|
||||
[[likely]]
|
||||
if(!localQueue.empty())
|
||||
{
|
||||
Promise* job = localQueue.retrieve();
|
||||
job->resume();
|
||||
job->removeRef();
|
||||
Job job = localQueue.retrieve();
|
||||
job.resume();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -194,7 +174,8 @@ void ThreadPool::threadLoop()
|
||||
}
|
||||
// take 1/numThreads jobs, maybe make this a parameter that
|
||||
// adjusts based on past workload
|
||||
uint32 numTaken = std::max(jobQueue.size() / workers.size(), 1ull);
|
||||
uint32 partitionedWorkload = (uint32)(jobQueue.size() / workers.size());
|
||||
uint32 numTaken = std::clamp(partitionedWorkload, 1u, localQueueSize);
|
||||
while (!jobQueue.empty() && localQueue.size() < numTaken)
|
||||
{
|
||||
localQueue.add(jobQueue.retrieve());
|
||||
|
||||
+79
-90
@@ -10,66 +10,65 @@ namespace Seele
|
||||
{
|
||||
extern class ThreadPool& getGlobalThreadPool();
|
||||
template<bool MainJob>
|
||||
struct JobBase;
|
||||
template<bool MainJob>
|
||||
struct JobPromiseBase;
|
||||
struct Event
|
||||
{
|
||||
public:
|
||||
Event();
|
||||
Event(nullptr_t);
|
||||
Event(const std::string& name);
|
||||
Event(const std::source_location& location);
|
||||
Event(const std::string& name, const std::source_location& location = std::source_location::current());
|
||||
Event(const std::source_location& location = std::source_location::current());
|
||||
Event(const Event& other) = delete;
|
||||
Event(Event&& other) = default;
|
||||
~Event() = default;
|
||||
Event& operator=(const Event& other) = delete;
|
||||
Event& operator=(Event&& other) = default;
|
||||
auto operator<=>(const Event& other) const
|
||||
{
|
||||
return flag <=> other.flag;
|
||||
return name <=> other.name;
|
||||
}
|
||||
bool operator==(const Event& other) const
|
||||
{
|
||||
return flag == other.flag;
|
||||
}
|
||||
Event operator co_await()
|
||||
{
|
||||
return *this;
|
||||
return name == other.name;
|
||||
}
|
||||
operator bool()
|
||||
{
|
||||
std::scoped_lock lock(flag->lock);
|
||||
return flag->data;
|
||||
std::scoped_lock lock(eventLock);
|
||||
return data;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const Event& event)
|
||||
{
|
||||
stream
|
||||
<< event.flag->location.file_name()
|
||||
<< event.location.file_name()
|
||||
<< "("
|
||||
<< event.flag->location.line()
|
||||
<< event.location.line()
|
||||
<< ":"
|
||||
<< event.flag->location.column()
|
||||
<< event.location.column()
|
||||
<< "): "
|
||||
<< event.flag->location.function_name();
|
||||
<< event.location.function_name();
|
||||
return stream;
|
||||
}
|
||||
|
||||
void raise();
|
||||
void reset();
|
||||
bool await_ready();
|
||||
template<bool MainJob>
|
||||
constexpr void await_suspend(std::coroutine_handle<JobPromiseBase<MainJob>> h);
|
||||
void await_suspend(std::coroutine_handle<JobPromiseBase<false>> h);
|
||||
void await_suspend(std::coroutine_handle<JobPromiseBase<true>> h);
|
||||
constexpr void await_resume() {}
|
||||
private:
|
||||
struct StateStore
|
||||
{
|
||||
std::mutex lock;
|
||||
std::string name;
|
||||
std::source_location location;
|
||||
bool data;
|
||||
};
|
||||
std::shared_ptr<StateStore> flag;
|
||||
std::mutex eventLock;
|
||||
std::string name;
|
||||
std::source_location location;
|
||||
bool data = false;
|
||||
Array<JobBase<false>> waitingJobs;
|
||||
Array<JobBase<true>> waitingMainJobs;
|
||||
friend class ThreadPool;
|
||||
};
|
||||
|
||||
template<bool MainJob>
|
||||
struct JobBase;
|
||||
extern std::mutex promisesLock;
|
||||
extern List<JobPromiseBase<false>*> promises;
|
||||
template<bool MainJob>
|
||||
struct JobPromiseBase
|
||||
{
|
||||
@@ -82,12 +81,24 @@ struct JobPromiseBase
|
||||
DONE
|
||||
};
|
||||
JobPromiseBase(const std::source_location& location = std::source_location::current())
|
||||
: handle(std::coroutine_handle<JobPromiseBase<MainJob>>::from_promise(*this))
|
||||
, finishedEvent(Event(location))
|
||||
{
|
||||
handle = std::coroutine_handle<JobPromiseBase<MainJob>>::from_promise(*this);
|
||||
finishedEvent = Event(location);
|
||||
if constexpr(!MainJob)
|
||||
{
|
||||
std::scoped_lock lock(promisesLock);
|
||||
promises.add(this);
|
||||
}
|
||||
}
|
||||
~JobPromiseBase()
|
||||
{}
|
||||
{
|
||||
if constexpr (!MainJob)
|
||||
{
|
||||
std::scoped_lock lock(promisesLock);
|
||||
promises.remove(promises.find(this));
|
||||
}
|
||||
}
|
||||
|
||||
JobBase<MainJob> get_return_object() noexcept;
|
||||
|
||||
inline auto initial_suspend() noexcept;
|
||||
@@ -102,7 +113,6 @@ struct JobPromiseBase
|
||||
|
||||
void resume()
|
||||
{
|
||||
std::scoped_lock lock(promiseLock);
|
||||
if(!handle || handle.done() || executing())
|
||||
{
|
||||
return;
|
||||
@@ -116,17 +126,16 @@ struct JobPromiseBase
|
||||
finishedEvent.raise();
|
||||
if(continuation)
|
||||
{
|
||||
std::scoped_lock lock(continuation->promiseLock);
|
||||
getGlobalThreadPool().scheduleJob(continuation);
|
||||
getGlobalThreadPool().scheduleJob(JobBase<MainJob>(continuation));
|
||||
continuation->removeRef();
|
||||
}
|
||||
}
|
||||
void setContinuation(JobPromiseBase* cont)
|
||||
{
|
||||
std::scoped_lock lock(promiseLock, cont->promiseLock);
|
||||
assert(cont->ready());
|
||||
continuation = cont;
|
||||
cont->state = State::SCHEDULED;
|
||||
cont->waitingFor = &finishedEvent;
|
||||
cont->addRef();
|
||||
}
|
||||
bool done()
|
||||
@@ -149,29 +158,25 @@ struct JobPromiseBase
|
||||
{
|
||||
return state == State::READY;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
std::scoped_lock lock(promiseLock);
|
||||
finishedEvent.reset();
|
||||
}
|
||||
void enqueue(Event& event)
|
||||
void enqueue(Event* event)
|
||||
{
|
||||
if(!handle || handle.done() || waiting() || scheduled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
state = State::WAITING;
|
||||
getGlobalThreadPool().enqueueWaiting(event, this);
|
||||
waitingFor = event;
|
||||
getGlobalThreadPool().enqueueWaiting(event, std::move(JobBase<MainJob>(this)));
|
||||
}
|
||||
void schedule()
|
||||
bool schedule()
|
||||
{
|
||||
std::scoped_lock lock(promiseLock);
|
||||
if(!handle || done() || !ready())
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
state = State::SCHEDULED;
|
||||
getGlobalThreadPool().scheduleJob(this);
|
||||
getGlobalThreadPool().scheduleJob(std::move(JobBase<MainJob>(this)));
|
||||
return true;
|
||||
}
|
||||
void addRef()
|
||||
{
|
||||
@@ -179,25 +184,23 @@ struct JobPromiseBase
|
||||
}
|
||||
void removeRef()
|
||||
{
|
||||
if(--numRefs < 1)
|
||||
numRefs--;
|
||||
if(numRefs == 0)
|
||||
{
|
||||
if(done())
|
||||
if(!schedule())
|
||||
{
|
||||
handle.destroy();
|
||||
}
|
||||
else
|
||||
{
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::mutex promiseLock;
|
||||
uint64 pad0 = 0x7472617453;
|
||||
std::coroutine_handle<JobPromiseBase> handle;
|
||||
Event* waitingFor = nullptr;
|
||||
JobPromiseBase* continuation = nullptr;
|
||||
std::atomic_uint64_t numRefs = 0;
|
||||
uint64 numRefs = 0;
|
||||
Event finishedEvent;
|
||||
State state = State::READY;
|
||||
uint64 pad1 = 0x646E45;
|
||||
};
|
||||
|
||||
template<bool MainJob = false>
|
||||
@@ -213,16 +216,15 @@ public:
|
||||
explicit JobBase(JobPromiseBase<MainJob>* promise)
|
||||
: promise(promise)
|
||||
{
|
||||
promise->addRef();
|
||||
}
|
||||
JobBase(const JobBase& other)
|
||||
{
|
||||
std::scoped_lock lock(other.promise->promiseLock);
|
||||
promise = other.promise;
|
||||
promise->addRef();
|
||||
}
|
||||
JobBase(JobBase&& other)
|
||||
{
|
||||
std::scoped_lock lock(other.promise->promiseLock);
|
||||
promise = other.promise;
|
||||
other.promise = nullptr;
|
||||
}
|
||||
@@ -238,7 +240,10 @@ public:
|
||||
{
|
||||
if(this != &other)
|
||||
{
|
||||
std::scoped_lock lock(other.promise->promiseLock);
|
||||
if(promise != nullptr)
|
||||
{
|
||||
promise->removeRef();
|
||||
}
|
||||
promise = other.promise;
|
||||
promise->addRef();
|
||||
}
|
||||
@@ -248,7 +253,10 @@ public:
|
||||
{
|
||||
if(this != &other)
|
||||
{
|
||||
std::scoped_lock lock(other.promise->promiseLock);
|
||||
if(promise != nullptr)
|
||||
{
|
||||
promise->removeRef();
|
||||
}
|
||||
promise = other.promise;
|
||||
other.promise = nullptr;
|
||||
}
|
||||
@@ -273,7 +281,7 @@ public:
|
||||
{
|
||||
return promise->done();
|
||||
}
|
||||
Event operator co_await() const
|
||||
Event& operator co_await()
|
||||
{
|
||||
// the co_await operator keeps a reference to this, it won't
|
||||
// be scheduled from the destructor
|
||||
@@ -311,8 +319,7 @@ public:
|
||||
Array<JobBase> jobs;
|
||||
for(auto&& param : params)
|
||||
{
|
||||
JobBase base = func(param);
|
||||
jobs.add(base);
|
||||
jobs.add(func(param));
|
||||
}
|
||||
getGlobalThreadPool().scheduleBatch(jobs);
|
||||
for(auto job : jobs)
|
||||
@@ -333,15 +340,11 @@ using Promise = JobPromiseBase<false>;
|
||||
class ThreadPool
|
||||
{
|
||||
public:
|
||||
ThreadPool(uint32 threadCount = std::thread::hardware_concurrency());
|
||||
ThreadPool(uint32 threadCount = 1);//std::thread::hardware_concurrency());
|
||||
virtual ~ThreadPool();
|
||||
void waitIdle();
|
||||
// Adds a job to the waiting queue for event
|
||||
void enqueueWaiting(Event& event, Promise* job);
|
||||
// Adds a job to the waiting queue for event
|
||||
void enqueueWaiting(Event& event, MainPromise* job);
|
||||
void scheduleJob(Promise* job);
|
||||
void scheduleJob(MainPromise* job);
|
||||
void scheduleJob(Job job);
|
||||
void scheduleJob(MainJob job);
|
||||
template<std::ranges::range Iterable>
|
||||
requires std::same_as<std::ranges::range_value_t<Iterable>, MainJob>
|
||||
void scheduleBatch(Iterable jobs)
|
||||
@@ -349,9 +352,9 @@ public:
|
||||
std::scoped_lock lock(mainJobLock);
|
||||
for(auto job : jobs)
|
||||
{
|
||||
job.promise->addRef();
|
||||
//job.promise->addRef();
|
||||
job.promise->state = JobPromiseBase<true>::State::SCHEDULED;
|
||||
mainJobs.add(job.promise);
|
||||
mainJobs.add(job);
|
||||
}
|
||||
mainJobCV.notify_one();
|
||||
}
|
||||
@@ -362,13 +365,13 @@ public:
|
||||
std::scoped_lock lock(jobQueueLock);
|
||||
for(auto job : jobs)
|
||||
{
|
||||
job.promise->addRef();
|
||||
//job.promise->addRef();
|
||||
job.promise->state = JobPromiseBase<false>::State::SCHEDULED;
|
||||
jobQueue.add(job.promise);
|
||||
jobQueue.add(job);
|
||||
}
|
||||
jobQueueCV.notify_all();
|
||||
}
|
||||
void notify(Event& event);
|
||||
void notify(Event* event);
|
||||
void mainLoop();
|
||||
void threadLoop();
|
||||
private:
|
||||
@@ -378,27 +381,20 @@ private:
|
||||
uint32 numIdling;
|
||||
Array<std::thread> workers;
|
||||
|
||||
List<MainPromise*> mainJobs;
|
||||
List<MainJob> mainJobs;
|
||||
std::mutex mainJobLock;
|
||||
std::condition_variable mainJobCV;
|
||||
|
||||
List<Promise*> jobQueue;
|
||||
List<Job> jobQueue;
|
||||
std::mutex jobQueueLock;
|
||||
std::condition_variable jobQueueCV;
|
||||
|
||||
Map<Event, List<MainPromise*>> waitingMainJobs;
|
||||
std::mutex waitingMainLock;
|
||||
|
||||
Map<Event, List<Promise*>> waitingJobs;
|
||||
std::mutex waitingLock;
|
||||
|
||||
uint32 maxLocalQueueSize = 50;
|
||||
uint32 localQueueSize = 50;
|
||||
};
|
||||
|
||||
template<bool MainJob>
|
||||
inline JobBase<MainJob> JobPromiseBase<MainJob>::get_return_object() noexcept
|
||||
{
|
||||
numRefs++;
|
||||
return JobBase<MainJob>(this);
|
||||
}
|
||||
|
||||
@@ -415,11 +411,4 @@ inline auto JobPromiseBase<MainJob>::final_suspend() noexcept
|
||||
return std::suspend_always{};
|
||||
}
|
||||
|
||||
template<bool MainJob>
|
||||
inline constexpr void Event::await_suspend(std::coroutine_handle<JobPromiseBase<MainJob>> h)
|
||||
{
|
||||
h.promise().enqueue(*this);
|
||||
flag->lock.unlock();
|
||||
}
|
||||
|
||||
} // namespace Seele
|
||||
|
||||
@@ -25,3 +25,8 @@ void View::setFocused()
|
||||
{
|
||||
owner->setFocused(this);
|
||||
}
|
||||
|
||||
const std::string& View::getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ public:
|
||||
void applyArea(URect area);
|
||||
void setFocused();
|
||||
|
||||
const std::string& getName();
|
||||
|
||||
protected:
|
||||
Gfx::PGraphics graphics;
|
||||
Gfx::PViewport viewport;
|
||||
|
||||
@@ -16,9 +16,7 @@ Window::~Window()
|
||||
|
||||
void Window::addView(PView view)
|
||||
{
|
||||
WindowView* windowView = new WindowView();
|
||||
windowView->view = view;
|
||||
windowView->updateFinished = Event(view->name);
|
||||
WindowView* windowView = new WindowView(view);
|
||||
//windowView->worker = std::thread(&Window::viewWorker, this, windowView);
|
||||
views.add(windowView);
|
||||
viewWorker(views.size() - 1);
|
||||
|
||||
@@ -10,6 +10,10 @@ struct WindowView
|
||||
PView view;
|
||||
Event updateFinished;
|
||||
std::mutex workerMutex;
|
||||
WindowView(PView view)
|
||||
: view(view)
|
||||
, updateFinished(view->getName())
|
||||
{}
|
||||
};
|
||||
DEFINE_REF(WindowView)
|
||||
DECLARE_REF(WindowManager)
|
||||
|
||||
+78
-70
@@ -1,112 +1,120 @@
|
||||
#include "EngineTest.h"
|
||||
#include "MinimalEngine.h"
|
||||
#include "ThreadPool.h"
|
||||
#define BOOST_TEST_MODULE SeeleEngine
|
||||
#include <boost/test/unit_test.hpp>
|
||||
//#include <vld.h>
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
Seele::GlobalFixture::~GlobalFixture()
|
||||
{
|
||||
getGlobalThreadPool().waitIdle();
|
||||
}
|
||||
|
||||
BOOST_TEST_GLOBAL_FIXTURE(GlobalFixture);
|
||||
BOOST_AUTO_TEST_SUITE(RefPtr)
|
||||
|
||||
struct TestStruct
|
||||
{
|
||||
TestStruct()
|
||||
: data(10)
|
||||
{
|
||||
}
|
||||
virtual ~TestStruct()
|
||||
{
|
||||
data = 15;
|
||||
}
|
||||
uint32 data;
|
||||
TestStruct()
|
||||
: data(10)
|
||||
{
|
||||
}
|
||||
virtual ~TestStruct()
|
||||
{
|
||||
data = 15;
|
||||
}
|
||||
uint32 data;
|
||||
};
|
||||
|
||||
struct DeclStruct;
|
||||
BOOST_AUTO_TEST_CASE(basic_refcount)
|
||||
{
|
||||
{
|
||||
Seele::RefPtr<TestStruct> ptr = new TestStruct();
|
||||
BOOST_REQUIRE_EQUAL(ptr->data, 10);
|
||||
{
|
||||
Seele::RefPtr<TestStruct> secondPtr = ptr;
|
||||
BOOST_REQUIRE_EQUAL(secondPtr->data, 10);
|
||||
BOOST_REQUIRE_EQUAL(ptr->data, 10);
|
||||
}
|
||||
BOOST_REQUIRE_EQUAL(ptr->data, 10);
|
||||
}
|
||||
{
|
||||
Seele::RefPtr<TestStruct> ptr = new TestStruct();
|
||||
BOOST_REQUIRE_EQUAL(ptr->data, 10);
|
||||
{
|
||||
Seele::RefPtr<TestStruct> secondPtr = ptr;
|
||||
BOOST_REQUIRE_EQUAL(secondPtr->data, 10);
|
||||
BOOST_REQUIRE_EQUAL(ptr->data, 10);
|
||||
}
|
||||
BOOST_REQUIRE_EQUAL(ptr->data, 10);
|
||||
}
|
||||
}
|
||||
struct DeclStruct
|
||||
{
|
||||
~DeclStruct()
|
||||
{
|
||||
data = 10;
|
||||
}
|
||||
uint32 data = 20;
|
||||
~DeclStruct()
|
||||
{
|
||||
data = 10;
|
||||
}
|
||||
uint32 data = 20;
|
||||
};
|
||||
|
||||
struct DerivedStruct : public TestStruct
|
||||
{
|
||||
DerivedStruct()
|
||||
:data2(20)
|
||||
{
|
||||
DerivedStruct()
|
||||
:data2(20)
|
||||
{
|
||||
|
||||
}
|
||||
~DerivedStruct()
|
||||
{
|
||||
data2 = 30;
|
||||
}
|
||||
uint32 data2;
|
||||
}
|
||||
~DerivedStruct()
|
||||
{
|
||||
data2 = 30;
|
||||
}
|
||||
uint32 data2;
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE(inheritance_cast)
|
||||
{
|
||||
Seele::RefPtr<DerivedStruct> backCast;
|
||||
{
|
||||
Seele::RefPtr<DerivedStruct> derived = new DerivedStruct();
|
||||
Seele::RefPtr<TestStruct> base = derived;
|
||||
BOOST_REQUIRE_EQUAL(base->data, 10);
|
||||
backCast = base.cast<DerivedStruct>();
|
||||
BOOST_REQUIRE_EQUAL(backCast->data, 10);
|
||||
BOOST_REQUIRE_EQUAL(backCast->data2, 20);
|
||||
}
|
||||
BOOST_REQUIRE_EQUAL(backCast->data, 10);
|
||||
BOOST_REQUIRE_EQUAL(backCast->data2, 20);
|
||||
Seele::RefPtr<DerivedStruct> backCast;
|
||||
{
|
||||
Seele::RefPtr<DerivedStruct> derived = new DerivedStruct();
|
||||
Seele::RefPtr<TestStruct> base = derived;
|
||||
BOOST_REQUIRE_EQUAL(base->data, 10);
|
||||
backCast = base.cast<DerivedStruct>();
|
||||
BOOST_REQUIRE_EQUAL(backCast->data, 10);
|
||||
BOOST_REQUIRE_EQUAL(backCast->data2, 20);
|
||||
}
|
||||
BOOST_REQUIRE_EQUAL(backCast->data, 10);
|
||||
BOOST_REQUIRE_EQUAL(backCast->data2, 20);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(unique_ptr)
|
||||
{
|
||||
Seele::UniquePtr<TestStruct> uptr = new TestStruct();
|
||||
Seele::UniquePtr<TestStruct> uptr2 = std::move(uptr);
|
||||
BOOST_REQUIRE_EQUAL(uptr2->data, 10);
|
||||
BOOST_REQUIRE_EQUAL(uptr.isValid(), false);
|
||||
Seele::UniquePtr<TestStruct> uptr = new TestStruct();
|
||||
Seele::UniquePtr<TestStruct> uptr2 = std::move(uptr);
|
||||
BOOST_REQUIRE_EQUAL(uptr2->data, 10);
|
||||
BOOST_REQUIRE_EQUAL(uptr.isValid(), false);
|
||||
}
|
||||
struct ThisReference
|
||||
{
|
||||
ThisReference()
|
||||
{
|
||||
}
|
||||
~ThisReference()
|
||||
{
|
||||
data = 12;
|
||||
}
|
||||
Seele::RefPtr<ThisReference> getRef()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
uint32 data = 1;
|
||||
ThisReference()
|
||||
{
|
||||
}
|
||||
~ThisReference()
|
||||
{
|
||||
data = 12;
|
||||
}
|
||||
Seele::RefPtr<ThisReference> getRef()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
uint32 data = 1;
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE(this_reference)
|
||||
{
|
||||
Seele::RefPtr<ThisReference> ptr2;
|
||||
{
|
||||
Seele::RefPtr<ThisReference> ptr = new ThisReference();
|
||||
BOOST_REQUIRE_EQUAL(ptr->data, 1);
|
||||
ptr2 = ptr->getRef();
|
||||
BOOST_REQUIRE_EQUAL(ptr2->data, 1);
|
||||
ptr2->data = 5;
|
||||
BOOST_REQUIRE_EQUAL(ptr->data, 5);
|
||||
}
|
||||
BOOST_REQUIRE_EQUAL(ptr2->data, 5);
|
||||
Seele::RefPtr<ThisReference> ptr2;
|
||||
{
|
||||
Seele::RefPtr<ThisReference> ptr = new ThisReference();
|
||||
BOOST_REQUIRE_EQUAL(ptr->data, 1);
|
||||
ptr2 = ptr->getRef();
|
||||
BOOST_REQUIRE_EQUAL(ptr2->data, 1);
|
||||
ptr2->data = 5;
|
||||
BOOST_REQUIRE_EQUAL(ptr->data, 5);
|
||||
}
|
||||
BOOST_REQUIRE_EQUAL(ptr2->data, 5);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include <vld.h>
|
||||
#include "ThreadPool.h"
|
||||
|
||||
namespace Seele
|
||||
{
|
||||
@@ -10,10 +9,7 @@ namespace Seele
|
||||
{
|
||||
//_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||
}
|
||||
~GlobalFixture()
|
||||
{
|
||||
getGlobalThreadPool().waitIdle();
|
||||
}
|
||||
~GlobalFixture();
|
||||
void setup()
|
||||
{
|
||||
//Fibers::JobQueue::initJobQueues();
|
||||
|
||||
@@ -42,6 +42,7 @@ Job basicAwaitBase()
|
||||
basicAwaitState = 25;
|
||||
co_await basicAwaitThird();
|
||||
BOOST_REQUIRE_EQUAL(basicAwaitState, 30);
|
||||
co_return;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(basic_coawait)
|
||||
@@ -211,7 +212,7 @@ Job launchStressTest()
|
||||
|
||||
BOOST_AUTO_TEST_CASE(stress_test)
|
||||
{
|
||||
//launchStressTest();
|
||||
launchStressTest();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
Reference in New Issue
Block a user