Provisional multithreading framework

This commit is contained in:
Dynamitos
2021-03-31 12:18:16 +02:00
parent fb3c66cc4c
commit 28f0f88c03
37 changed files with 788 additions and 186 deletions
+2 -2
View File
@@ -12,8 +12,8 @@
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceRoot}/bin/Debug",
"console": "internalConsole",
"environment": [],
"externalConsole": false,
"symbolSearchPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.25.28610\\lib\\x64",
"requireExactSource": false,
"logging": {
@@ -30,9 +30,9 @@
"program": "${workspaceRoot}/bin/Debug/Seele_unit_tests.exe",
"args": [],
"stopAtEntry": false,
"console": "internalConsole",
"cwd": "${workspaceRoot}/bin/Debug",
"environment": [],
"externalConsole": false
},
]
}
+6 -5
View File
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.15)
cmake_minimum_required(VERSION 3.19)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
# Handle superbuild first
option (USE_SUPERBUILD "Whether or not a superbuild should be invoked" ON)
@@ -27,6 +27,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin/${CMAKE_BUILD
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/bin/Debug)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/bin/Release)
add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/MP>)
if (USE_SUPERBUILD)
project (SUPERBUILD NONE)
# execute the superbuild (this script will be invoked again without the
@@ -52,13 +54,12 @@ find_package(SLang REQUIRED)
include_directories(${GLM_INCLUDE_DIRS})
include_directories(${STB_INCLUDE_DIRS})
include_directories(${Vulkan_INCLUDE_DIR})
include_directories(${SPIRV_INCLUDE_DIRS})
#include_directories(${SPIRV_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${GLFW_INCLUDE_DIRS})
include_directories(${SLANG_INCLUDE_DIRS})
include_directories(${ASSIMP_INCLUDE_DIRS})
include_directories(${JSON_INCLUDE_DIRS})
include_directories(${SPIRV_INCLUDE_DIRS})
include_directories(${ENGINE_ROOT})
include_directories(src/Engine)
add_definitions(${Vulkan_DEFINITIONS})
@@ -77,7 +78,7 @@ target_link_libraries(SeeleEngine ${GLFW_LIBRARIES})
target_link_libraries(SeeleEngine ${SLANG_LIBRARIES})
target_link_libraries(SeeleEngine ${ASSIMP_LIBRARIES})
target_link_libraries(SeeleEngine ${JSON_LIBRARY})
target_link_libraries(SeeleEngine ${SPIRV_LIBRARIES})
#target_link_libraries(SeeleEngine ${SPIRV_LIBRARIES})
#target_precompile_headers(SeeleEngine
# PRIVATE
+4 -4
View File
@@ -6,17 +6,17 @@
"debug": {
"short": "Debug",
"long": "Enable debugging and validation",
"buildType": "Debug",
"settings": {
"CMAKE_DEBUG_POSTFIX": "d"
"CMAKE_DEBUG_POSTFIX": "d",
"CMAKE_BUILD_TYPE": "Debug"
}
},
"release": {
"short": "Release",
"long": "Optimize binary for speed",
"buildType": "Release",
"settings": {
"CMAKE_DEBUG_POSTFIX": ""
"CMAKE_DEBUG_POSTFIX": "",
"CMAKE_BUILD_TYPE": "Release"
}
}
}
+2 -1
View File
@@ -29,7 +29,8 @@ if (WIN32)
NAMES assimp-vc${MSVC_TOOLSET_VERSION}-mt${CMAKE_DEBUG_POSTFIX}.lib
PATHS
$ENV{PROGRAMFILES}/lib
${ASSIMP_ROOT}/lib/)
${ASSIMP_ROOT}/lib
${ASSIMP_ROOT}/lib/${CMAKE_BUILD_TYPE})
find_file(
ASSIMP_BINARY
+11 -8
View File
@@ -5,8 +5,11 @@ set(EXTRA_CMAKE_ARGS)
#------------ASSIMP---------------
list(APPEND DEPENDENCIES assimp)
set(ASSIMP_BUILD_TESTS OFF CACHE INTERNAL "")
set(ASSIMP_BUILD_SAMPLES OFF CACHE INTERNAL "")
set(ASSIMP_BUILD_OVERALLS OFF CACHE INTERNAL "")
set(ASSIMP_BUILD_ASSIMP_TOOLS OFF CACHE INTERNAL "")
set(ASSIMP_INSTALL OFF CACHE INTERNAL "")
set(ASSIMP_BUILD_ZLIB OFF CACHE INTERNAL "")
set(BUILD_SHARED_LIBS ON CACHE INTERNAL "")
add_subdirectory(${ASSIMP_ROOT} ${ASSIMP_ROOT})
@@ -74,14 +77,14 @@ ExternalProject_Add(slang
endif()
#----------------SPIR-V-CROSS--------------------
list(APPEND DEPENDENCIES spirv-cross-reflect)
set(SPIRV_CROSS_ENABLE_HLSL OFF CACHE BOOL "")
set(SPIRV_CROSS_ENABLE_TESTS OFF CACHE BOOL "")
set(SPIRV_CROSS_CLI OFF CACHE BOOL "")
set(SPIRV_CROSS_ENABLE_C_API OFF CACHE BOOL "")
set(SPIRV_CROSS_ENABLE_UTIL OFF CACHE BOOL "")
set(SPIRV_CROSS_SKIP_INSTALL ON CACHE BOOL "")
add_subdirectory(${SPIRV_ROOT})
# list(APPEND DEPENDENCIES spirv-cross-reflect)
# set(SPIRV_CROSS_ENABLE_HLSL OFF CACHE BOOL "")
# set(SPIRV_CROSS_ENABLE_TESTS OFF CACHE BOOL "")
# set(SPIRV_CROSS_CLI OFF CACHE BOOL "")
# set(SPIRV_CROSS_ENABLE_C_API OFF CACHE BOOL "")
# set(SPIRV_CROSS_ENABLE_UTIL OFF CACHE BOOL "")
# set(SPIRV_CROSS_SKIP_INSTALL ON CACHE BOOL "")
# add_subdirectory(${SPIRV_ROOT})
#-----------------SeeleEngine--------------------
+1
View File
@@ -0,0 +1 @@
This file needs to be here because otherwise git will delete the folder and the engine can't automatically generate it
+1
View File
@@ -0,0 +1 @@
add_subdirectory(x64/)
+4 -5
View File
@@ -29,8 +29,7 @@ MeshLoader::~MeshLoader()
void MeshLoader::importAsset(const std::filesystem::path &path)
{
//futures.add(std::async(std::launch::async, &MeshLoader::import, this, path));
import(path);
futures.add(std::async(std::launch::async, &MeshLoader::import, this, path));
}
void MeshLoader::loadMaterials(const aiScene* scene, Array<PMaterialAsset>& globalMaterials, Gfx::PGraphics graphics)
@@ -118,7 +117,7 @@ VertexStreamComponent createVertexStream(uint32 size, aiVector3D* sourceData, Gf
vbInfo.vertexSize = sizeof(Vector);
vbInfo.resourceData.data = (uint8 *)buffer.data();
vbInfo.resourceData.owner = Gfx::QueueType::DEDICATED_TRANSFER;
vbInfo.resourceData.size = sizeof(Vector) * buffer.size();
vbInfo.resourceData.size = sizeof(Vector) * (uint32)buffer.size();
return VertexStreamComponent(graphics->createVertexBuffer(vbInfo), 0, vbInfo.vertexSize, Gfx::SE_FORMAT_R32G32B32_SFLOAT);
}
VertexStreamComponent createVertexStream(uint32 size, aiVector2D* sourceData, Gfx::PGraphics graphics)
@@ -133,7 +132,7 @@ VertexStreamComponent createVertexStream(uint32 size, aiVector2D* sourceData, Gf
vbInfo.vertexSize = sizeof(Vector2);
vbInfo.resourceData.data = (uint8 *)buffer.data();
vbInfo.resourceData.owner = Gfx::QueueType::DEDICATED_TRANSFER;
vbInfo.resourceData.size = sizeof(Vector2) * buffer.size();
vbInfo.resourceData.size = sizeof(Vector2) * (uint32)buffer.size();
return VertexStreamComponent(graphics->createVertexBuffer(vbInfo), 0, vbInfo.vertexSize, Gfx::SE_FORMAT_R32G32_SFLOAT);
}
void MeshLoader::loadGlobalMeshes(const aiScene* scene, Array<PMesh>& globalMeshes, const Array<PMaterialAsset>& materials, Gfx::PGraphics graphics)
@@ -180,7 +179,7 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, Array<PMesh>& globalMesh
idxInfo.indexType = Gfx::SE_INDEX_TYPE_UINT32;
idxInfo.resourceData.data = (uint8 *)indices.data();
idxInfo.resourceData.owner = Gfx::QueueType::DEDICATED_TRANSFER;
idxInfo.resourceData.size = sizeof(uint32) * indices.size();
idxInfo.resourceData.size = sizeof(uint32) * (uint32)indices.size();
Gfx::PIndexBuffer indexBuffer = graphics->createIndexBuffer(idxInfo);
indexBuffer->transferOwnership(Gfx::QueueType::GRAPHICS);
+2
View File
@@ -5,7 +5,9 @@ target_sources(SeeleEngine
main.cpp)
add_subdirectory(Asset/)
add_subdirectory(Arch/)
add_subdirectory(Containers/)
add_subdirectory(Fibers/)
add_subdirectory(Graphics/)
add_subdirectory(Material/)
add_subdirectory(Math/)
+126 -100
View File
@@ -25,12 +25,12 @@ namespace Seele
//std::memset(_data, 0, sizeof(T) * DEFAULT_ALLOC_SIZE);
refreshIterators();
}
Array(uint32 size, T value = T())
Array(size_t size, T value = T())
: allocated(size), arraySize(size)
{
_data = new T[size];
assert(_data != nullptr);
for (uint32 i = 0; i < size; ++i)
for (size_t i = 0; i < size; ++i)
{
assert(i < size);
_data[i] = value;
@@ -38,7 +38,7 @@ namespace Seele
refreshIterators();
}
Array(std::initializer_list<T> init)
: allocated((uint32)init.size()), arraySize((uint32)init.size())
: allocated(init.size()), arraySize(init.size())
{
_data = new T[init.size()];
auto it = init.begin();
@@ -194,6 +194,17 @@ namespace Seele
}
return endIt;
}
Iterator find(T&& item)
{
for (uint32 i = 0; i < arraySize; ++i)
{
if (_data[i] == item)
{
return Iterator(&_data[i]);
}
}
return endIt;
}
Iterator begin() const
{
return beginIt;
@@ -215,11 +226,11 @@ namespace Seele
{
if (arraySize == allocated)
{
uint32 newSize = arraySize + 1;
size_t newSize = arraySize + 1;
allocated = calculateGrowth(newSize);
T *tempArray = new T[allocated];
assert(tempArray != nullptr);
for (uint32 i = 0; i < arraySize; ++i)
for (size_t i = 0; i < arraySize; ++i)
{
tempArray[i] = _data[i];
}
@@ -230,6 +241,25 @@ namespace Seele
refreshIterators();
return _data[arraySize - 1];
}
T &add(T&& item)
{
if (arraySize == allocated)
{
size_t newSize = arraySize + 1;
allocated = calculateGrowth(newSize);
T *tempArray = new T[allocated];
assert(tempArray != nullptr);
for (size_t i = 0; i < arraySize; ++i)
{
tempArray[i] = std::move(_data[i]);
}
delete[] _data;
_data = tempArray;
}
_data[arraySize++] = std::move(item);
refreshIterators();
return _data[arraySize - 1];
}
T &addUnique(const T &item = T())
{
Iterator it;
@@ -240,22 +270,22 @@ namespace Seele
return add(item);
}
template<typename... args>
T &emplace(args...)
T &emplace(args... arguments)
{
if (arraySize == allocated)
{
uint32 newSize = arraySize + 1;
size_t newSize = arraySize + 1;
allocated = calculateGrowth(newSize);
T *tempArray = new T[allocated];
assert(tempArray != nullptr);
for (uint32 i = 0; i < arraySize; ++i)
for (size_t i = 0; i < arraySize; ++i)
{
tempArray[i] = _data[i];
}
delete[] _data;
_data = tempArray;
}
_data[arraySize++] = T(args...);
_data[arraySize++] = T(arguments...);
refreshIterators();
return _data[arraySize - 1];
}
@@ -271,7 +301,7 @@ namespace Seele
}
else
{
_data[index] = _data[arraySize - 1];
_data[index] = std::move(_data[arraySize - 1]);
}
arraySize--;
}
@@ -283,7 +313,7 @@ namespace Seele
allocated = 0;
refreshIterators();
}
void resize(uint32 newSize)
void resize(size_t newSize)
{
if (newSize < allocated)
{
@@ -301,27 +331,31 @@ namespace Seele
}
refreshIterators();
}
inline uint32 indexOf(Iterator iterator)
inline size_t indexOf(Iterator iterator)
{
return iterator - beginIt;
}
inline uint32 indexOf(ConstIterator iterator) const
inline size_t indexOf(ConstIterator iterator) const
{
return iterator.p - beginIt.p;
}
inline uint32 indexOf(T& t)
inline size_t indexOf(T& t)
{
return indexOf(find(t));
}
inline uint32 indexOf(const T& t) const
inline size_t indexOf(const T& t) const
{
return indexOf(find(t));
}
inline uint32 size() const
inline size_t size() const
{
return arraySize;
}
inline uint32 capacity() const
inline size_t empty() const
{
return arraySize == 0;
}
inline size_t capacity() const
{
return allocated;
}
@@ -338,44 +372,27 @@ namespace Seele
arraySize--;
refreshIterators();
}
T &operator[](uint32 index)
T &operator[](size_t index)
{
assert(index < arraySize);
return _data[index];
}
inline T &operator[](size_t index)
{
return this->operator[]((uint32)index);
}
inline T &operator[](int32 index)
{
return this->operator[]((uint32)index);
}
const T &operator[](uint32 index) const
const T &operator[](size_t index) const
{
assert(index < arraySize);
return _data[index];
}
inline const T &operator[](size_t index) const
{
return this->operator[]((uint32)index);
}
inline const T &operator[](int32 index) const
{
return this->operator[]((uint32)index);
}
private:
uint32 calculateGrowth(uint32 newSize) const
size_t calculateGrowth(size_t newSize) const
{
const uint32 oldCapacity = capacity();
const size_t oldCapacity = capacity();
if (oldCapacity > UINT32_MAX - oldCapacity / 2)
if (oldCapacity > SIZE_MAX - oldCapacity / 2)
{
return newSize; // geometric growth would overflow
}
const uint32 geometric = oldCapacity + oldCapacity / 2;
const size_t geometric = oldCapacity + oldCapacity / 2;
if (geometric < newSize)
{
@@ -395,71 +412,30 @@ namespace Seele
{
ar & arraySize;
ar & allocated;
for(uint32 i = 0; i < arraySize; ++i)
for(size_t i = 0; i < arraySize; ++i)
ar & _data[i];
refreshIterators();
}
uint32 arraySize;
uint32 allocated;
size_t arraySize;
size_t allocated;
Iterator beginIt;
Iterator endIt;
T *_data;
};
template <typename T, uint32 N>
template <typename T, size_t N>
struct StaticArray
{
public:
StaticArray()
{
beginIt = Iterator(_data);
endIt = Iterator(_data + N);
}
StaticArray(T value)
{
for (int i = 0; i < N; ++i)
{
_data[i] = value;
}
beginIt = Iterator(_data);
endIt = Iterator(_data + N);
}
~StaticArray()
{
}
inline uint32 size() const
{
return N;
}
inline T *data()
{
return _data;
}
inline const T *data() const
{
return _data;
}
T &operator[](int index)
{
assert(index >= 0 && index < N);
return _data[index];
}
const T &operator[](int index) const
{
assert(index >= 0 && index < N);
return _data[index];
}
public:
template <typename X>
class IteratorBase
{
public:
typedef std::forward_iterator_tag iterator_category;
typedef X value_type;
typedef std::ptrdiff_t difference_type;
typedef X &reference;
typedef X *pointer;
using iterator_category = std::forward_iterator_tag;
using value_type = X;
using difference_type = std::ptrdiff_t;
using reference = X&;
using pointer = X*;
IteratorBase(X *x = nullptr)
: p(x)
@@ -500,36 +476,86 @@ namespace Seele
private:
X *p;
};
typedef IteratorBase<T> Iterator;
typedef IteratorBase<const T> ConstIterator;
using value_type = T;
using size_type = size_t;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
Iterator begin()
using iterator = IteratorBase<T>;
using const_iterator = IteratorBase<const T>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
StaticArray()
{
beginIt = iterator(_data);
endIt = iterator(_data + N);
}
StaticArray(T value)
{
for (int i = 0; i < N; ++i)
{
_data[i] = value;
}
beginIt = iterator(_data);
endIt = iterator(_data + N);
}
~StaticArray()
{
}
inline size_type size() const
{
return N;
}
inline pointer data()
{
return _data;
}
inline const_pointer data() const
{
return _data;
}
constexpr reference operator[](size_type index) noexcept
{
assert(index >= 0 && index < N);
return _data[index];
}
constexpr const_reference operator[](size_type index) const noexcept
{
assert(index >= 0 && index < N);
return _data[index];
}
iterator begin()
{
return beginIt;
}
Iterator end()
iterator end()
{
return endIt;
}
ConstIterator begin() const
const_iterator begin() const
{
return beginIt;
}
ConstIterator end() const
const_iterator end() const
{
return beginIt;
}
private:
T _data[N];
Iterator beginIt;
Iterator endIt;
iterator beginIt;
iterator endIt;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned int version)
{
ar & N;
ar & _data;
refreshIterators();
}
};
} // namespace Seele
+8
View File
@@ -250,6 +250,14 @@ public:
refreshIterators();
return Iterator(next);
}
void popBack()
{
remove(Iterator(tail->prev));
}
void popFront()
{
remove(Iterator(root));
}
Iterator insert(Iterator pos, const T &value)
{
_size++;
+56 -26
View File
@@ -1,4 +1,5 @@
#pragma once
#include <utility>
#include "Array.h"
namespace Seele
@@ -9,12 +10,15 @@ struct Pair
public:
Pair()
: key(K()), value(V())
{
}
Pair(K key, V value)
: key(key), value(value)
{
}
{}
template<class KeyType>
explicit Pair(KeyType&& key)
: key(key), value(V())
{}
template<class KeyType, class ValueType>
explicit Pair(KeyType&& key, ValueType&& value)
: key(std::move(key)), value(std::move(value))
{}
K key;
V value;
};
@@ -28,11 +32,12 @@ private:
Node *leftChild;
Node *rightChild;
Node()
: leftChild(nullptr), rightChild(nullptr), pair(K(), V())
: leftChild(nullptr), rightChild(nullptr), pair()
{
}
Node(const K &key)
: leftChild(nullptr), rightChild(nullptr), pair(key, V())
template<class KeyType, class ValueType>
explicit Node(KeyType&& key, ValueType&& value)
: leftChild(nullptr), rightChild(nullptr), pair(key, value)
{
}
Node(const Node& other)
@@ -242,7 +247,7 @@ public:
Iterator operator--(int)
{
Iterator tmp(*this);
++*this;
--*this;
return tmp;
}
Iterator operator++(int)
@@ -256,8 +261,7 @@ public:
Node *node;
Array<Node *> traversal;
};
V &operator[](const K &key)
V &operator[](const K& key)
{
root = splay(root, key);
if (root == nullptr || root->pair.key < key || key < root->pair.key)
@@ -268,7 +272,18 @@ public:
}
return root->pair.value;
}
Iterator find(const K &key)
V &operator[](K&& key)
{
root = splay(root, std::forward<K>(key));
if (root == nullptr || root->pair.key < key || key < root->pair.key)
{
root = insert(root, std::forward<K>(key));
_size++;
refreshIterators();
}
return root->pair.value;
}
Iterator find(const K& key)
{
root = splay(root, key);
if (root == nullptr || root->pair.key != key)
@@ -277,10 +292,25 @@ public:
}
return Iterator(root);
}
Iterator erase(const K &key)
Iterator find(K&& key)
{
root = splay(root, std::move(key));
if (root == nullptr || root->pair.key != key)
{
return endIt;
}
return Iterator(root);
}
Iterator erase(const K& key)
{
root = remove(root, key);
refreshIterators();
return Iterator(root);
}
Iterator erase(K&& key)
{
root = remove(root, std::move(key));
refreshIterators();
return Iterator(root);
}
void clear()
@@ -290,9 +320,9 @@ public:
_size = 0;
refreshIterators();
}
bool exists(const K &key)
bool exists(K&& key)
{
return find(key) != endIt;
return find(std::forward<K>(key)) != endIt;
}
Iterator begin() const
{
@@ -365,21 +395,19 @@ private:
y->leftChild = node;
return y;
}
Node *makeNode(const K &key)
{
return new Node(key);
}
Node *insert(Node *r, const K &key)
template<class KeyType>
Node *insert(Node *r, KeyType&& key)
{
if (r == nullptr)
return makeNode(key);
{
return new Node(std::forward<KeyType>(key), V());
}
r = splay(r, key);
if (!(r->pair.key < key || key < r->pair.key))
return r;
Node *newNode = makeNode(key);
Node *newNode = new Node(std::forward<KeyType>(key), V());
if (key < r->pair.key)
{
@@ -395,7 +423,8 @@ private:
}
return newNode;
}
Node *remove(Node *r, const K &key)
template<class KeyType>
Node *remove(Node *r, KeyType&& key)
{
Node *temp;
if (!r)
@@ -424,7 +453,8 @@ private:
delete temp;
return r;
}
Node *splay(Node *r, const K &key)
template<class KeyType>
Node *splay(Node *r, KeyType&& key)
{
if (r == nullptr || !(r->pair.key < key || key < r->pair.key))
{
+6
View File
@@ -0,0 +1,6 @@
target_sources(SeeleEngine
PRIVATE
Fibers.h
Fibers.cpp
JobQueue.h
JobQueue.cpp)
+36
View File
@@ -0,0 +1,36 @@
#include "Fibers.h"
using namespace Seele;
using namespace Seele::Fibers;
std::atomic_uint64_t FiberJob::jobIDGenerator;
Counter::Counter()
{
count.store(0);
}
Counter::Counter(uint64 initialValue)
{
count.store(initialValue);
}
Counter::~Counter()
{
}
AwaitCounter&& FiberTask::promise_type::await_transform(AwaitCounter&& awaitCounter)
{
counter = awaitCounter.counter;
target = awaitCounter.target;
priority = awaitCounter.priority;
return std::move(awaitCounter);
}
FiberJob::FiberJob()
{
}
FiberJob::~FiberJob()
{
}
+205
View File
@@ -0,0 +1,205 @@
#pragma once
#include "MinimalEngine.h"
#include "JobQueue.h"
#include <atomic>
#include <functional>
namespace Seele
{
namespace Fibers
{
class Counter
{
public:
Counter();
Counter(uint64 initialValue);
~Counter();
inline void increment()
{
count++;
}
inline void decrement()
{
count--;
}
inline void setValue(uint64 value)
{
count.store(value);
}
inline uint64 getValue()
{
return count.load();
}
inline bool greaterEqual(uint64 target)
{
return count.load() >= target;
}
inline bool greaterThan(uint64 target)
{
return count.load() > target;
}
inline bool lessEqual(uint64 target)
{
return count.load() <= target;
}
inline bool lessThan(uint64 target)
{
return count.load() < target;
}
inline bool equals(uint64 target)
{
return count.load() == target;
}
friend std::strong_ordering operator<=>(const Counter& counter, uint64 other)
{
return counter.count.load() <=> other;
}
friend std::ostream& operator<<(std::ostream& stream, const Counter* counter)
{
stream << counter->count;
return stream;
}
friend std::ostream& operator<<(std::ostream& stream, PCounter counter)
{
stream << counter->count;
return stream;
}
private:
std::atomic_uint64_t count;
};
DEFINE_REF(Counter);
struct AwaitCounter
{
PCounter counter;
uint64 target;
JobPriority priority = JobPriority::MEDIUM;
bool await_ready() { return counter->greaterEqual(target); }
void await_suspend(std::coroutine_handle<> h) {
}
void await_resume() {}
};
struct AwaitCounter;
class FiberTask
{
public:
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
private:
promise_type* promise;
public:
FiberTask() = default;
explicit FiberTask(promise_type* promise)
: promise(promise) {}
FiberTask(const FiberTask& other)
: promise(other.promise) {}
FiberTask(FiberTask&& other)
: promise(std::move(other.promise)) {}
FiberTask& operator=(const FiberTask& other)
{
promise = other.promise;
return *this;
}
FiberTask& operator=(FiberTask&& other)
{
promise = std::move(other.promise);
return *this;
}
inline void resume() { promise->resume(); }
inline void destroy() { promise->destroy(); }
inline bool done() { return promise->done(); }
inline PCounter getCounter() const { return promise->counter; }
inline uint64 getTarget() const { return promise->target; }
inline JobPriority getPriority() const { return promise->priority; }
struct promise_type
{
promise_type()
{
handle = handle_type::from_promise(*this);
}
~promise_type() = default;
promise_type(const promise_type&) = delete;
promise_type(promise_type&&) = delete;
promise_type &operator=(const promise_type&) = delete;
promise_type &operator=(promise_type&&) = delete;
FiberTask get_return_object()
{
return FiberTask(this);
}
auto initial_suspend() { return std::suspend_never{}; }
auto final_suspend() noexcept { return std::suspend_always{}; }
auto return_void() {}
void unhandled_exception() { std::exit(1); }
AwaitCounter&& await_transform(AwaitCounter&& awaitCounter);
inline void resume() { handle.resume(); }
inline void destroy() { handle.destroy(); }
inline bool done() { return handle.done(); }
private:
handle_type handle;
PCounter counter;
uint64 target;
JobPriority priority;
friend class FiberTask;
};
};
class FiberJob
{
public:
FiberJob();
template<typename func, typename... args>
FiberJob(PCounter counter, func function, args... arg)
: counter(counter), function(std::bind(function, arg...))
{
jobID = jobIDGenerator.fetch_add(1);
}
template<typename func, typename...args>
FiberJob(PCounter counter, JobPriority priority, func function, args... arg)
: counter(counter), priority(priority), function(std::bind(function, arg...))
{
}
FiberJob(const FiberJob& other) = delete;
FiberJob(FiberJob&& other)
: counter(std::move(other.counter))
, jobID(std::move(other.jobID))
, priority(std::move(other.priority))
, function(std::move(other.function))
{
}
~FiberJob();
FiberJob& operator=(const FiberJob& other) = delete;
FiberJob& operator=(FiberJob&& other)
{
if(this != &other)
{
counter = std::move(other.counter);
jobID = std::move(other.jobID);
priority = std::move(other.priority);
function = std::move(other.function);
}
return *this;
}
void operator()()
{
FiberTask task = function();
if(!task.done())
{
JobQueue::suspendJob(std::move(task));
}
else
{
counter->increment();
task.destroy();
}
}
inline JobPriority getPriority()
{
return priority;
}
private:
PCounter counter;
uint64 jobID;
static std::atomic_uint64_t jobIDGenerator;
JobPriority priority = JobPriority::MEDIUM;
std::function<FiberTask()> function;
};
} // namespace Fibers
} // namespace Seele
+134
View File
@@ -0,0 +1,134 @@
#include "JobQueue.h"
#include "Fibers.h"
#include <Windows.h>
#include <processthreadsapi.h>
using namespace Seele;
using namespace Seele::Fibers;
std::wstring toString(JobPriority priority)
{
switch (priority)
{
case JobPriority::HIGH:
return L"HIGH";
case JobPriority::MEDIUM:
return L"MEDIUM";
case JobPriority::LOW:
return L"LOW";
case JobPriority::IO:
return L"IO";
default:
return L"Illegal Priority";
}
}
Array<JobQueue*> JobQueue::workers;
StaticArray<JobPriorityInfo, (size_t)JobPriority::NUM_PRIORITIES> JobQueue::priorityQueues;
JobQueue::JobQueue(JobPriority priority)
: priority(priority)
{
threadHandle = std::thread(&JobQueue::work, this);
SetThreadDescription(threadHandle.native_handle(), toString(priority).c_str());
}
JobQueue::~JobQueue()
{
running = false;
threadHandle.join();
}
void JobQueue::initJobQueues()
{
// TODO: make this dependent on actual cores
JobPriority priorities[16] = {
JobPriority::IO, JobPriority::IO,
JobPriority::LOW, JobPriority::LOW, JobPriority::LOW, JobPriority::LOW,
JobPriority::MEDIUM, JobPriority::MEDIUM, JobPriority::MEDIUM, JobPriority::MEDIUM, JobPriority::MEDIUM,
JobPriority::HIGH, JobPriority::HIGH, JobPriority::HIGH, JobPriority::HIGH, JobPriority::HIGH};
for(uint32 i = 0; i < 16; ++i)
{
workers.add(new JobQueue(priorities[i]));
}
}
void JobQueue::cleanupJobQueues()
{
for(auto worker : workers)
{
delete worker;
}
}
void JobQueue::runJobs(FiberJob* jobs, uint32 numJobs)
{
for(uint32 i = 0; i < numJobs; ++i)
{
JobPriorityInfo& info = priorityQueues[(size_t)jobs[i].getPriority()];
std::unique_lock lock(info.jobQueueLock);
info.jobQueue.add(std::move(jobs[i]));
//info.jobQueueCV.notify_one();
}
}
void JobQueue::waitForCounter(PCounter counter, uint32 waitFor)
{
while(counter->lessThan(waitFor))
std::this_thread::yield();
}
void JobQueue::suspendJob(FiberTask&& task)
{
JobPriorityInfo& info = priorityQueues[(size_t)task.getPriority()];
std::unique_lock lock(info.jobQueueLock);
info.waiterQueue[task.getCounter()].add(task);
}
void JobQueue::refreshWaiterQueue()
{
JobPriorityInfo& info = priorityQueues[(size_t)priority];
//shortcut to avoid iterator creation
if(info.waiterQueue.empty())
return;
for(auto it : info.waiterQueue)
{
auto& entries = info.waiterQueue[it.key];
for(uint32 i = 0; i < entries.size(); ++i)
{
if(it.key->greaterEqual(entries[i].getTarget()))
{
info.resumableTasks.add(std::move(entries[i]));
entries.remove(i);
i--;
}
}
}
}
void JobQueue::work()
{
JobPriorityInfo& targetInfo = priorityQueues[(size_t)priority];
auto& jobQueue = targetInfo.jobQueue;
auto& resumableTasks = targetInfo.resumableTasks;
while(running)
{
std::unique_lock lock(targetInfo.jobQueueLock);
refreshWaiterQueue();
if(resumableTasks.size() > 0)
{
FiberTask task = std::move(resumableTasks.front());
resumableTasks.popFront();
lock.unlock();
task.resume();
lock.lock();
}
if(jobQueue.size() > 0)
{
FiberJob job = std::move(jobQueue.front());
jobQueue.popFront();
lock.unlock();
job();
lock.lock();
}
}
}
+56
View File
@@ -0,0 +1,56 @@
#pragma once
#include "MinimalEngine.h"
#include "Containers/List.h"
#include <coroutine>
namespace Seele
{
namespace Fibers
{
class FiberJob;
DECLARE_REF(Counter);
enum class JobPriority : size_t
{
HIGH = 0,
MEDIUM,
LOW,
IO,
NUM_PRIORITIES
};
struct AtomicJobQueue
{
};
class FiberTask;
struct JobPriorityInfo
{
List<FiberJob> jobQueue;
Map<PCounter, Array<FiberTask>> waiterQueue;
List<FiberTask> resumableTasks;
std::mutex jobQueueLock;
};
class JobQueue
{
public:
JobQueue(JobPriority priority);
JobQueue(const JobQueue& other) = delete;
JobQueue(JobQueue&& other) = delete;
JobQueue& operator=(const JobQueue& other) = delete;
JobQueue& operator=(JobQueue&& other) = delete;
~JobQueue();
static void initJobQueues();
static void cleanupJobQueues();
static void runJobs(FiberJob* jobs, uint32 numJobs);
//This does in fact not do any coroutine stuff, but is a simple busy wait
//For coroutine waits, you have to be in a coroutine, and
static void waitForCounter(PCounter counter, uint32 waitFor);
static void suspendJob(FiberTask&& task);
void refreshWaiterQueue();
private:
void work();
static Array<JobQueue*> workers;
static StaticArray<JobPriorityInfo, (size_t)JobPriority::NUM_PRIORITIES> priorityQueues;
std::thread threadHandle;
JobPriority priority;
bool running = true;
};
} // namespace Fibers
} // namespace Seele
+1 -1
View File
@@ -57,7 +57,7 @@ private:
template<class Archive>
void serialize(Archive& ar, const unsigned int version)
{
ar & referencedMaterial->getFullPath();
//ar & referencedMaterial->getFullPath();
//TODO:
}
};
+2 -2
View File
@@ -91,7 +91,7 @@ Gfx::VertexElement VertexShaderInput::accessStreamComponent(const VertexStreamCo
vertexStream.stride = component.stride;
vertexStream.offset = component.offset;
return Gfx::VertexElement(streams.indexOf(streams.addUnique(vertexStream)), component.offset, component.type, attributeIndex, vertexStream.stride);
return Gfx::VertexElement((uint8)streams.indexOf(streams.addUnique(vertexStream)), component.offset, component.type, attributeIndex, vertexStream.stride);
}
Gfx::VertexElement VertexShaderInput::accessPositionStreamComponent(const VertexStreamComponent& component, uint8 attributeIndex)
@@ -101,7 +101,7 @@ Gfx::VertexElement VertexShaderInput::accessPositionStreamComponent(const Vertex
vertexStream.stride = component.stride;
vertexStream.offset = component.offset;
return Gfx::VertexElement(streams.indexOf(streams.addUnique(vertexStream)), component.offset, component.type, attributeIndex, vertexStream.stride);
return Gfx::VertexElement((uint8)streams.indexOf(streams.addUnique(vertexStream)), component.offset, component.type, attributeIndex, vertexStream.stride);
}
void VertexShaderInput::initDeclaration(Gfx::PGraphics graphics, Array<Gfx::VertexElement>& elements)
@@ -65,7 +65,7 @@ void CmdBuffer::beginRenderPass(PRenderPass newRenderPass, PFramebuffer newFrame
VkRenderPassBeginInfo beginInfo =
init::RenderPassBeginInfo();
beginInfo.clearValueCount = renderPass->getClearValueCount();
beginInfo.clearValueCount = (uint32)renderPass->getClearValueCount();
beginInfo.pClearValues = renderPass->getClearValues();
beginInfo.renderArea = renderPass->getRenderArea();
beginInfo.renderPass = renderPass->getHandle();
@@ -95,7 +95,7 @@ void CmdBuffer::executeCommands(Array<Gfx::PRenderCommand> commands)
}
cmdBuffers[i] = command->getHandle();
}
vkCmdExecuteCommands(handle, cmdBuffers.size(), cmdBuffers.data());
vkCmdExecuteCommands(handle, (uint32)cmdBuffers.size(), cmdBuffers.data());
}
void CmdBuffer::addWaitSemaphore(VkPipelineStageFlags flags, PSemaphore semaphore)
@@ -212,7 +212,7 @@ void SecondaryCmdBuffer::bindDescriptor(const Array<Gfx::PDescriptorSet>& descri
boundDescriptors.add(descriptorSet);
sets[descriptorSet->getSetIndex()] = descriptorSet->getHandle();
}
vkCmdBindDescriptorSets(handle, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getLayout(), 0, descriptorSets.size(), sets, 0, nullptr);
vkCmdBindDescriptorSets(handle, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getLayout(), 0, (uint32)descriptorSets.size(), sets, 0, nullptr);
delete[] sets;
}
void SecondaryCmdBuffer::bindVertexBuffer(const Array<VertexInputStream>& streams)
@@ -225,7 +225,7 @@ void SecondaryCmdBuffer::bindVertexBuffer(const Array<VertexInputStream>& stream
buffers[i] = buf->getHandle();
offsets[i] = streams[i].offset;
};
vkCmdBindVertexBuffers(handle, 0, streams.size(), buffers.data(), offsets.data());
vkCmdBindVertexBuffers(handle, 0, (uint32)streams.size(), buffers.data(), offsets.data());
}
void SecondaryCmdBuffer::bindIndexBuffer(Gfx::PIndexBuffer indexBuffer)
{
@@ -39,7 +39,7 @@ void DescriptorLayout::create()
binding.pImmutableSamplers = nullptr;
}
VkDescriptorSetLayoutCreateInfo createInfo =
init::DescriptorSetLayoutCreateInfo(bindings.data(), bindings.size());
init::DescriptorSetLayoutCreateInfo(bindings.data(), (uint32)bindings.size());
VK_CHECK(vkCreateDescriptorSetLayout(graphics->getDevice(), &createInfo, nullptr, &layoutHandle));
allocator = new DescriptorAllocator(graphics, *this);
@@ -75,7 +75,7 @@ void PipelineLayout::create()
}
VkPipelineLayoutCreateInfo createInfo =
init::PipelineLayoutCreateInfo(vulkanDescriptorLayouts.data(), vulkanDescriptorLayouts.size());
init::PipelineLayoutCreateInfo(vulkanDescriptorLayouts.data(), (uint32)vulkanDescriptorLayouts.size());
Array<VkPushConstantRange> vkPushConstants(pushConstants.size());
for (size_t i = 0; i < pushConstants.size(); i++)
{
@@ -83,7 +83,7 @@ void PipelineLayout::create()
vkPushConstants[i].size = pushConstants[i].size;
vkPushConstants[i].stageFlags = cast((VkShaderStageFlagBits)pushConstants[i].stageFlags);
}
createInfo.pushConstantRangeCount = vkPushConstants.size();
createInfo.pushConstantRangeCount = (uint32)vkPushConstants.size();
createInfo.pPushConstantRanges = vkPushConstants.data();
boost::crc_32_type result;
@@ -198,7 +198,7 @@ void DescriptorSet::updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx::
bool DescriptorSet::operator<(Gfx::PDescriptorSet other)
{
PDescriptorSet otherSet = other.cast<DescriptorSet>();
return setHandle < otherSet->setHandle;
return this < otherSet.getHandle();
}
void DescriptorSet::writeChanges()
@@ -210,7 +210,7 @@ void DescriptorSet::writeChanges()
currentlyBound->getManager()->waitForCommands(currentlyBound);
currentlyBound = nullptr;
}
vkUpdateDescriptorSets(graphics->getDevice(), writeDescriptors.size(), writeDescriptors.data(), 0, nullptr);
vkUpdateDescriptorSets(graphics->getDevice(), (uint32)writeDescriptors.size(), writeDescriptors.data(), 0, nullptr);
writeDescriptors.clear();
imageInfos.clear();
bufferInfos.clear();
@@ -241,7 +241,7 @@ DescriptorAllocator::DescriptorAllocator(PGraphics graphics, DescriptorLayout &l
poolSizes.add(size);
}
}
VkDescriptorPoolCreateInfo createInfo = init::DescriptorPoolCreateInfo(poolSizes.size(), poolSizes.data(), maxSets);
VkDescriptorPoolCreateInfo createInfo = init::DescriptorPoolCreateInfo((uint32)poolSizes.size(), poolSizes.data(), maxSets);
VK_CHECK(vkCreateDescriptorPool(graphics->getDevice(), &createInfo, nullptr, &poolHandle));
}
@@ -34,7 +34,7 @@ Framebuffer::Framebuffer(PGraphics graphics, PRenderPass renderPass, Gfx::PRende
VkFramebufferCreateInfo createInfo =
init::FramebufferCreateInfo(
renderPass->getHandle(),
attachments.size(),
(uint32)attachments.size(),
attachments.data(),
renderPass->getRenderArea().extent.width,
renderPass->getRenderArea().extent.height,
@@ -215,9 +215,9 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo
std::memcpy(hashStruct.attribs, attributes.data(), attributes.size() * sizeof(VkVertexInputAttributeDescription));
vertexInput.pVertexBindingDescriptions = bindings.data();
vertexInput.vertexBindingDescriptionCount = bindings.size();
vertexInput.vertexBindingDescriptionCount = (uint32)bindings.size();
vertexInput.pVertexAttributeDescriptions = attributes.data();
vertexInput.vertexAttributeDescriptionCount = attributes.size();
vertexInput.vertexAttributeDescriptionCount = (uint32)attributes.size();
VkPipelineInputAssemblyStateCreateInfo assemblyInfo =
init::PipelineInputAssemblyStateCreateInfo(
@@ -291,7 +291,7 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo
}
VkPipelineColorBlendStateCreateInfo blendState =
init::PipelineColorBlendStateCreateInfo(
blendAttachments.size(),
(uint32)blendAttachments.size(),
blendAttachments.data()
);
blendState.logicOpEnable = gfxInfo.colorBlend.logicOpEnable;
@@ -91,10 +91,10 @@ RenderPass::RenderPass(PGraphics graphics, Gfx::PRenderTargetLayout layout)
VkSubpassDescription subPassDesc =
init::SubpassDescription(
VK_PIPELINE_BIND_POINT_GRAPHICS,
colorRefs.size(),
(uint32)colorRefs.size(),
colorRefs.data(),
&depthRef,
inputRefs.size(),
(uint32)inputRefs.size(),
inputRefs.data());
VkSubpassDependency dependency = {};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
@@ -108,7 +108,7 @@ RenderPass::RenderPass(PGraphics graphics, Gfx::PRenderTargetLayout layout)
VkRenderPassCreateInfo info =
init::RenderPassCreateInfo(
attachments.size(),
(uint32)attachments.size(),
attachments.data(),
1,
&subPassDesc,
@@ -15,7 +15,7 @@ public:
{
return renderPass;
}
inline uint32 getClearValueCount() const
inline size_t getClearValueCount() const
{
return clearValues.size();
}
+1 -1
View File
@@ -113,7 +113,7 @@ void Shader::create(const ShaderCreateInfo& createInfo)
spAddSearchPath(request, "shaders/lib/");
spAddSearchPath(request, "shaders/generated/");
spSetGlobalGenericArgs(request, createInfo.typeParameter.size(), createInfo.typeParameter.data());
spSetGlobalGenericArgs(request, (int)createInfo.typeParameter.size(), createInfo.typeParameter.data());
int entryPointIndex = spAddEntryPoint(request, translationUnitIndex, entryPointName.c_str(), getStageFromShaderType(type));
if(spCompile(request))
+7 -7
View File
@@ -65,7 +65,7 @@ void Material::compile()
for(auto param : j["params"].items())
{
std::string type = param.value()["type"].get<std::string>();
auto default = param.value().find("default");
auto defaultValue = param.value().find("default");
if(type.compare("float") == 0)
{
PFloatParameter p = new FloatParameter(param.key(), uniformBufferOffset, 0);
@@ -76,9 +76,9 @@ void Material::compile()
uniformBinding = bindingCounter++;
}
uniformBufferOffset += 4;
if(default != param.value().end())
if(defaultValue != param.value().end())
{
p->data = std::stof(default.value().get<std::string>());
p->data = std::stof(defaultValue.value().get<std::string>());
}
parameters.add(p);
}
@@ -92,9 +92,9 @@ void Material::compile()
uniformBinding = bindingCounter++;
}
uniformBufferOffset += 12;
if(default != param.value().end())
if(defaultValue != param.value().end())
{
p->data = parseVector(default.value().get<std::string>().c_str());
p->data = parseVector(defaultValue.value().get<std::string>().c_str());
}
parameters.add(p);
}
@@ -102,9 +102,9 @@ void Material::compile()
{
PTextureParameter p = new TextureParameter(param.key(), 0, bindingCounter);
layout->addDescriptorBinding(bindingCounter++, Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
if(default != param.value().end())
if(defaultValue != param.value().end())
{
p->data = AssetRegistry::findTexture(default.value().get<std::string>());
p->data = AssetRegistry::findTexture(defaultValue.value().get<std::string>());
}
else
{
+1 -1
View File
@@ -10,7 +10,7 @@ public:
Transform();
Transform(const Transform &other);
Transform(Transform &&other);
Transform(Vector position);
explicit Transform(Vector position);
Transform(Vector position, Quaternion rotation);
Transform(Vector position, Quaternion rotation, Vector scale);
Transform(Quaternion rotation, Vector scale);
+1 -1
View File
@@ -108,7 +108,7 @@ public:
private:
T *handle;
uint64 refCount;
std::atomic_uint64_t refCount;
};
template <typename T>
+1 -1
View File
@@ -15,7 +15,7 @@ Scene::Scene(Gfx::PGraphics graphics)
lightEnv.directionalLights[0].intensity = Vector4(1, 1, 1, 1);
lightEnv.numDirectionalLights = 1;
lightEnv.numPointLights = 0;
srand(time(NULL));
srand((unsigned int)time(NULL));
}
Scene::~Scene()
+4
View File
@@ -1,7 +1,11 @@
#include "Graphics/RenderCore.h"
#include "Window/SceneView.h"
#include "Asset/AssetRegistry.h"
#include "Fibers/Fibers.h"
#include <queue>
using namespace Seele;
int main()
{
RenderCore core;
+1
View File
@@ -5,5 +5,6 @@ target_sources(Seele_unit_tests
EngineTest.cpp)
target_include_directories(Seele_unit_tests PUBLIC ./)
add_subdirectory(Containers/)
add_subdirectory(Fibers/)
add_subdirectory(Graphics/)
add_subdirectory(Math/)
+1 -1
View File
@@ -31,7 +31,7 @@ BOOST_AUTO_TEST_CASE(for_each)
map[6] = 4;
map[4] = 7;
int count = 0;
for(auto it = map.begin(); it != map.end(); ++it)
for(auto it : map)
{
count++;
}
+1 -1
View File
@@ -3,7 +3,7 @@
#include <boost/test/unit_test.hpp>
using namespace Seele;
BOOST_TEST_GLOBAL_FIXTURE(GlobalFixture);
BOOST_AUTO_TEST_SUITE(RefPtr)
struct TestStruct
+23 -1
View File
@@ -1 +1,23 @@
#pragma once
#pragma once
#include "Fibers/JobQueue.h"
namespace Seele
{
struct GlobalFixture
{
GlobalFixture()
{
}
~GlobalFixture()
{
}
void setup()
{
Fibers::JobQueue::initJobQueues();
}
void teardown()
{
Fibers::JobQueue::cleanupJobQueues();
}
};
};
+5
View File
@@ -0,0 +1,5 @@
target_sources(Seele_unit_tests
PRIVATE
../../../src/Engine/Fibers/JobQueue.cpp
../../../src/Engine/Fibers/Fibers.cpp
Fibers.cpp)
+61
View File
@@ -0,0 +1,61 @@
#include "EngineTest.h"
#include "MinimalEngine.h"
#include "Fibers/Fibers.h"
#include <coroutine>
#include <boost/test/unit_test.hpp>
using namespace Seele;
using namespace Seele::Fibers;
BOOST_AUTO_TEST_SUITE(Fibers_Suite)
FiberTask basicFiberSync1(PCounter syncCounter)
{
syncCounter->increment();
std::cout << "basicFiberSync1 start" << std::endl;
co_await AwaitCounter{syncCounter, 2};
std::cout << "basicFiberSync1 has resumed, counter is " << syncCounter << std::endl;
co_return;
}
FiberTask basicFiberSync2(PCounter syncCounter)
{
syncCounter->increment();
std::cout << "basicFiberSync2 start" << std::endl;
co_await AwaitCounter(syncCounter, 3);
std::cout << "basicFiberSync2 has resumed, counter is " << syncCounter << std::endl;
co_return;
}
BOOST_AUTO_TEST_CASE(basicFiberSync)
{
PCounter syncCounter = new Counter(1);
PCounter counter1 = new Counter();
FiberJob job1 = FiberJob(counter1, &basicFiberSync1, syncCounter);
JobQueue::runJobs(&job1, 1);
FiberJob job2 = FiberJob(counter1, &basicFiberSync2, syncCounter);
JobQueue::runJobs(&job2, 1);
while(counter1->lessThan(2))
std::this_thread::yield();
BOOST_CHECK_EQUAL(syncCounter->getValue(), 3);
}
FiberTask incrementJob(PCounter localCounter)
{
localCounter->increment();
co_return;
}
BOOST_AUTO_TEST_CASE(jobBatch)
{
PCounter localCounter = new Counter();
PCounter jobCounter = new Counter();
FiberJob jobs[256];
for(int i = 0; i < 256; ++i)
{
jobs[i] = FiberJob(jobCounter, JobPriority::HIGH, &incrementJob, localCounter);
}
JobQueue::runJobs(jobs, 256);
while(jobCounter->lessThan(256))
std::this_thread::yield();
BOOST_CHECK_EQUAL(localCounter->getValue(), 256);
}
BOOST_AUTO_TEST_SUITE_END()