coroutines truly are cursed

This commit is contained in:
2021-11-11 20:12:50 +01:00
parent 1848bb5139
commit 01049019fd
25 changed files with 202 additions and 92 deletions
+1 -1
View File
@@ -104,7 +104,7 @@ void AssetRegistry::importTexture(const std::filesystem::path &filePath)
void AssetRegistry::importMaterial(const std::filesystem::path &filePath)
{
materialLoader->queueAsset(filePath);
materialLoader->importAsset(filePath);
}
void AssetRegistry::registerMesh(PMeshAsset mesh)
+15 -8
View File
@@ -17,15 +17,22 @@ MaterialLoader::~MaterialLoader()
{
}
PMaterialAsset MaterialLoader::queueAsset(const std::filesystem::path& filePath)
void MaterialLoader::importAsset(const std::filesystem::path& name)
{
PMaterialAsset result = new MaterialAsset(filePath);
result->load();
graphics->getShaderCompiler()->registerMaterial(result);
AssetRegistry::get().registerMaterial(result);
// TODO: There is actually no real reason to import a standalone material,
// maybe in the future there could be a substance loader or something
return result;
std::filesystem::path assetPath = name.filename();
assetPath.replace_extension("asset");
PMaterialAsset asset = new MaterialAsset(assetPath.generic_string());
asset->setStatus(Asset::Status::Loading);
AssetRegistry::get().registerMaterial(asset);
import(name, asset);
}
Job MaterialLoader::import(std::filesystem::path, PMaterialAsset asset)
{
asset->load();
graphics->getShaderCompiler()->registerMaterial(asset);
AssetRegistry::get().registerMaterial(asset);
co_return;
}
PMaterialAsset MaterialLoader::getPlaceHolderMaterial()
+3 -1
View File
@@ -1,6 +1,7 @@
#pragma once
#include "MinimalEngine.h"
#include "Containers/List.h"
#include "ThreadPool.h"
#include <thread>
#include <future>
#include <filesystem>
@@ -14,9 +15,10 @@ class MaterialLoader
public:
MaterialLoader(Gfx::PGraphics graphic);
~MaterialLoader();
PMaterialAsset queueAsset(const std::filesystem::path& filePath);
void importAsset(const std::filesystem::path& name);
PMaterialAsset getPlaceHolderMaterial();
private:
Job import(std::filesystem::path filePath, PMaterialAsset asset);
Gfx::PGraphics graphics;
List<std::future<void>> futures;
PMaterialAsset placeholderMaterial;
+6 -4
View File
@@ -30,9 +30,10 @@ void MeshLoader::importAsset(const std::filesystem::path &path)
{
std::filesystem::path assetPath = path.filename();
assetPath.replace_extension("asset");
PMeshAsset meshAsset = new MeshAsset(assetPath.generic_string());
AssetRegistry::get().registerMesh(meshAsset);
futures.add(std::async(std::launch::async, &MeshLoader::import, this, meshAsset, path));
PMeshAsset asset = new MeshAsset(assetPath.generic_string());
asset->setStatus(Asset::Status::Loading);
AssetRegistry::get().registerMesh(asset);
import(path, asset);
}
void MeshLoader::loadMaterials(const aiScene* scene, Array<PMaterialAsset>& globalMaterials, Gfx::PGraphics graphics)
@@ -228,7 +229,7 @@ void MeshLoader::loadTextures(const aiScene* scene, const std::filesystem::path&
AssetRegistry::importFile(texPngPath.string());
}
}
void MeshLoader::import(PMeshAsset meshAsset, const std::filesystem::path &path)
Job MeshLoader::import(std::filesystem::path path, PMeshAsset meshAsset)
{
std::cout << "Starting to import "<<path << std::endl;
meshAsset->setStatus(Asset::Status::Loading);
@@ -263,4 +264,5 @@ void MeshLoader::import(PMeshAsset meshAsset, const std::filesystem::path &path)
meshAsset->setStatus(Asset::Status::Ready);
meshAsset->save();
std::cout << "Finished loading " << path << std::endl;
co_return;
}
+2 -1
View File
@@ -1,6 +1,7 @@
#pragma once
#include "MinimalEngine.h"
#include "Containers/List.h"
#include "ThreadPool.h"
#include <thread>
#include <future>
#include <filesystem>
@@ -25,7 +26,7 @@ private:
void loadGlobalMeshes(const aiScene* scene, Array<PMesh>& globalMeshes, const Array<PMaterialAsset>& materials, Gfx::PGraphics graphics);
void convertAssimpARGB(unsigned char* dst, aiTexel* src, uint32 numPixels);
void import(PMeshAsset meshAsset, const std::filesystem::path& path);
Job import(std::filesystem::path path, PMeshAsset meshAsset);
List<std::future<void>> futures;
Gfx::PGraphics graphics;
};
+10 -11
View File
@@ -22,20 +22,15 @@ TextureLoader::~TextureLoader()
{
}
void TextureLoader::importAsset(const std::filesystem::path& filePath)
void TextureLoader::importAsset(const std::filesystem::path& path)
{
auto assetFileName = filePath;
PTextureAsset asset = new TextureAsset(assetFileName.replace_extension("asset").filename().generic_string());
std::filesystem::path assetPath = path.filename();
assetPath.replace_extension("asset");
PTextureAsset asset = new TextureAsset(assetPath.generic_string());
asset->setStatus(Asset::Status::Loading);
asset->setTexture(placeholderAsset->getTexture());
AssetRegistry::get().registerTexture(asset);
futures.add(std::async(std::launch::async, [this, filePath, asset] () mutable {
using namespace std::chrono_literals;
//std::this_thread::sleep_for(5s);
import(filePath, asset);
asset->load();
asset->setStatus(Asset::Status::Ready);
}));
import(path, asset);
}
PTextureAsset TextureLoader::getPlaceholderTexture()
@@ -43,7 +38,7 @@ PTextureAsset TextureLoader::getPlaceholderTexture()
return placeholderAsset;
}
void TextureLoader::import(const std::filesystem::path& path, PTextureAsset textureAsset)
Job TextureLoader::import(std::filesystem::path path, PTextureAsset textureAsset)
{
int x, y, n;
unsigned char* data = stbi_load(path.string().c_str(), &x, &y, &n, 4);
@@ -72,4 +67,8 @@ void TextureLoader::import(const std::filesystem::path& path, PTextureAsset text
ktxTexture_WriteToNamedFile(ktxTexture(kTexture), textureAsset->getFullPath().c_str());
ktxTexture_Destroy(ktxTexture(kTexture));
textureAsset->load();
textureAsset->setStatus(Asset::Status::Ready);
co_return;
}
+2 -1
View File
@@ -1,6 +1,7 @@
#pragma once
#include "MinimalEngine.h"
#include "Containers/List.h"
#include "ThreadPool.h"
#include <thread>
#include <future>
#include <filesystem>
@@ -18,7 +19,7 @@ public:
void importAsset(const std::filesystem::path& filePath);
PTextureAsset getPlaceholderTexture();
private:
void import(const std::filesystem::path& path, PTextureAsset asset);
Job import(std::filesystem::path path, PTextureAsset asset);
Gfx::PGraphics graphics;
List<std::future<void>> futures;
PTextureAsset placeholderAsset;
+14
View File
@@ -246,6 +246,20 @@ public:
_size++;
return insertedElement;
}
// takes all elements from other and move-inserts them into
// this, clearing other in the process
void moveElements(List& other){
tail->prev->next = other.root;
other.root->prev = tail->prev;
_size += other._size;
deallocateNode(tail);
tail = other.tail;
other._size = 0;
other.root = nullptr;
other.tail = nullptr;
markIteratorDirty();
other.markIteratorDirty();
}
template<typename... args>
constexpr reference emplace(args... arguments)
{
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include <utility>
#include "List.h"
#include "Array.h"
namespace Seele
{
+1 -1
View File
@@ -51,7 +51,7 @@ ShaderBuffer::ShaderBuffer(PGraphics graphics, uint32 size, VkBufferUsageFlags u
memRequirements.pNext = &dedicatedRequirements;
for (uint32 i = 0; i < numBuffers; ++i)
{
vkCreateBuffer(graphics->getDevice(), &info, nullptr, &buffers[i].buffer);
VK_CHECK(vkCreateBuffer(graphics->getDevice(), &info, nullptr, &buffers[i].buffer));
bufferReqInfo.buffer = buffers[i].buffer;
vkGetBufferMemoryRequirements2(graphics->getDevice(), &bufferReqInfo, &memRequirements);
auto temp = graphics->getAllocator()->allocate(memRequirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, buffers[i].buffer);
+9 -18
View File
@@ -2,7 +2,6 @@
#include "Containers/Map.h"
#include "EngineTypes.h"
#include "Math/Math.h"
//#include "ThreadPool.h"
#define DEFINE_REF(x) \
typedef RefPtr<x> P##x; \
@@ -80,23 +79,19 @@ public:
}
return *this;
}
inline bool operator==(const RefObject &other) const
bool operator==(const RefObject &rhs) const
{
return handle == other.handle;
return handle == rhs.handle;
}
inline bool operator!=(const RefObject &other) const
auto operator<=>(const RefObject& rhs) const
{
return handle != other.handle;
}
inline bool operator<(const RefObject &other) const
{
return handle < other.handle;
return handle <=> rhs.handle;
}
void addRef()
{
refCount++;
}
inline void removeRef()
void removeRef()
{
refCount--;
if (refCount == 0)
@@ -235,17 +230,13 @@ public:
object->removeRef();
}
}
inline bool operator==(const RefPtr &other) const
bool operator==(const RefPtr& rhs) const
{
return object == other.object;
return object == rhs.object;
}
inline bool operator!=(const RefPtr &other) const
auto operator<=>(const RefPtr &rhs) const
{
return object != other.object;
}
bool operator<(const RefPtr &other) const
{
return object < other.object;
return object <=> rhs.object;
}
inline T *operator->()
{
-2
View File
@@ -14,12 +14,10 @@ Actor::~Actor()
}
void Actor::tick(float deltaTime)
{
addWorldRotation(glm::vec3(0, 1 * deltaTime, 0));
}
void Actor::notifySceneAttach(PScene scene)
{
owningScene = scene;
scene->getSceneUpdater()->registerActorUpdate(this);
rootComponent->notifySceneAttach(scene);
for(auto child : children)
{
+1 -3
View File
@@ -1,9 +1,7 @@
target_sources(SeeleEngine
PRIVATE
Scene.cpp
Scene.h
SceneUpdater.h
SceneUpdater.cpp)
Scene.h)
add_subdirectory(Actor/)
add_subdirectory(Components/)
@@ -36,7 +36,6 @@ PActor Component::getOwner()
void Component::notifySceneAttach(PScene scene)
{
owningScene = scene;
scene->getSceneUpdater()->registerComponentUpdate(this);
for (auto child : children)
{
child->notifySceneAttach(scene);
-2
View File
@@ -13,7 +13,6 @@ inline float frand()
Scene::Scene(Gfx::PGraphics graphics)
: graphics(graphics)
, updater(new SceneUpdater())
{
lightEnv.directionalLights[0].color = Vector4(1, 1, 1, 1);
lightEnv.directionalLights[0].direction = Vector4(1, 1, 0, 1);
@@ -36,7 +35,6 @@ Scene::~Scene()
void Scene::tick(double deltaTime)
{
updater->runUpdates(static_cast<float>(deltaTime));
for(auto &&meshBatch : staticMeshes)
{
meshBatch.material->updateDescriptorData();
-3
View File
@@ -4,7 +4,6 @@
#include "Graphics/GraphicsResources.h"
#include "Components/PrimitiveComponent.h"
#include "Graphics/MeshBatch.h"
#include "SceneUpdater.h"
namespace Seele
{
@@ -46,13 +45,11 @@ public:
const Array<PPrimitiveComponent>& getPrimitives() const { return primitives; }
const Array<StaticMeshBatch>& getStaticMeshes() const { return staticMeshes; }
const LightEnv& getLightBuffer() const { return lightEnv; }
UPSceneUpdater& getSceneUpdater() { return updater; }
private:
Array<StaticMeshBatch> staticMeshes;
Array<PActor> rootActors;
Array<PPrimitiveComponent> primitives;
LightEnv lightEnv;
Gfx::PGraphics graphics;
UPSceneUpdater updater;
};
} // namespace Seele
+1 -1
View File
@@ -2,7 +2,7 @@
#include "MinimalEngine.h"
#include "Containers/List.h"
#include <semaphore>
//DEPRECATED
namespace Seele
{
DECLARE_REF(Component);
+34 -10
View File
@@ -46,42 +46,53 @@ ThreadPool::~ThreadPool()
void ThreadPool::addJob(Job&& job)
{
std::unique_lock lock(jobQueueLock);
jobQueue.add(job);
//std::cout << "Adding job " << job << std::endl;
jobQueue.add(std::move(job));
jobQueueCV.notify_one();
}
void ThreadPool::addJob(MainJob&& job)
{
std::unique_lock lock(mainJobLock);
mainJobs.add(job);
//std::cout << "Adding main job " << job << std::endl;
mainJobs.add(std::move(job));
mainJobCV.notify_one();
}
void ThreadPool::enqueueWaiting(Event* event, Job&& job)
{
//std::cout << job << " waiting for event " << event->name << std::endl;
std::unique_lock lock(waitingLock);
waitingJobs[event].add(std::move(job));
waitingJobs[*event].add(std::move(job));
}
void ThreadPool::enqueueWaiting(Event* event, MainJob&& job)
{
//std::cout << job << " main waiting for event " << event->name << std::endl;
std::unique_lock lock(waitingMainLock);
waitingMainJobs[event].add(std::move(job));
waitingMainJobs[*event].add(std::move(job));
}
void ThreadPool::notify(Event* event)
{
{
std::unique_lock lock(jobQueueLock);
std::unique_lock lock2(waitingLock);
for(auto&& job : waitingJobs[event])
for(Job& job : waitingJobs[*event])
{
jobQueue.add(job);
//std::cout << "Waking up job " << job << std::endl;
jobQueue.add(std::move(job));
jobQueueCV.notify_one();
}
waitingJobs[event].clear();
waitingJobs[*event].clear();
}
{
std::unique_lock lock(mainJobLock);
std::unique_lock lock2(waitingMainLock);
for(auto&& job : waitingMainJobs[event])
auto&& jobsToQueue = std::move(waitingMainJobs[*event]);
waitingMainJobs.erase(*event);
for(MainJob& job : jobsToQueue)
{
mainJobs.add(job);
//std::cout << "Waking up main job " << job << std::endl;
mainJobs.add(std::move(job));
mainJobCV.notify_one();
}
waitingMainJobs[event].clear();
}
event->reset();
}
@@ -95,9 +106,22 @@ void ThreadPool::threadLoop(const bool mainThread)
if(!mainJobs.empty())
{
MainJob&& job = mainJobs.retrieve();
lock.unlock();
job.resume();
}
}
std::unique_lock lock(jobQueueLock);
if(jobQueue.empty())
{
jobQueueCV.wait(lock);
}
if(!jobQueue.empty())
{
Job&& job = jobQueue.retrieve();
lock.unlock();
//std::cout << "Starting job " << job << std::endl;
job.resume();
}
}
}
+51 -6
View File
@@ -30,16 +30,49 @@ struct JobBase
public:
using promise_type = JobPromiseBase<MainJob>;
explicit JobBase()
{}
explicit JobBase(std::coroutine_handle<promise_type> handle)
: handle(handle)
{}
{
std::cout << "Creating job " << handle.address() << std::endl;
}
JobBase(const JobBase & rhs) = delete;
JobBase(JobBase&& rhs)
: handle(std::move(rhs.handle))
{
rhs.handle = nullptr;
}
~JobBase()
{
if(handle)
{
std::cout << "Destroying job " << handle.address() << std::endl;
handle.destroy();
}
}
JobBase& operator=(const JobBase& rhs) = delete;
JobBase& operator=(JobBase&& rhs)
{
if(this != &rhs)
{
handle = std::move(rhs.handle);
rhs.handle = nullptr;
}
return *this;
}
friend std::basic_ostream<char>& operator<<(std::basic_ostream<char>& stream, const JobBase& obj)
{
if (obj.handle == nullptr)
{
stream << nullptr;
}
else
{
stream << obj.handle.address();
}
return stream;
}
void resume()
{
handle.resume();
@@ -56,6 +89,15 @@ struct Event
public:
Event();
Event(const std::string& name);
auto operator<=>(const Event& other) const
{
return name <=> other.name;
}
Event operator co_await()
{
return *this;
}
void raise();
void reset();
bool await_ready();
@@ -65,6 +107,7 @@ public:
private:
std::string name;
RefPtr<std::atomic_bool> flag;
friend class ThreadPool;
};
class ThreadPool
@@ -84,14 +127,16 @@ private:
List<MainJob> mainJobs;
std::mutex mainJobLock;
std::condition_variable mainJobCV;
List<Job> jobQueue;
std::mutex jobQueueLock;
std::condition_variable jobQueueCV;
Map<Event*, List<Job>> waitingJobs;
Map<Event, List<Job>> waitingJobs;
std::mutex waitingLock;
Map<Event*, List<MainJob>> waitingMainJobs;
Map<Event, List<MainJob>> waitingMainJobs;
std::mutex waitingMainLock;
void threadLoop(const bool isMainThread);
@@ -100,7 +145,7 @@ private:
template<bool MainJob>
inline JobBase<MainJob> JobPromiseBase<MainJob>::get_return_object() noexcept {
return JobBase<MainJob> { std::coroutine_handle<JobPromiseBase<MainJob>>::from_promise(*this) };
return JobBase<MainJob>();
}
template<bool MainJob>
@@ -111,7 +156,7 @@ inline auto JobPromiseBase<MainJob>::initial_suspend() const noexcept
constexpr bool await_ready() { return false; }
constexpr void await_suspend(std::coroutine_handle<JobPromiseBase<MainJob>> h)
{
getGlobalThreadPool().addJob(JobBase<MainJob>(h));
getGlobalThreadPool().addJob(std::move(JobBase<MainJob>(h)));
}
constexpr void await_resume() {}
};
@@ -121,7 +166,7 @@ inline auto JobPromiseBase<MainJob>::initial_suspend() const noexcept
template<bool MainJob>
inline constexpr void Event::await_suspend(std::coroutine_handle<JobPromiseBase<MainJob>> h)
{
getGlobalThreadPool().enqueueWaiting(this, JobBase<MainJob>(h));
getGlobalThreadPool().enqueueWaiting(this, std::move(JobBase<MainJob>(h)));
}
} // namespace Seele
+16 -11
View File
@@ -18,8 +18,10 @@ void Window::addView(PView view)
{
WindowView* windowView = new WindowView();
windowView->view = view;
windowView->updateFinished = Event("test");
//windowView->worker = std::thread(&Window::viewWorker, this, windowView);
views.add(windowView);
viewWorker(views.size() - 1);
}
MainJob Window::render()
@@ -27,8 +29,8 @@ MainJob Window::render()
gfxHandle->beginFrame();
for(auto& windowView : views)
{
viewWorker(windowView);
co_await windowView->updateFinished;
std::cout << "view update finished" << std::endl;
{
std::unique_lock lock(windowView->workerMutex);
windowView->view->prepareRender();
@@ -36,6 +38,8 @@ MainJob Window::render()
windowView->view->render();
}
gfxHandle->endFrame();
//Enqueue a new render main job
render();
}
Gfx::PWindow Window::getGfxHandle()
@@ -60,17 +64,18 @@ void Window::setFocused(PView view)
});
}
Job Window::viewWorker(WindowView* windowView)
Job Window::viewWorker(size_t viewIndex)
{
while(true)
WindowView* windowView = views[viewIndex];
windowView->view->beginUpdate();
windowView->view->update();
{
windowView->view->beginUpdate();
windowView->view->update();
{
std::unique_lock lock(windowView->workerMutex);
windowView->view->commitUpdate();
}
windowView->updateFinished.raise();
std::unique_lock lock(windowView->workerMutex);
windowView->view->commitUpdate();
}
std::cout << "Update completed" << std::endl;
windowView->updateFinished.raise();
// enqueue next frame update
viewWorker(viewIndex);
co_return;
}
+1 -1
View File
@@ -29,7 +29,7 @@ protected:
Array<WindowView*> views;
Gfx::PWindow gfxHandle;
Job viewWorker(WindowView* view);
Job viewWorker(size_t viewIndex);
};
DEFINE_REF(Window)
} // namespace Seele
+5
View File
@@ -39,4 +39,9 @@ PWindow WindowManager::addWindow(const WindowCreateInfo &createInfo)
void WindowManager::notifyWindowClosed(PWindow window)
{
windows.remove(windows.find(window));
if(windows.empty())
{
std::unique_lock lock(windowsLock);
windowsCV.notify_all();
}
}
+8
View File
@@ -11,6 +11,7 @@ class WindowManager
public:
WindowManager();
~WindowManager();
Job init();
PWindow addWindow(const WindowCreateInfo &createInfo);
void notifyWindowClosed(PWindow window);
static Gfx::PGraphics getGraphics()
@@ -21,9 +22,16 @@ public:
{
return windows.size();
}
void waitForCompletion()
{
std::unique_lock lock(windowsLock);
windowsCV.wait(lock);
}
private:
Array<PWindow> windows;
std::mutex windowsLock;
std::condition_variable windowsCV;
static Gfx::PGraphics graphics;
};
DEFINE_REF(WindowManager)
+2 -4
View File
@@ -34,9 +34,7 @@ int main()
PInspectorView inspectorView = new InspectorView(windowManager->getGraphics(), window, inspectorViewInfo);
window->addView(inspectorView);
sceneView->setFocused();
while(windowManager->isActive())
{
window->render();
}
window->render();
windowManager->waitForCompletion();
return 0;
}
+18
View File
@@ -40,4 +40,22 @@ BOOST_AUTO_TEST_CASE(basic_remove)
BOOST_REQUIRE_EQUAL(list.size(), 2);
}
BOOST_AUTO_TEST_CASE(list_join)
{
List<int> list1;
List<int> list2;
list1.add(2);
list1.add(1);
list1.add(3);
list1.add(4);
list2.add(5);
list2.add(7);
list2.add(8);
list2.add(6);
list2.add(9);
list1.moveElements(list2);
BOOST_REQUIRE_EQUAL(list1.size(), 9);
BOOST_REQUIRE_EQUAL(list2.size(), 0);
}
BOOST_AUTO_TEST_SUITE_END()