feat: assets module
This commit is contained in:
parent
0fe399a33e
commit
0c4b3dd0f9
6 changed files with 353 additions and 0 deletions
14
modules/assets/CMakeLists.txt
Normal file
14
modules/assets/CMakeLists.txt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
add_library_module(assets
|
||||||
|
shader.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
assets
|
||||||
|
PUBLIC
|
||||||
|
logger
|
||||||
|
lt_debug
|
||||||
|
)
|
||||||
|
|
||||||
|
add_test_module(assets
|
||||||
|
shader.test.cpp
|
||||||
|
)
|
73
modules/assets/private/shader.cpp
Normal file
73
modules/assets/private/shader.cpp
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#include <assets/shader.hpp>
|
||||||
|
|
||||||
|
namespace lt::assets {
|
||||||
|
|
||||||
|
ShaderAsset::ShaderAsset(const std::filesystem::path &path)
|
||||||
|
: m_stream(path, std::ios::binary | std::ios::beg)
|
||||||
|
{
|
||||||
|
constexpr auto total_metadata_size = //
|
||||||
|
sizeof(AssetMetadata) //
|
||||||
|
+ sizeof(Metadata) //
|
||||||
|
+ sizeof(BlobMetadata);
|
||||||
|
|
||||||
|
ensure(m_stream.is_open(), "Failed to open shader asset at: {}", path.string());
|
||||||
|
|
||||||
|
m_stream.seekg(0, std::ifstream::end);
|
||||||
|
const auto file_size = static_cast<size_t>(m_stream.tellg());
|
||||||
|
|
||||||
|
ensure(
|
||||||
|
file_size > total_metadata_size,
|
||||||
|
"Failed to open shader asset at: {}, file smaller than metadata: {} < {}",
|
||||||
|
path.string(),
|
||||||
|
total_metadata_size,
|
||||||
|
file_size
|
||||||
|
);
|
||||||
|
|
||||||
|
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
m_stream.seekg(0, std::ifstream::beg);
|
||||||
|
m_stream.read((char *)&m_asset_metadata, sizeof(m_asset_metadata));
|
||||||
|
m_stream.read((char *)&m_metadata, sizeof(m_metadata));
|
||||||
|
m_stream.read((char *)&m_code_blob_metadata, sizeof(m_code_blob_metadata));
|
||||||
|
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
|
||||||
|
ensure(
|
||||||
|
m_asset_metadata.type == asset_type_identifier,
|
||||||
|
"Failed to open shader asset at: {}, incorrect asset type: {} != {}",
|
||||||
|
path.string(),
|
||||||
|
m_asset_metadata.type,
|
||||||
|
asset_type_identifier
|
||||||
|
);
|
||||||
|
|
||||||
|
ensure(
|
||||||
|
m_asset_metadata.version == current_version,
|
||||||
|
"Failed to open shader asset at: {}, version mismatch: {} != {}",
|
||||||
|
path.string(),
|
||||||
|
m_asset_metadata.version,
|
||||||
|
current_version
|
||||||
|
);
|
||||||
|
|
||||||
|
ensure(
|
||||||
|
std::to_underlying(m_metadata.type) <= std::to_underlying(Type::compute),
|
||||||
|
"Failed to open shader asset at: {}, invalid shader type: {}",
|
||||||
|
path.string(),
|
||||||
|
std::to_underlying(m_metadata.type)
|
||||||
|
);
|
||||||
|
|
||||||
|
ensure(
|
||||||
|
m_code_blob_metadata.tag == std::to_underlying(BlobTag::code),
|
||||||
|
"Failed to open shader asset at: {}, invalid blob tag: {}",
|
||||||
|
path.string(),
|
||||||
|
m_code_blob_metadata.tag
|
||||||
|
);
|
||||||
|
|
||||||
|
ensure(
|
||||||
|
m_code_blob_metadata.offset + m_code_blob_metadata.compressed_size <= file_size,
|
||||||
|
"Failed to open shader asset at: {}, file smaller than blob: {} > {} + {}",
|
||||||
|
path.string(),
|
||||||
|
file_size,
|
||||||
|
m_code_blob_metadata.offset,
|
||||||
|
m_code_blob_metadata.compressed_size
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lt::assets
|
89
modules/assets/private/shader.test.cpp
Normal file
89
modules/assets/private/shader.test.cpp
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#include <assets/shader.hpp>
|
||||||
|
#include <ranges>
|
||||||
|
#include <test/test.hpp>
|
||||||
|
|
||||||
|
using ::lt::assets::AssetMetadata;
|
||||||
|
using ::lt::assets::BlobMetadata;
|
||||||
|
using ::lt::assets::ShaderAsset;
|
||||||
|
using ::lt::test::Case;
|
||||||
|
using ::lt::test::expect_eq;
|
||||||
|
using ::lt::test::expect_throw;
|
||||||
|
using ::lt::test::expect_true;
|
||||||
|
using ::lt::test::Suite;
|
||||||
|
|
||||||
|
const auto test_data_path = std::filesystem::path { "./data/test_assets" };
|
||||||
|
const auto tmp_path = std::filesystem::path { "/tmp/lt_assets_tests/" };
|
||||||
|
|
||||||
|
Suite raii = "shader_raii"_suite = [] {
|
||||||
|
std::filesystem::current_path(test_data_path);
|
||||||
|
std::filesystem::create_directories(tmp_path);
|
||||||
|
|
||||||
|
Case { "happy path won't throw" } = [] {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "many won't freeze/throw" } = [] {
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "unhappy path throws" } = [] {
|
||||||
|
expect_throw([] { ShaderAsset { "random_path" }; });
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-interfaces-global-init)
|
||||||
|
Suite packing = "shader_pack"_suite = [] {
|
||||||
|
Case { "" } = [] {
|
||||||
|
const auto out_path = tmp_path / "shader_packing";
|
||||||
|
auto dummy_blob = lt::assets::Blob {};
|
||||||
|
for (auto idx : std::views::iota(0, 255))
|
||||||
|
{
|
||||||
|
dummy_blob.emplace_back(static_cast<std::byte>(idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto expected_size = //
|
||||||
|
sizeof(AssetMetadata) //
|
||||||
|
+ sizeof(ShaderAsset::Metadata) //
|
||||||
|
+ sizeof(BlobMetadata) //
|
||||||
|
+ dummy_blob.size();
|
||||||
|
|
||||||
|
ShaderAsset::pack(
|
||||||
|
out_path,
|
||||||
|
lt::assets::AssetMetadata {
|
||||||
|
.version = lt::assets::current_version,
|
||||||
|
.type = ShaderAsset::asset_type_identifier,
|
||||||
|
},
|
||||||
|
ShaderAsset::Metadata {
|
||||||
|
.type = ShaderAsset::Type::vertex,
|
||||||
|
},
|
||||||
|
std::move(dummy_blob)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto stream = std::ifstream {
|
||||||
|
out_path,
|
||||||
|
std::ios::binary | std::ios::beg,
|
||||||
|
};
|
||||||
|
expect_true(stream.is_open());
|
||||||
|
|
||||||
|
stream.seekg(0, std::ios::end);
|
||||||
|
const auto file_size = static_cast<size_t>(stream.tellg());
|
||||||
|
expect_eq(file_size, expected_size);
|
||||||
|
stream.close();
|
||||||
|
|
||||||
|
auto shader_asset = ShaderAsset { out_path };
|
||||||
|
|
||||||
|
const auto &asset_metadata = shader_asset.get_asset_metadata();
|
||||||
|
expect_eq(asset_metadata.type, ShaderAsset::asset_type_identifier);
|
||||||
|
expect_eq(asset_metadata.version, lt::assets::current_version);
|
||||||
|
|
||||||
|
const auto &metadata = shader_asset.get_metadata();
|
||||||
|
expect_eq(metadata.type, ShaderAsset::Type::vertex);
|
||||||
|
|
||||||
|
auto blob = shader_asset.unpack(ShaderAsset::BlobTag::code);
|
||||||
|
expect_eq(blob.size(), 255);
|
||||||
|
|
||||||
|
for (auto idx : std::views::iota(0, 255))
|
||||||
|
{
|
||||||
|
expect_eq(blob[idx], static_cast<std::byte>(idx));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
3
modules/assets/public/compressors/lz4.hpp
Normal file
3
modules/assets/public/compressors/lz4.hpp
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// TO BE DOOO
|
42
modules/assets/public/metadata.hpp
Normal file
42
modules/assets/public/metadata.hpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace lt::assets {
|
||||||
|
|
||||||
|
using Type_T = std::array<const char, 16>;
|
||||||
|
|
||||||
|
using Tag_T = uint8_t;
|
||||||
|
|
||||||
|
using Version = uint8_t;
|
||||||
|
|
||||||
|
using Blob = std::vector<std::byte>;
|
||||||
|
|
||||||
|
constexpr auto current_version = Version { 1u };
|
||||||
|
|
||||||
|
enum class CompressionType : uint8_t
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
lz4,
|
||||||
|
lz4_hc,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AssetMetadata
|
||||||
|
{
|
||||||
|
Version version;
|
||||||
|
|
||||||
|
Type_T type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BlobMetadata
|
||||||
|
{
|
||||||
|
Tag_T tag;
|
||||||
|
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
CompressionType compression_type;
|
||||||
|
|
||||||
|
size_t compressed_size;
|
||||||
|
|
||||||
|
size_t uncompressed_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lt::assets
|
132
modules/assets/public/shader.hpp
Normal file
132
modules/assets/public/shader.hpp
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <assets/metadata.hpp>
|
||||||
|
|
||||||
|
namespace lt::assets {
|
||||||
|
|
||||||
|
class ShaderAsset
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr auto asset_type_identifier = Type_T { "SHADER_________" };
|
||||||
|
|
||||||
|
enum class BlobTag : Tag_T
|
||||||
|
{
|
||||||
|
code,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Type : uint8_t
|
||||||
|
{
|
||||||
|
vertex,
|
||||||
|
fragment,
|
||||||
|
geometry,
|
||||||
|
compute,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Metadata
|
||||||
|
{
|
||||||
|
Type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void pack(
|
||||||
|
const std::filesystem::path &destination,
|
||||||
|
AssetMetadata asset_metadata,
|
||||||
|
Metadata metadata,
|
||||||
|
Blob code_blob
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto stream = std::ofstream {
|
||||||
|
destination,
|
||||||
|
std::ios::binary | std::ios::trunc,
|
||||||
|
};
|
||||||
|
ensure(stream.is_open(), "Failed to pack shader asset to {}", destination.string());
|
||||||
|
|
||||||
|
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
stream.write((char *)&asset_metadata, sizeof(asset_metadata));
|
||||||
|
stream.write((char *)&metadata, sizeof(metadata));
|
||||||
|
|
||||||
|
auto code_blob_metadata = BlobMetadata {
|
||||||
|
.tag = std::to_underlying(BlobTag::code),
|
||||||
|
.offset = static_cast<size_t>(stream.tellp()) + sizeof(BlobMetadata),
|
||||||
|
.compression_type = CompressionType::none,
|
||||||
|
.compressed_size = code_blob.size(),
|
||||||
|
.uncompressed_size = code_blob.size(),
|
||||||
|
};
|
||||||
|
stream.write((char *)&code_blob_metadata, sizeof(BlobMetadata));
|
||||||
|
|
||||||
|
stream.write((char *)code_blob.data(), static_cast<long long>(code_blob.size()));
|
||||||
|
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderAsset(const std::filesystem::path &path);
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_asset_metadata() const -> const AssetMetadata &
|
||||||
|
{
|
||||||
|
return m_asset_metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_metadata() const -> const Metadata &
|
||||||
|
{
|
||||||
|
return m_metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_blob_metadata(BlobTag tag) const -> const BlobMetadata &
|
||||||
|
{
|
||||||
|
ensure(
|
||||||
|
tag == BlobTag::code,
|
||||||
|
"Invalid blob tag for shader asset: {}",
|
||||||
|
std::to_underlying(tag)
|
||||||
|
);
|
||||||
|
|
||||||
|
return m_code_blob_metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unpack_to(BlobTag tag, std::span<std::byte> destination) const
|
||||||
|
{
|
||||||
|
ensure(
|
||||||
|
tag == BlobTag::code,
|
||||||
|
"Invalid blob tag for shader asset: {}",
|
||||||
|
std::to_underlying(tag)
|
||||||
|
);
|
||||||
|
|
||||||
|
ensure(
|
||||||
|
destination.size() >= m_code_blob_metadata.uncompressed_size,
|
||||||
|
"Failed to unpack shader blob {} to destination ({}) of size {} since it's smaller "
|
||||||
|
"than the blobl's uncompressed size: {}",
|
||||||
|
std::to_underlying(tag),
|
||||||
|
(size_t)(destination.data()), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
destination.size(),
|
||||||
|
m_code_blob_metadata.uncompressed_size
|
||||||
|
);
|
||||||
|
|
||||||
|
m_stream.seekg(static_cast<long long>(m_code_blob_metadata.offset));
|
||||||
|
m_stream.read(
|
||||||
|
(char *)destination.data(), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
static_cast<long long>(m_code_blob_metadata.uncompressed_size)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto unpack(BlobTag tag) const -> Blob
|
||||||
|
{
|
||||||
|
ensure(
|
||||||
|
tag == BlobTag::code,
|
||||||
|
"Invalid blob tag for shader asset: {}",
|
||||||
|
std::to_underlying(tag)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto blob = Blob(m_code_blob_metadata.uncompressed_size);
|
||||||
|
unpack_to(tag, blob);
|
||||||
|
|
||||||
|
return blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AssetMetadata m_asset_metadata {};
|
||||||
|
|
||||||
|
Metadata m_metadata {};
|
||||||
|
|
||||||
|
BlobMetadata m_code_blob_metadata {};
|
||||||
|
|
||||||
|
mutable std::ifstream m_stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lt::assets
|
Loading…
Add table
Reference in a new issue