Files
DX12/Engine/Content/ContentToEngine.cpp
2026-03-19 18:27:49 +08:00

529 lines
14 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file ContentToEngine.cpp
* @brief 内容二进制数据到渲染/资源句柄的转换实现。
* @details
* 本文件完成导入数据的运行时落地,包含:
* - 网格层级(LOD)结构重排与子网格 GPU 资源创建;
* - 着色器分组缓存与 key 索引查询;
* - 材质/纹理/几何资源的统一创建与释放入口。
*/
#include "ContentToEngine.h"
#include "Graphics\Renderer.h"
#include "Utilities\IOStream.h"
namespace XEngine::content {
namespace {
/**
* @brief 几何层级缓冲区的视图封装。
* @details
* 对连续内存中的几何层级布局进行字段映射提供阈值、LOD 偏移与 GPU ID 访问。
*/
class geometry_hierarchy_stream
{
public:
DISABLE_COPY_AND_MOVE(geometry_hierarchy_stream);
geometry_hierarchy_stream(u8 *const buffer, u32 lods = u32_invalid_id)
:_buffer{ buffer }
{
assert(buffer && lods);
if (lods != u32_invalid_id)
{
*((u32*)buffer) = lods;
}
_lod_count = *((u32*)buffer);
_thresholds = (f32*)(&buffer[sizeof(u32)]);
_lod_offsets = (lod_offset*)(&_thresholds[_lod_count]);
_gpu_ids = (id::id_type*)(&_lod_offsets[_lod_count]);
}
void gpu_ids(u32 lod, id::id_type*& ids, u32& id_count)
{
assert(lod < _lod_count);
ids = &_gpu_ids[_lod_offsets[lod].offset];
id_count = _lod_offsets[lod].count;
}
u32 lod_from_threshold(f32 threshold)
{
assert(threshold > 0);
if (_lod_count == 1) return 0;
for (u32 i{ _lod_count - 1 }; i > 0; --i)
{
if (_thresholds[i] <= threshold) return i;
}
assert(false);
return 0;
}
[[nodiscard]] constexpr u32 lod_count() const { return _lod_count; }
[[nodiscard]] constexpr f32* thresholds() const { return _thresholds; }
[[nodiscard]] constexpr lod_offset* lod_offsets() const { return _lod_offsets; }
[[nodiscard]] constexpr id::id_type* gpu_ids() const { return _gpu_ids; }
private:
u8 *const _buffer;
f32* _thresholds;
lod_offset* _lod_offsets;
id::id_type* _gpu_ids;
u32 _lod_count;
};
/**
* @brief 支持 noexcept 移动的着色器组缓存容器。
*/
struct noexcept_map {
std::unordered_map<u32, std::unique_ptr<u8[]>> map;
noexcept_map() = default;
noexcept_map(const noexcept_map&) = default;
noexcept_map(noexcept_map&&) noexcept = default;
noexcept_map& operator=(const noexcept_map&) = default;
noexcept_map& operator=(noexcept_map&&) noexcept = default;
};
/**
* @brief 单子网格资源的指针标记位。
*/
constexpr uintptr_t single_mesh_marker{ (uintptr_t)0x01 };
/**
* @brief 几何层级资源池。
*/
utl::free_list<u8*> geometry_hierarchies;
/**
* @brief 几何资源互斥锁。
*/
std::mutex geometry_mutex;
/**
* @brief 着色器组资源池。
*/
utl::free_list<noexcept_map> shader_groups;
/**
* @brief 着色器资源互斥锁。
*/
std::mutex shader_mutex;
/**
* @brief 预估并计算几何层级缓冲区所需字节数。
* @param data 几何二进制输入数据。
* @return 所需缓冲区大小(字节)。
*/
u32
get_geometry_hierarchy_buffer_size(const void *const data)
{
assert(data);
utl::blob_stream_reader blob{ (const u8*)data };
const u32 lod_count{ blob.reader<u32>() };
assert(lod_count);
constexpr u32 su32{ sizeof(u32) };
u32 size{ su32 + (sizeof(f32) + sizeof(lod_offset)) * lod_count };
for (u32 lod_idx{ 0 }; lod_idx < lod_count; ++lod_idx)
{
// skip threshold
blob.skip(sizeof(f32));
// add size of gpu_ids
size += sizeof(id::id_type) * blob.reader<u32>();
// skip submesh data and goto next LOD
blob.skip(blob.reader<u32>());
}
return size;
}
/**
* @brief 创建多 LOD 网格层级资源。
* @param data 几何二进制输入数据。
* @return 几何内容资源 ID。
*/
//id::id_type
//create_mesh_hierarchy(const void *const data)
//{
// assert(data);
//
// const u32 size{ get_geometry_hierarchy_buffer_size(data) };
// u8 *const hierarchy_buffer{ (u8 *const)malloc(size) };
//
// utl::blob_stream_reader blob{ (const u8*)data };
// const u32 lod_count{ blob.reader<u32>() };
// assert(lod_count);
// geometry_hierarchy_stream stream{ hierarchy_buffer, lod_count };
// u32 submesh_index{ 0 };
// id::id_type *const gpu_ids{ stream.gpu_ids() };
//
// for (u32 lod_idx{ 0 }; lod_idx < lod_count; ++lod_idx)
// {
// stream.thresholds()[lod_idx] = blob.reader<f32>();
// const u32 id_count{ blob.reader<u32>() };
// assert(id_count < (1 << 16));
// stream.lod_offsets()[lod_idx] = { (u16)submesh_index, (u16)id_count };
// blob.skip(sizeof(u32)); // skip sizeof submeshes
// for (u32 id_idx{ 0 }; id_idx < id_count; ++id_idx)
// {
// const u8* at{ blob.position() };
// gpu_ids[submesh_index++] = graphics::add_submesh(at);
// blob.skip((u32)(at - blob.position()));
// assert(submesh_index < (1 << 16));
// }
// }
//
// assert([&]()
// {
// f32 previous_theshold{ stream.thresholds()[0] };
// for (u32 i{ 1 }; i < lod_count; ++i)
// {
// if (stream.thresholds()[i] <= previous_theshold) return false;
// previous_theshold = stream.thresholds()[i];
// }
// return true;
// }());
//
// static_assert(alignof(void*) > 2, "We need the least significant bit for th single mesh marker.");
// std::lock_guard lock{ geometry_mutex };
// return geometry_hierarchies.add(hierarchy_buffer);
//}
/**
* @brief 判断几何数据是否为单 LOD 单子网格。
* @param data 几何二进制输入数据。
* @return 单子网格返回 true。
*/
bool
is_single_mesh(const void *const data)
{
assert(data);
utl::blob_stream_reader blob{ (const u8*)data };
const u32 lod_count{ blob.reader<u32>() };
assert(lod_count);
if (lod_count > 1) return false;
blob.skip(sizeof(f32)); // skip threhold
const u32 submesh_count{ blob.reader<u32>() };
assert(submesh_count);
return submesh_count == 1;
}
/**
* @brief 创建单子网格资源并编码为伪指针句柄。
* @param data 几何二进制输入数据。
* @return 几何内容资源 ID。
*/
//id::id_type
//create_single_submesh(const void *const data)
//{
// assert(data);
// utl::blob_stream_reader blob{ (const u8*)data };
// // skip lod_count, lod_threshold, submesh_count, and sizeof_submeshes
// blob.skip(sizeof(u32) + sizeof(f32) + sizeof(u32) + sizeof(u32));
// const u8* at{ blob.position() };
// const id::id_type gpu_id{ graphics::add_submesh(at) };
//
// // create a fake pointer and put it in the geometry_hierarchies.
// static_assert(sizeof(uintptr_t) > sizeof(id::id_type));
// constexpr u8 shift_bits{ (sizeof(uintptr_t) - sizeof(id::id_type)) << 3 };
// u8 *const fake_pointer{ (u8 *const)((((uintptr_t)gpu_id) << shift_bits) | single_mesh_marker) };
// std::lock_guard lock{ geometry_mutex };
// return geometry_hierarchies.add(fake_pointer);
//}
/**
* @brief 从单子网格伪指针解码 GPU 资源 ID。
* @param pointer 编码后的伪指针。
* @return GPU 子网格 ID。
*/
constexpr id::id_type
gpu_id_from_fake_pointer(u8 *const pointer)
{
assert((uintptr_t)pointer & single_mesh_marker);
static_assert(sizeof(uintptr_t) > sizeof(id::id_type));
constexpr u8 shift_bits{ (sizeof(uintptr_t) - sizeof(id::id_type)) << 3 };
return (((uintptr_t)pointer) >> shift_bits) & (uintptr_t)id::invalid_id;
}
//
// data contain:
//struct{
// u32 lod_count,
// struct{
// f32 lod_threshold,
// u32 submesh_count,
// u32 sizeof_submeshes,
// struct{
// u32 element_size, u32 vertex_count,
// u32 index_count, u32 elements_type, u32 primitive_topology
// u8 positions[sizeof(f32) * 3 * vertex_count],
// u8 elements[sizeof(element_size) * vertex_count],
// u8 indices[index_size * index_count],
// } submeshes[submesh_count]
// }mesh_lods[lod_count]
// } geometry;
//
// Output format
//
// struct{
// u32 lod_count,
// f32 thresholds[lod_count]
// struct{
// u16 offset,
// u16 count
// }lod_offsets[lod_count],
// id::idtype gpu_ids[total_number_of_submeshes]
//}geometry_hierarchy
//
//
//
//
/**
* @brief 按输入几何形态创建对应资源。
* @param data 几何二进制输入数据。
* @return 几何内容资源 ID。
*/
//id::id_type
//create_geometry_resource(const void *const data)
//{
// assert(data);
// return is_single_mesh(data) ? create_single_submesh(data) : create_mesh_hierarchy(data);
//}
/**
* @brief 销毁几何资源并释放关联子网格。
* @param id 几何内容资源 ID。
*/
//void
//destory_geometry_resource(id::id_type id)
//{
// std::lock_guard lock{ geometry_mutex };
// u8 *const pointer{ geometry_hierarchies[id] };
// if ((uintptr_t)pointer & single_mesh_marker)
// {
// graphics::remove_submesh(gpu_id_from_fake_pointer(pointer));
// }
// else
// {
// geometry_hierarchy_stream stream{ pointer };
// const u32 lod_count{ stream.lod_count() };
// u32 id_index{ 0 };
// for (u32 lod{ 0 }; lod < lod_count; ++lod)
// {
// for (u32 i{ 0 }; i < stream.lod_offsets()[lod].count; ++i)
// {
// graphics::remove_submesh(stream.gpu_ids()[id_index++]);
// }
// }
//
// free(pointer);
// }
//
// geometry_hierarchies.remove(id);
//}
/**
* @brief 创建材质资源。
* @param data 材质初始化数据。
* @return 材质资源 ID。
*/
//id::id_type
//create_material_resource(const void *const data)
//{
// assert(data);
// return graphics::add_material(*(const graphics::material_init_info *const)data);
//}
} // namespace
/**
* @brief 销毁材质资源。
* @param id 材质资源 ID。
*/
//void
//destory_material_resource(id::id_type id)
//{
// graphics::remove_material(id);
//}
/**
* @brief 统一资源创建入口。
* @param data 资源二进制数据。
* @param type 资源类型。
* @return 资源 ID。
*/
//id::id_type
//create_resource(const void *const data, asset_type::type type)
//{
// assert(data);
// id::id_type id{ id::invalid_id };
//
// switch (type)
// {
// case XEngine::content::asset_type::unknown: break;
// case XEngine::content::asset_type::animation: break;
// case XEngine::content::asset_type::audio: break;
// case XEngine::content::asset_type::material: id = create_material_resource(data); break;
// case XEngine::content::asset_type::mesh: id = create_geometry_resource(data); break;
// case XEngine::content::asset_type::skeleton: break;
// case XEngine::content::asset_type::texture: break;
// }
//
// assert(id::is_valid(id));
// return id;
//
//}
/**
* @brief 统一资源销毁入口。
* @param id 资源 ID。
* @param type 资源类型。
*/
//void
//destroy_resource(id::id_type id, asset_type::type type)
//{
// assert(id::is_valid(id));
// switch (type)
// {
// case XEngine::content::asset_type::unknown: break;
// case XEngine::content::asset_type::animation: break;
// case XEngine::content::asset_type::audio: break;
// case XEngine::content::asset_type::material: destory_material_resource(id); break;
// case XEngine::content::asset_type::mesh: destory_geometry_resource(id); break;
// case XEngine::content::asset_type::skeleton: break;
// case XEngine::content::asset_type::texture: break;
// default:
// assert(false);
// break;
// }
//}
/**
* @brief 注册着色器组并复制其二进制数据。
* @param shaders 着色器数组。
* @param num_shaders 着色器数量。
* @param keys 查询键数组。
* @return 着色器组 ID。
*/
id::id_type
add_shader_group(const u8 *const * shaders, u32 num_shaders, const u32 *const keys)
{
assert(shaders && num_shaders && keys);
noexcept_map group;
for (u32 i{ 0 }; i < num_shaders; ++i)
{
assert(shaders[i]);
const compiled_shader_ptr shader_ptr{ (const compiled_shader_ptr)shaders[i] };
const u64 size{ shader_ptr->buffer_size()};
std::unique_ptr<u8[]> shader{ std::make_unique<u8[]>(size) };
memcpy(shader.get(), shaders[i], size);
group.map[keys[i]] = std::move(shader);
}
std::lock_guard lock{ shader_mutex };
return shader_groups.add(std::move(group));
}
/**
* @brief 删除着色器组。
* @param id 着色器组 ID。
*/
void
remove_shader_group(id::id_type id)
{
std::lock_guard lock{ shader_mutex };
assert(id::is_valid(id));
shader_groups[id].map.clear();
shader_groups.remove(id);
}
/**
* @brief 在着色器组内按键查找着色器。
* @param id 着色器组 ID。
* @param shader_key 查询键。
* @return 命中时返回着色器指针。
*/
compiled_shader_ptr
get_shader(id::id_type id, u32 shader_key)
{
std::lock_guard lock{ shader_mutex };
assert(id::is_valid(id));
for (const auto& [key, value] : shader_groups[id].map)
{
if (key == shader_key)
{
return (const compiled_shader_ptr)value.get();
}
}
assert(false);
return nullptr;
}
/**
* @brief 获取几何资源包含的全部子网格 GPU ID。
* @param geometry_content_id 几何内容资源 ID。
* @param id_count 输出数组长度。
* @param gpu_ids 输出数组。
*/
void
get_submesh_gpu_id(id::id_type geometry_content_id, u32 id_count, id::id_type *const gpu_ids)
{
std::lock_guard lock{ geometry_mutex };
u8 *const pointer{ geometry_hierarchies[geometry_content_id] };
if ((uintptr_t)pointer & single_mesh_marker)
{
assert(id_count == 1);
*gpu_ids = gpu_id_from_fake_pointer(pointer);
}
else
{
geometry_hierarchy_stream stream{ pointer };
assert([&]() {
const u32 lod_count{ stream.lod_count() };
const lod_offset lod_offset{ stream.lod_offsets()[lod_count - 1] };
const u32 gpu_id_count{ (u32)lod_offset.offset + (u32)lod_offset.count };
return gpu_id_count == id_count;
}());
memcpy(gpu_ids, stream.gpu_ids(), sizeof(id::id_type) * id_count);
}
}
/**
* @brief 按阈值查询各几何实例使用的 LOD 偏移。
* @param geometry_ids 几何资源 ID 数组。
* @param thresholds 每个实例的阈值数组。
* @param id_count 查询数量。
* @param offsets 输出 LOD 偏移数组。
*/
void
get_lod_offset(const id::id_type *const geometry_ids, const f32 *const thresholds, u32 id_count, utl::vector<lod_offset>& offsets)
{
assert(geometry_ids && thresholds && id_count);
assert(offsets.empty());
std::lock_guard lock{ geometry_mutex };
for (u32 i{ 0 }; i < id_count; ++i)
{
u8 *const pointer{ geometry_hierarchies[geometry_ids[i]] };
if ((uintptr_t)pointer & single_mesh_marker)
{
assert(id_count == 1);
offsets.emplace_back(lod_offset{ 0,1 });
}
else
{
geometry_hierarchy_stream stream{ pointer };
const u32 lod{ stream.lod_from_threshold(thresholds[i]) };
offsets.emplace_back(stream.lod_offsets()[lod]);
}
}
}
}