16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-22 15:09:19 +02:00

New Components/ Prepare to new scene loading system

This commit is contained in:
2026-06-16 21:33:29 +02:00
parent 2c599cb419
commit cb739365b4
15 changed files with 712 additions and 57 deletions

View File

@@ -0,0 +1,86 @@
#include "stdafx.h"
#include "AsyncFilePreloader.h"
#include <fstream>
#include <algorithm>
#include <thread>
AsyncFilePreloader GModelPreloader;
void AsyncFilePreloader::start(int thread_count) {
if (m_running.load()) return;
int n = thread_count > 0 ? thread_count
: (int)std::thread::hardware_concurrency();
n = std::clamp(n, 1, 8);
m_running = true;
m_workers.reserve(n);
for (int i = 0; i < n; ++i)
m_workers.emplace_back([this] { worker(); });
}
void AsyncFilePreloader::stop() {
{
std::lock_guard<std::mutex> lk(m_mutex);
m_running = false;
// drain the queue so workers don't pick up more work
while (!m_pending.empty()) m_pending.pop();
}
m_cv.notify_all();
for (auto& t : m_workers)
if (t.joinable()) t.join();
m_workers.clear();
}
void AsyncFilePreloader::queue(std::string path) {
std::lock_guard<std::mutex> lk(m_mutex);
if (!m_running) return;
if (!m_queued.insert(path).second) return; // already queued / cached
m_pending.push(std::move(path));
m_cv.notify_one();
}
AsyncFilePreloader::Buffer AsyncFilePreloader::get(const std::string& path) const {
std::lock_guard<std::mutex> lk(m_mutex);
auto it = m_cache.find(path);
return (it != m_cache.end()) ? it->second : nullptr;
}
void AsyncFilePreloader::clear() {
std::lock_guard<std::mutex> lk(m_mutex);
m_cache.clear();
m_queued.clear();
}
void AsyncFilePreloader::worker() {
while (true) {
std::string path;
{
std::unique_lock<std::mutex> lk(m_mutex);
m_cv.wait(lk, [this] {
return !m_pending.empty() || !m_running.load(std::memory_order_relaxed);
});
if (!m_running && m_pending.empty()) return;
if (m_pending.empty()) continue;
path = std::move(m_pending.front());
m_pending.pop();
}
auto buf = std::make_shared<std::vector<char>>();
{
std::ifstream f(path, std::ios::binary | std::ios::ate);
if (f) {
auto sz = static_cast<std::streamsize>(f.tellg());
f.seekg(0);
buf->resize(static_cast<size_t>(sz));
f.read(buf->data(), sz);
if (!f) buf->clear(); // read error — fall back to sync load
}
}
{
std::lock_guard<std::mutex> lk(m_mutex);
m_cache[path] = std::move(buf);
}
}
}

View File

@@ -0,0 +1,57 @@
#pragma once
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <queue>
#include <atomic>
// Thread pool that reads files from disk into memory so the main thread can
// skip disk I/O and parse directly from RAM. Only covers the binary path
// (E3D); text models fall back to synchronous load.
class AsyncFilePreloader {
public:
using Buffer = std::shared_ptr<std::vector<char>>;
AsyncFilePreloader() = default;
~AsyncFilePreloader() { stop(); }
AsyncFilePreloader(const AsyncFilePreloader&) = delete;
AsyncFilePreloader& operator=(const AsyncFilePreloader&) = delete;
// Start N worker threads (clamped to [1, hardware_concurrency]).
void start(int thread_count = 0);
// Signal workers to stop and join them. Clears the queue but keeps
// already-loaded buffers so late callers still get cache hits.
void stop();
// Queue a file for background loading. Silently skips duplicates.
void queue(std::string path);
// Return the preloaded buffer for `path`, or nullptr if not ready yet.
// Does NOT block — callers must fall back to synchronous I/O if nullptr.
Buffer get(const std::string& path) const;
// Drop all cached buffers (call after loading finishes to free memory).
void clear();
bool is_running() const { return m_running.load(std::memory_order_relaxed); }
private:
void worker();
mutable std::mutex m_mutex;
std::condition_variable m_cv;
std::queue<std::string> m_pending;
std::unordered_set<std::string> m_queued; // prevents duplicate queuing
std::unordered_map<std::string, Buffer> m_cache;
std::vector<std::thread> m_workers;
std::atomic<bool> m_running { false };
};
extern AsyncFilePreloader GModelPreloader;