Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 32 additions & 12 deletions ZEngine/ZEngine/Helpers/ThreadPool.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,16 @@ namespace ZEngine::Helpers
/// The callback runs before any queued tasks on each worker thread.
/// @param fn Callback — fn(ctx, worker_idx). Must be thread-safe.
/// @param ctx Caller context forwarded to fn.
void InitClosureSlab(Core::Memory::ArenaAllocator* arena, size_t bytes)
{
m_closure_slab.Init(arena, bytes);
}

Core::Memory::TLSFSlab* GetClosureSlab()
{
return m_closure_slab.Pool ? &m_closure_slab : nullptr;
}

void RegisterWorkerInit(WorkerInitFn fn, void* ctx)
{
m_init_ctx.value.store(ctx, std::memory_order_relaxed);
Expand All @@ -124,13 +134,9 @@ namespace ZEngine::Helpers
m_cancellation.value.store(true, std::memory_order_release);
for (size_t i = 0; i < WorkerCount; ++i)
m_workers[i].cv.notify_one();
// Yield until all workers have exited — ensures Worker::mutex and
// Worker::cv are not destroyed while a thread is still using them.
// yield() lets the OS schedule worker threads so they can see the
// cancellation token and decrement the counter; a pure spin-wait
// would starve workers on a loaded CI runner.
while (m_active_workers.value.load(std::memory_order_acquire) > 0)
std::this_thread::yield();
m_closure_slab.Shutdown();
}

private:
Expand All @@ -141,6 +147,7 @@ namespace ZEngine::Helpers
std::condition_variable cv;
};

Core::Memory::TLSFSlab m_closure_slab{};
Worker m_workers[MAX_WORKERS];
PaddedAtomic<uint32_t> m_cursor{};
PaddedAtomic<bool> m_cancellation{};
Expand Down Expand Up @@ -200,17 +207,30 @@ namespace ZEngine::Helpers
Pool->Submit(ctx, fn);
}

// Lambda shim — one heap allocation per lambda call (for captures).
// Use the C-style overload directly to stay on the zero-alloc path.
template <typename T>
static void Submit(T&& f)
{
using Fn = std::decay_t<T>;
auto* p = new Fn(std::forward<T>(f));
Pool->Submit(p, [](void* ctx) {
auto* fn = static_cast<Fn*>(ctx);
using Fn = std::decay_t<T>;

static constexpr size_t fn_offset = (sizeof(Core::Memory::TLSFSlab*) + alignof(Fn) - 1) & ~(alignof(Fn) - 1);
static constexpr size_t block_size = fn_offset + sizeof(Fn);

Core::Memory::TLSFSlab* slab = Pool ? Pool->GetClosureSlab() : nullptr;
uint8_t* block = slab ? static_cast<uint8_t*>(slab->Alloc(block_size)) : static_cast<uint8_t*>(::operator new(block_size));

*reinterpret_cast<Core::Memory::TLSFSlab**>(block) = slab;
new (block + fn_offset) Fn(std::forward<T>(f));

Pool->Submit(block, [](void* ctx) {
uint8_t* raw = static_cast<uint8_t*>(ctx);
Core::Memory::TLSFSlab* slab = *reinterpret_cast<Core::Memory::TLSFSlab**>(raw);
auto* fn = reinterpret_cast<Fn*>(raw + fn_offset);
(*fn)();
delete fn;
fn->~Fn();
if (slab)
slab->Free(raw);
else
::operator delete(raw);
});
}

Expand Down
8 changes: 4 additions & 4 deletions ZEngine/ZEngine/Importers/AssetCodec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ namespace ZEngine::Importers::AssetCodec

out_cubemap = Rendering::Buffers::Bitmap(header.FaceWidth, header.FaceHeight, header.LayerCount, header.Channel, Rendering::Buffers::BitmapFormat::FLOAT);
out_cubemap.Type = Rendering::Buffers::BitmapType::CUBE;
in.read(reinterpret_cast<char*>(out_cubemap.Buffer.data()), static_cast<std::streamsize>(header.BufferByteSize));
in.read(reinterpret_cast<char*>(out_cubemap.Buffer), static_cast<std::streamsize>(header.BufferByteSize));
return in.good();
}

Expand Down Expand Up @@ -375,13 +375,13 @@ namespace ZEngine::Importers::AssetCodec
.FaceHeight = cubemap.Height,
.Channel = cubemap.Channel,
.LayerCount = cubemap.Depth,
.BufferByteSize = static_cast<uint64_t>(cubemap.Buffer.size()),
.BufferByteSize = static_cast<uint64_t>(cubemap.BufferSize),
};

const auto* hdr_bytes = reinterpret_cast<const uint8_t*>(&header);
auto w1 = file->Write({hdr_bytes, sizeof(header)}, 0);
const auto* data_bytes = reinterpret_cast<const uint8_t*>(cubemap.Buffer.data());
auto w2 = file->Write({data_bytes, cubemap.Buffer.size()}, sizeof(header));
const auto* data_bytes = reinterpret_cast<const uint8_t*>(cubemap.Buffer);
auto w2 = file->Write({data_bytes, cubemap.BufferSize}, sizeof(header));
auto flush = file->Flush();
file->Close();
ctx.Close(file);
Expand Down
8 changes: 5 additions & 3 deletions ZEngine/ZEngine/Importers/EnvironmentMapImporter.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <ZEngine/Helpers/MemoryOperations.h>
#include <ZEngine/Helpers/ThreadPool.h>
#include <ZEngine/Importers/AssetCodec.h>
#include <ZEngine/Importers/EnvironmentMapImporter.h>
#include <ZEngine/Logging/LoggerDefinition.h>
Expand Down Expand Up @@ -40,11 +41,12 @@ namespace ZEngine::Importers
return Core::VFS::VFSResult<void>::Fail(Core::VFS::VFSError::IOError);
}

Bitmap equirect = {width, height, 4, BitmapFormat::FLOAT, image_data};
Core::Memory::TLSFSlab* slab = Helpers::GetWorkerSlab();
Bitmap equirect(width, height, 4, BitmapFormat::FLOAT, image_data, slab);
stbi_image_free(const_cast<float*>(image_data));

Bitmap vertical_cross = Bitmap::EquirectangularMapToVerticalCross(equirect);
Bitmap cubemap = Bitmap::VerticalCrossToCubemap(vertical_cross);
Bitmap vertical_cross = Bitmap::EquirectangularMapToVerticalCross(equirect, slab);
Bitmap cubemap = Bitmap::VerticalCrossToCubemap(vertical_cross, slab);

// Write to project://_cache/envmaps/<uuid>.zenvmap via VFS.
// Keyed by UUID — regenerable, gitignored, transparent to game code.
Expand Down
Loading
Loading