feat: make image loading async
This commit is contained in:
@@ -4,7 +4,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
@@ -12,6 +14,7 @@
|
||||
#include <destrum/Graphics/GPUImage.h>
|
||||
#include <destrum/Graphics/ids.h>
|
||||
#include <destrum/Graphics/TextureIntent.h>
|
||||
#include <destrum/Graphics/imageLoader.h>
|
||||
|
||||
class GfxDevice;
|
||||
|
||||
@@ -33,6 +36,14 @@ public:
|
||||
VkImageUsageFlags usage,
|
||||
bool mipMap, TextureIntent intent = TextureIntent::ColorSrgb);
|
||||
|
||||
// Reserves the ID now and decodes on a job worker, the slot is filled in by finishPendingLoads
|
||||
ImageID requestImage(
|
||||
const std::filesystem::path& path,
|
||||
VkImageUsageFlags usage,
|
||||
bool mipMap, TextureIntent intent = TextureIntent::ColorSrgb);
|
||||
void finishPendingLoads();
|
||||
[[nodiscard]] std::size_t getPendingLoadCount() const { return pendingImages.size(); }
|
||||
|
||||
ImageID addImage(GPUImage image);
|
||||
ImageID addImage(ImageID id, GPUImage image);
|
||||
[[nodiscard]] const GPUImage& getImage(ImageID id) const;
|
||||
@@ -61,7 +72,22 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
struct PendingImage {
|
||||
ImageID id{NULL_IMAGE_ID};
|
||||
std::future<ImageData> data;
|
||||
};
|
||||
|
||||
[[nodiscard]] std::optional<ImageID> findLoadedImage(
|
||||
const std::filesystem::path& path,
|
||||
VkImageUsageFlags usage,
|
||||
bool mipMap,
|
||||
TextureIntent intent) const;
|
||||
ImageID reserveImageId();
|
||||
void finishPendingLoad(ImageID id);
|
||||
void completePendingLoad(PendingImage pending);
|
||||
|
||||
std::vector<GPUImage> images;
|
||||
std::vector<PendingImage> pendingImages;
|
||||
std::shared_ptr<std::vector<ImageID>> freeIds = std::make_shared<std::vector<ImageID>>();
|
||||
GfxDevice& gfxDevice;
|
||||
|
||||
|
||||
@@ -141,6 +141,15 @@ public:
|
||||
return imageManager.loadImageFromFile(path, usage, mipMap, intent);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<GPUImage> createImageFromData(
|
||||
const ImageData& data,
|
||||
VkImageUsageFlags usage,
|
||||
bool mipMap,
|
||||
const std::string& debugName) const
|
||||
{
|
||||
return imageManager.createImageFromData(data, usage, mipMap, debugName);
|
||||
}
|
||||
|
||||
void uploadImageDataSized(
|
||||
const GPUImage& image,
|
||||
const void* pixelData,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
class VulkanImmediateExecutor;
|
||||
class MemoryManager;
|
||||
struct ImageData;
|
||||
|
||||
class ImageManager {
|
||||
public:
|
||||
@@ -41,6 +42,12 @@ public:
|
||||
bool mipMap,
|
||||
TextureIntent intent) const;
|
||||
|
||||
[[nodiscard]] std::optional<GPUImage> createImageFromData(
|
||||
const ImageData& data,
|
||||
VkImageUsageFlags usage,
|
||||
bool mipMap,
|
||||
const std::string& debugName) const;
|
||||
|
||||
void uploadImageData(
|
||||
const GPUImage& image,
|
||||
const void* pixelData,
|
||||
|
||||
@@ -48,6 +48,10 @@ public:
|
||||
|
||||
ImageID loadMaterialTexture(GfxDevice& gfxDevice, const std::filesystem::path& path, TextureIntent intent);
|
||||
|
||||
// While a scope is open material textures decode on job workers, closing the last one uploads them
|
||||
void beginDeferredTextureLoads();
|
||||
void endDeferredTextureLoads();
|
||||
|
||||
struct ReleaseStats {
|
||||
std::size_t meshes{0};
|
||||
std::size_t materials{0};
|
||||
@@ -105,6 +109,20 @@ private:
|
||||
ImageID whiteImageId{NULL_IMAGE_ID};
|
||||
ImageID errorImageId{NULL_IMAGE_ID};
|
||||
ImageID defaultNormalImageId{NULL_IMAGE_ID};
|
||||
|
||||
int deferredTextureLoads{0};
|
||||
};
|
||||
|
||||
class DeferredTextureLoadScope {
|
||||
public:
|
||||
explicit DeferredTextureLoadScope(RenderResources* resources);
|
||||
~DeferredTextureLoadScope();
|
||||
|
||||
DeferredTextureLoadScope(const DeferredTextureLoadScope&) = delete;
|
||||
DeferredTextureLoadScope& operator=(const DeferredTextureLoadScope&) = delete;
|
||||
|
||||
private:
|
||||
RenderResources* resources;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -58,12 +58,12 @@ public:
|
||||
void Wait(JobCounter& counter);
|
||||
|
||||
template <typename F>
|
||||
auto Async(F&& fn) -> std::future<std::invoke_result_t<std::decay_t<F>>>
|
||||
auto Async(F&& fn, JobPriority priority = JobPriority::Low) -> std::future<std::invoke_result_t<std::decay_t<F>>>
|
||||
{
|
||||
using Result = std::invoke_result_t<std::decay_t<F>>;
|
||||
auto task = std::make_shared<std::packaged_task<Result()>>(std::forward<F>(fn));
|
||||
auto future = task->get_future();
|
||||
Submit([task] { (*task)(); }, JobPriority::Low);
|
||||
Submit([task] { (*task)(); }, priority);
|
||||
return future;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user