asset_manager concept

This commit is contained in:
2026-09-09 11:36:07 -07:00
parent 9aef3f57fc
commit 4190ff847b
14 changed files with 525 additions and 12 deletions
+40 -1
View File
@@ -183,7 +183,16 @@ class Application::Impl {
commandBuffer.setViewport(0, viewport);
commandBuffer.setScissor(0, scissor);
modelRenderSystem.render(commandBuffer, this->meshes, frameInfo);
std::vector<ModelRenderSystem::MeshInstance> instances;
instances.reserve(this->meshes.size() + this->drawCalls.size());
for (const std::unique_ptr<Mesh>& mesh : this->meshes) {
instances.push_back({mesh.get(), glm::mat4{1.f}});
}
instances.insert(instances.end(), this->drawCalls.begin(),
this->drawCalls.end());
modelRenderSystem.render(commandBuffer, instances, frameInfo);
this->drawCalls.clear();
commandBuffer.endRendering();
@@ -224,6 +233,25 @@ class Application::Impl {
this->meshes.clear();
}
MeshHandle createMesh(std::vector<CanvasVertex> vertices,
std::vector<u32> indices) {
Mesh::Builder builder{};
builder.vertices.reserve(vertices.size());
for (const CanvasVertex& vertex : vertices) {
builder.vertices.push_back({vertex.position, vertex.color});
}
builder.indices = std::move(indices);
this->persistentMeshes.push_back(
std::make_unique<Mesh>(this->device, builder));
return static_cast<MeshHandle>(this->persistentMeshes.size() - 1);
}
void drawMesh(MeshHandle handle, const glm::mat4& transform) {
this->drawCalls.push_back(
{this->persistentMeshes[handle].get(), transform});
}
private:
Application& application;
const Application::Config config;
@@ -232,6 +260,8 @@ class Application::Impl {
RenderContext renderContext;
std::vector<std::unique_ptr<Mesh>> meshes;
std::vector<std::unique_ptr<Mesh>> persistentMeshes;
std::vector<ModelRenderSystem::MeshInstance> drawCalls;
};
void Application::setCommandLineArgs(int argc, const char* const* argv) {
@@ -254,4 +284,13 @@ void Application::pushMesh(std::vector<CanvasVertex> vertices,
void Application::clearMeshes() { impl->clearMeshes(); }
MeshHandle Application::createMesh(std::vector<CanvasVertex> vertices,
std::vector<u32> indices) {
return impl->createMesh(std::move(vertices), std::move(indices));
}
void Application::drawMesh(MeshHandle handle, const glm::mat4& transform) {
impl->drawMesh(handle, transform);
}
} // namespace sophia
+24
View File
@@ -0,0 +1,24 @@
#include "assets/asset_manager.hpp"
#include "mesh.hpp"
namespace sophia {
AssetManager::AssetManager(Device& device) : device{device}, meshPool{device} {}
template <>
MeshHandle AssetManager::create<Mesh>(const Mesh::Builder& builder) {
return meshPool.create(builder);
}
template <>
const Mesh& AssetManager::get<Mesh>(MeshHandle handle) const {
return meshPool.get(handle);
}
template <>
void AssetManager::release<Mesh>(MeshHandle handle) {
meshPool.release(handle);
}
} // namespace sophia
+41
View File
@@ -0,0 +1,41 @@
#pragma once
#include <string>
#include "device.hpp"
#include "pools/mesh_pool.hpp"
namespace sophia {
class AssetManager {
public:
explicit AssetManager(Device& device);
~AssetManager() = default;
AssetManager(const AssetManager&) = delete;
AssetManager& operator=(const AssetManager&) = delete;
template <typename T>
using HandleFor = typename T::HandleType;
template <typename T>
HandleFor<T> load(const std::string& path);
template <typename T>
HandleFor<T> create(const typename T::Builder& builder);
template <typename T>
const T& get(HandleFor<T> handle) const;
template <typename T>
void release(HandleFor<T> handle);
private:
Device& device;
MeshPool meshPool;
// TexturePool texturePool;
// MaterialPool materialPool;
};
} // namespace sophia
+41
View File
@@ -0,0 +1,41 @@
#include "assets/pools/mesh_pool.hpp"
#include <sophia/util/assert.hpp>
namespace sophia {
MeshPool::MeshPool(Device& device) : device{device} {}
MeshPool::~MeshPool() = default;
MeshHandle MeshPool::create(const Mesh::Builder& builder) {
auto mesh = std::make_unique<Mesh>(device, builder);
if (!freeList.empty()) {
MeshHandle handle = freeList.back();
freeList.pop_back();
meshes[handle] = std::move(mesh);
return handle;
}
meshes.push_back(std::move(mesh));
return static_cast<MeshHandle>(meshes.size() - 1);
}
const Mesh& MeshPool::get(MeshHandle handle) const {
SOPHIA_ASSERT(handle < meshes.size(), "invalid MeshHandle:", handle);
SOPHIA_ASSERT(meshes[handle] != nullptr,
"MeshHandle refers to a released mesh:", handle);
return *meshes[handle];
}
void MeshPool::release(MeshHandle handle) {
SOPHIA_ASSERT(handle < meshes.size(), "invalid MeshHandle:", handle);
SOPHIA_ASSERT(meshes[handle] != nullptr,
"MeshHandle already released:", handle);
meshes[handle].reset();
freeList.push_back(handle);
}
} // namespace sophia
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <memory>
#include <vector>
#include "device.hpp"
#include "mesh.hpp"
namespace sophia {
class MeshPool {
public:
explicit MeshPool(Device& device);
~MeshPool();
MeshPool(const MeshPool&) = delete;
MeshPool& operator=(const MeshPool&) = delete;
MeshHandle create(const Mesh::Builder& builder);
const Mesh& get(MeshHandle handle) const;
void release(MeshHandle handle);
private:
Device& device;
std::vector<std::unique_ptr<Mesh>> meshes;
std::vector<MeshHandle> freeList;
};
} // namespace sophia
+17
View File
@@ -0,0 +1,17 @@
#include "scene.hpp"
#include <sophia/components.hpp>
#include <sophia/util/logger.hpp>
namespace sophia {
Scene::Scene() {
entt::entity entity = this->registry.create();
auto& a = this->registry.emplace<TransformComponent>(entity);
auto& b = this->registry.get<TransformComponent>(entity);
}
Scene::~Scene() { log::trace("destroying sophia::Scene"); }
} // namespace sophia
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include <entt/entt.hpp>
namespace sophia {
class Scene {
public:
Scene();
~Scene();
private:
entt::registry registry;
};
} // namespace sophia
+8 -8
View File
@@ -1,6 +1,6 @@
#include "model_render_system.hpp"
#include <cassert>
#include <sophia/util/assert.hpp>
#include "shaders/model_render_system.frag.spv.h"
#include "shaders/model_render_system.vert.spv.h"
@@ -12,8 +12,8 @@ ModelRenderSystem::ModelRenderSystem(Device& device,
: device{device}, renderContext{renderContext} {
createPipelineLayout();
assert(this->pipelineLayout.get() != nullptr &&
"Cannot create pipeline before pipeline layout");
SOPHIA_ASSERT(this->pipelineLayout.get() != nullptr,
"Cannot create pipeline before pipeline layout");
auto vertexShader = Shader::Builder()
.fromSPIRV(shaders::model_render_system_vert_spv)
@@ -42,23 +42,23 @@ ModelRenderSystem::~ModelRenderSystem() {
}
void ModelRenderSystem::render(vk::CommandBuffer commandBuffer,
std::span<const std::unique_ptr<Mesh>> meshes,
std::span<const MeshInstance> instances,
const FrameInfo& frameInfo) {
glm::mat4 viewProjection = frameInfo.camera.getViewProjection();
this->graphicsPipeline->bind(commandBuffer);
for (const std::unique_ptr<Mesh>& mesh : meshes) {
for (const MeshInstance& instance : instances) {
PushConstantData push{};
push.modelMatrix = viewProjection;
push.transform = viewProjection * instance.transform;
commandBuffer.pushConstants(
this->pipelineLayout.get(),
vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
0, sizeof(PushConstantData), &push);
mesh->bind(commandBuffer);
mesh->draw(commandBuffer);
instance.mesh->bind(commandBuffer);
instance.mesh->draw(commandBuffer);
}
}
+9 -3
View File
@@ -13,9 +13,15 @@ namespace sophia {
class ModelRenderSystem {
public:
// Layout must match the shader's `Push` block in model_render_system.vert.
struct PushConstantData {
glm::mat4 modelMatrix{1.f};
glm::mat4 normalMatrix{1.f};
glm::mat4 transform{1.f};
glm::vec4 color{1.f};
};
struct MeshInstance {
const Mesh* mesh;
glm::mat4 transform{1.f};
};
ModelRenderSystem(const ModelRenderSystem&) = delete;
@@ -25,7 +31,7 @@ class ModelRenderSystem {
~ModelRenderSystem();
void render(vk::CommandBuffer commandBuffer,
std::span<const std::unique_ptr<Mesh>> meshes,
std::span<const MeshInstance> instances,
const FrameInfo& frameInfo);
private: