refactor: asset loading/caching

This commit is contained in:
light7734 2025-07-10 21:51:17 +03:30
parent eca1bc91e6
commit b572b61f4b
Signed by: light7734
GPG key ID: 8C30176798F1A6BA
14 changed files with 174 additions and 140 deletions

View file

@ -2,20 +2,29 @@
#include <filesystem> #include <filesystem>
namespace Assets {
class TextAsset;
class TextureAsset;
} // namespace Assets
namespace Light { namespace Light {
class Shader; class Shader;
class Texture; class Texture;
/**
* Asset is the data on the disk.
* Resource is the data on the gpu/cpu
*
* eg. TextureAsset is the file on the disk
* eg. Texture is the representation of it in the GPU
*/
class AssetManager class AssetManager
{ {
public: public:
static auto instance() -> AssetManager &
{
static auto instance = AssetManager {};
return instance;
}
static void load_shader( static void load_shader(
const std::string &name, const std::string &name,
const std::filesystem::path &vertex_path, const std::filesystem::path &vertex_path,
@ -43,6 +52,8 @@ public:
private: private:
AssetManager() = default; AssetManager() = default;
static auto instance() -> AssetManager &;
void load_shader_impl( void load_shader_impl(
const std::string &name, const std::string &name,
const std::filesystem::path &vertex_path, const std::filesystem::path &vertex_path,
@ -51,6 +62,14 @@ private:
void load_texture_impl(const std::string &name, const std::filesystem::path &path); void load_texture_impl(const std::string &name, const std::filesystem::path &path);
auto get_or_load_text_asset(const std::filesystem::path &path) -> Ref<Assets::TextAsset>;
auto get_or_load_texture_asset(const std::filesystem::path &path) -> Ref<Assets::TextureAsset>;
std::unordered_map<std::string, Ref<Assets::TextAsset>> m_text_assets;
std::unordered_map<std::string, Ref<Assets::TextureAsset>> m_texture_assets;
std::unordered_map<std::string, Ref<Shader>> m_shaders; std::unordered_map<std::string, Ref<Shader>> m_shaders;
std::unordered_map<std::string, Ref<Texture>> m_textures; std::unordered_map<std::string, Ref<Texture>> m_textures;

View file

@ -1,13 +1,19 @@
#include <asset_manager/asset_manager.hpp>
#include <asset_parser/assets/text.hpp> #include <asset_parser/assets/text.hpp>
#include <asset_parser/assets/texture.hpp> #include <asset_parser/assets/texture.hpp>
#include <logger/logger.hpp>
#include <renderer/graphics_context.hpp> #include <renderer/graphics_context.hpp>
#include <renderer/shader.hpp> #include <renderer/shader.hpp>
#include <renderer/texture.hpp> #include <renderer/texture.hpp>
#include <asset_manager/asset_manager.hpp>
#include <logger/logger.hpp>
namespace Light { namespace Light {
/* static */ auto AssetManager::instance() -> AssetManager &
{
static auto instance = AssetManager {};
return instance;
}
void AssetManager::load_shader_impl( void AssetManager::load_shader_impl(
const std::string &name, const std::string &name,
const std::filesystem::path &vertex_path, const std::filesystem::path &vertex_path,
@ -21,21 +27,9 @@ void AssetManager::load_shader_impl(
log_trc("\tvertex path: {}", vertex_path.string()); log_trc("\tvertex path: {}", vertex_path.string());
log_trc("\tpixel path : {}", pixel_path.string()); log_trc("\tpixel path : {}", pixel_path.string());
auto vertex_asset = Assets::TextAsset { vertex_path };
auto pixel_asset = Assets::TextAsset { pixel_path };
auto vertex_blob_metadata = vertex_asset.get_blob_metadata(Assets::BlobMetadata::Tag::text);
auto pixel_blob_metadata = pixel_asset.get_blob_metadata(Assets::BlobMetadata::Tag::text);
auto vertex_blob = Assets::Blob(vertex_blob_metadata.uncompressed_size);
auto pixel_blob = Assets::Blob(pixel_blob_metadata.uncompressed_size);
vertex_asset.unpack_blob(vertex_blob_metadata.tag, vertex_blob.data(), vertex_blob.size());
pixel_asset.unpack_blob(pixel_blob_metadata.tag, pixel_blob.data(), pixel_blob.size());
m_shaders[name] = Ref<Shader>(Shader::create( m_shaders[name] = Ref<Shader>(Shader::create(
std::move(vertex_blob), get_or_load_text_asset(vertex_path.string()),
std::move(pixel_blob), get_or_load_text_asset(pixel_path),
GraphicsContext::get_shared_context() GraphicsContext::get_shared_context()
)); ));
} }
@ -57,21 +51,9 @@ void AssetManager::load_texture_impl(const std::string &name, const std::filesys
log_trc("\tname: {}", name); log_trc("\tname: {}", name);
log_trc("\tpath: {}", path.string()); log_trc("\tpath: {}", path.string());
auto asset = Assets::TextureAsset { path }; m_textures[name] = Ref<Texture>(
const auto metadata = asset.get_metadata(); Texture::create(get_or_load_texture_asset(path), GraphicsContext::get_shared_context())
const auto blob_metadata = asset.get_blob_metadata(Assets::BlobMetadata::Tag::color); );
auto blob = std::vector<std::byte>(blob_metadata.uncompressed_size);
asset.unpack_blob(blob_metadata.tag, blob.data(), blob.size());
m_textures[name] = Ref<Texture>(Texture::create(
metadata.pixel_size[0],
metadata.pixel_size[1],
metadata.num_components,
std::bit_cast<unsigned char *>(blob.data()),
GraphicsContext::get_shared_context(),
path
));
} }
catch (const std::exception &exp) catch (const std::exception &exp)
{ {
@ -82,4 +64,29 @@ void AssetManager::load_texture_impl(const std::string &name, const std::filesys
} }
} }
auto AssetManager::get_or_load_text_asset(const std::filesystem::path &path)
-> Ref<Assets::TextAsset>
{
const auto key = std::filesystem::canonical(path).string();
if (!m_text_assets.contains(key))
{
m_text_assets.emplace(key, create_ref<Assets::TextAsset>(path));
}
return m_text_assets[key];
}
auto AssetManager::get_or_load_texture_asset(const std::filesystem::path &path)
-> Ref<Assets::TextureAsset>
{
const auto key = std::filesystem::canonical(path).string();
if (!m_texture_assets.contains(key))
{
m_texture_assets.emplace(key, create_ref<Assets::TextureAsset>(path));
}
return m_texture_assets[key];
}
} // namespace Light } // namespace Light

View file

@ -31,7 +31,8 @@ public:
TextAsset(const std::filesystem::path &path); TextAsset(const std::filesystem::path &path);
void unpack_blob(BlobMetadata::Tag tag, std::byte *destination, size_t destination_capacity); void unpack_blob(BlobMetadata::Tag tag, std::byte *destination, size_t destination_capacity)
const;
[[nodiscard]] auto get_asset_metadata() const -> const Asset::Metadata &; [[nodiscard]] auto get_asset_metadata() const -> const Asset::Metadata &;
@ -48,7 +49,7 @@ private:
BlobMetadata m_text_blob_metadata {}; BlobMetadata m_text_blob_metadata {};
std::ifstream m_stream; mutable std::ifstream m_stream;
}; };
} // namespace Assets } // namespace Assets

View file

@ -80,7 +80,7 @@ void TextAsset::unpack_blob(
BlobMetadata::Tag tag, BlobMetadata::Tag tag,
std::byte *destination, std::byte *destination,
size_t destination_capacity size_t destination_capacity
) ) const
{ {
if (tag != BlobMetadata::Tag::text) if (tag != BlobMetadata::Tag::text)
{ {

View file

@ -3,7 +3,6 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <utility> #include <utility>
#include <utility>
namespace Light { namespace Light {

View file

@ -269,16 +269,17 @@ void SceneSerializer::serialize_entity(YAML::Emitter &out, Entity entity)
if (entity.has_component<SpriteRendererComponent>()) if (entity.has_component<SpriteRendererComponent>())
{ {
out << YAML::Key << "SpriteRendererComponent"; // TODO(Light): get scene serialization/de-serialization working.
out << YAML::BeginMap; // sprite renderer component; // out << YAML::Key << "SpriteRendererComponent";
// out << YAML::BeginMap; // sprite renderer component;
auto &spriteRendererComponent = entity.get_component<SpriteRendererComponent>(); // auto &spriteRendererComponent = entity.get_component<SpriteRendererComponent>();
out << YAML::Key << "Texture" << YAML::Value // out << YAML::Key << "Texture" << YAML::Value
<< spriteRendererComponent.texture->GetFilePath(); // << spriteRendererComponent.texture->GetFilePath();
out << YAML::Key << "Tint" << YAML::Value << spriteRendererComponent.tint; // out << YAML::Key << "Tint" << YAML::Value << spriteRendererComponent.tint;
out << YAML::EndMap; // sprite renderer component // out << YAML::EndMap; // sprite renderer component
} }
// #todo: // #todo:

View file

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <renderer/shader.hpp> #include <renderer/shader.hpp>
namespace Light { namespace Light {
@ -8,7 +7,7 @@ namespace Light {
class glShader: public Shader class glShader: public Shader
{ {
public: public:
glShader(Assets::Blob vertex_blob, Assets::Blob pixel_blob); glShader(const Ref<Assets::TextAsset> &vertex_asset, const Ref<Assets::TextAsset> &pixel_asset);
~glShader() override; ~glShader() override;

View file

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <renderer/texture.hpp> #include <renderer/texture.hpp>
namespace Light { namespace Light {
@ -8,13 +7,7 @@ namespace Light {
class glTexture: public Texture class glTexture: public Texture
{ {
public: public:
glTexture( glTexture(const Ref<Assets::TextureAsset> &asset);
unsigned int width,
unsigned int height,
unsigned int components,
unsigned char *pixels,
const std::string &filePath
);
~glTexture() override; ~glTexture() override;
@ -23,7 +16,11 @@ public:
auto get_texture() -> void * override; auto get_texture() -> void * override;
private: private:
unsigned int m_texture_id; [[nodiscard]] auto map_num_components_to_format(uint32_t num_components) const -> int;
[[nodiscard]] auto map_num_components_to_internal_format(uint32_t num_components) const -> int;
uint32_t m_texture_id {};
}; };
} // namespace Light } // namespace Light

View file

@ -1,9 +1,13 @@
#pragma once #pragma once
#include <asset_parser/assets/text.hpp>
#include <glm/glm.hpp> #include <glm/glm.hpp>
namespace Assets {
class TextAsset;
} // namespace Assets
namespace Light { namespace Light {
class SharedContext; class SharedContext;
@ -11,7 +15,7 @@ class SharedContext;
class Shader class Shader
{ {
public: public:
enum Stage enum Stage : uint8_t
{ {
none = 0, none = 0,
@ -21,8 +25,8 @@ public:
}; };
static auto create( static auto create(
Assets::Blob vertex_blob, Ref<Assets::TextAsset> vertex_asset,
Assets::Blob pixel_blob, Ref<Assets::TextAsset> pixel_asset,
const Ref<SharedContext> &shared_context const Ref<SharedContext> &shared_context
) -> Ref<Shader>; ) -> Ref<Shader>;

View file

@ -1,6 +1,10 @@
#pragma once #pragma once
namespace Assets {
class TextureAsset;
}
namespace Light { namespace Light {
@ -10,33 +14,26 @@ class Texture
{ {
public: public:
static Ref<Texture> create( static Ref<Texture> create(
unsigned int width, Ref<Assets::TextureAsset> asset,
unsigned int height, const Ref<SharedContext> &shared_context
unsigned int components,
unsigned char *pixels,
const Ref<SharedContext>& sharedContext,
const std::string &filePath
); );
virtual ~Texture() = default;
Texture(Texture &&) = default;
auto operator=(Texture &&) -> Texture & = default;
Texture(const Texture &) = delete; Texture(const Texture &) = delete;
auto operator=(const Texture &) -> Texture & = delete; auto operator=(const Texture &) -> Texture & = delete;
virtual ~Texture() = default;
virtual void bind(unsigned int slot = 0) = 0; virtual void bind(unsigned int slot = 0) = 0;
virtual auto get_texture() -> void * = 0; virtual auto get_texture() -> void * = 0;
[[nodiscard]] auto GetFilePath() const -> const std::string &
{
return m_file_path;
}
protected: protected:
std::string m_file_path; Texture() = default;
Texture(std::string filePath);
}; };
} // namespace Light } // namespace Light

View file

@ -1,14 +1,27 @@
#include <renderer/gl/shader.hpp> #include <asset_parser/assets/text.hpp>
#include <glad/gl.h> #include <glad/gl.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/matrix.hpp> #include <glm/matrix.hpp>
#include <renderer/gl/shader.hpp>
namespace Light { namespace Light {
glShader::glShader(Assets::Blob vertex_blob, Assets::Blob pixel_blob) glShader::glShader(
const Ref<Assets::TextAsset> &vertex_asset,
const Ref<Assets::TextAsset> &pixel_asset
)
: m_shader_id(glCreateProgram()) : m_shader_id(glCreateProgram())
{ {
auto vertex_blob_metadata = vertex_asset->get_blob_metadata(Assets::BlobMetadata::Tag::text);
auto pixel_blob_metadata = pixel_asset->get_blob_metadata(Assets::BlobMetadata::Tag::text);
auto vertex_blob = Assets::Blob(vertex_blob_metadata.uncompressed_size);
auto pixel_blob = Assets::Blob(pixel_blob_metadata.uncompressed_size);
vertex_asset->unpack_blob(vertex_blob_metadata.tag, vertex_blob.data(), vertex_blob.size());
pixel_asset->unpack_blob(pixel_blob_metadata.tag, pixel_blob.data(), pixel_blob.size());
auto vertex_source = std::string { auto vertex_source = std::string {
vertex_blob.data(), vertex_blob.data(),
vertex_blob.data() + vertex_blob.size(), // NOLINT vertex_blob.data() + vertex_blob.size(), // NOLINT

View file

@ -1,58 +1,35 @@
#include <glad/gl.h> #include <asset_parser/assets/texture.hpp>
#include <debug/assertions.hpp> #include <debug/assertions.hpp>
#include <glad/gl.h>
#include <renderer/gl/texture.hpp> #include <renderer/gl/texture.hpp>
namespace Light { namespace Light {
glTexture::glTexture( glTexture::glTexture(const Ref<Assets::TextureAsset> &asset)
unsigned int width,
unsigned int height,
unsigned int components,
unsigned char *pixels,
const std::string &filePath
)
: Texture(filePath)
, m_texture_id(NULL)
{ {
// create texture const auto metadata = asset->get_metadata();
glCreateTextures(GL_TEXTURE_2D, 1, &m_texture_id); const auto blob_metadata = asset->get_blob_metadata(Assets::BlobMetadata::Tag::color);
// set texture parameters glCreateTextures(GL_TEXTURE_2D, 1, &m_texture_id);
glTextureParameteri(m_texture_id, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTextureParameteri(m_texture_id, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTextureParameteri(m_texture_id, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTextureParameteri(m_texture_id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureParameteri(m_texture_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTextureParameteri(m_texture_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextureParameteri(m_texture_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTextureParameteri(m_texture_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// determine formats auto blob = std::vector<std::byte>(blob_metadata.uncompressed_size);
auto format = components == 4u ? GL_RGBA : asset->unpack_blob(blob_metadata.tag, blob.data(), blob.size());
components == 3u ? GL_RGB :
components == 2u ? GL_RG :
components == 1u ? GL_RED :
NULL;
auto internalFormat = format == GL_RGBA ? GL_RGBA8 :
format == GL_RGB ? GL_RGB8 :
format == GL_RG ? GL_RG8 :
format == GL_RED ? GL_R8 :
NULL;
// check
lt_assert(format, "Invalid number of components: {}", components);
// #todo: isn't there something like glTextureImage2D ???
// create texture and mipsmaps
bind(); bind();
glTexImage2D( glTexImage2D(
GL_TEXTURE_2D, GL_TEXTURE_2D,
0, 0,
internalFormat, map_num_components_to_internal_format(metadata.num_components),
width, static_cast<int>(metadata.pixel_size[0]),
height, static_cast<int>(metadata.pixel_size[1]),
0, 0,
format, map_num_components_to_format(metadata.num_components),
GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE,
pixels std::bit_cast<unsigned char *>(blob.data())
); );
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
} }
@ -73,4 +50,33 @@ auto glTexture::get_texture() -> void *
return (void *)(intptr_t)m_texture_id; return (void *)(intptr_t)m_texture_id;
} }
[[nodiscard]] auto glTexture::map_num_components_to_format(uint32_t num_components) const -> int
{
switch (num_components)
{
case 4u: return GL_RGBA;
case 3u: return GL_RGB;
case 2u: return GL_RG;
case 1u: return GL_RED;
default: lt_assert(false, "Invalid number of components: {}", num_components);
}
return {};
}
[[nodiscard]] auto glTexture::map_num_components_to_internal_format(uint32_t num_components) const
-> int
{
switch (num_components)
{
case 4u: return GL_RGBA8;
case 3u: return GL_RGB8;
case 2u: return GL_RG8;
case 1u: return GL_R8;
default: lt_assert(false, "Invalid number of components: {}", num_components);
}
return {};
}
} // namespace Light } // namespace Light

View file

@ -1,5 +1,6 @@
#include <renderer/shader.hpp> #include <asset_parser/assets/text.hpp>
#include <renderer/gl/shader.hpp> #include <renderer/gl/shader.hpp>
#include <renderer/shader.hpp>
#ifdef LIGHT_PLATFORM_WINDOWS #ifdef LIGHT_PLATFORM_WINDOWS
#include <renderer/dx/shader.hpp> #include <renderer/dx/shader.hpp>
@ -10,9 +11,9 @@
namespace Light { namespace Light {
auto Shader::create( /* static */ auto Shader::create(
Assets::Blob vertex_blob, Ref<Assets::TextAsset> vertex_asset,
Assets::Blob pixel_blob, Ref<Assets::TextAsset> pixel_asset,
const Ref<SharedContext> &shared_context const Ref<SharedContext> &shared_context
) -> Ref<Shader> ) -> Ref<Shader>
{ {
@ -22,12 +23,12 @@ auto Shader::create(
switch (GraphicsContext::get_graphics_api()) switch (GraphicsContext::get_graphics_api())
{ {
case GraphicsAPI::OpenGL: case GraphicsAPI::OpenGL:
return create_ref<glShader>(std::move(vertex_blob), std::move(pixel_blob)); return create_ref<glShader>(std::move(vertex_asset), std::move(pixel_asset));
case GraphicsAPI::DirectX: case GraphicsAPI::DirectX:
lt_win(return create_ref<dxShader>( lt_win(return create_ref<dxShader>(
vertexFile, vertex_asset,
pixelFile, pixel_asset,
std::static_pointer_cast<dxSharedContext>(sharedContext) std::static_pointer_cast<dxSharedContext>(sharedContext)
);); ););

View file

@ -8,23 +8,17 @@
#endif #endif
#include <renderer/graphics_context.hpp> #include <renderer/graphics_context.hpp>
#include <utility>
namespace Light { namespace Light {
auto Texture::create( /* static */ auto Texture::create(
unsigned int width, Ref<Assets::TextureAsset> asset,
unsigned int height, const Ref<SharedContext> &shared_context
unsigned int components,
unsigned char *pixels,
const Ref<SharedContext> & /*sharedContext*/,
const std::string &filePath
) -> Ref<Texture> ) -> Ref<Texture>
{ {
switch (GraphicsContext::get_graphics_api()) switch (GraphicsContext::get_graphics_api())
{ {
case GraphicsAPI::OpenGL: case GraphicsAPI::OpenGL: return create_ref<glTexture>(std::move(asset));
return create_ref<glTexture>(width, height, components, pixels, filePath);
case GraphicsAPI::DirectX: case GraphicsAPI::DirectX:
lt_win(return create_ref<dxTexture>( lt_win(return create_ref<dxTexture>(
@ -46,8 +40,4 @@ auto Texture::create(
} }
} }
Texture::Texture(std::string filePath): m_file_path(std::move(filePath))
{
}
} // namespace Light } // namespace Light