/** * @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> 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 geometry_hierarchies; /** * @brief 几何资源互斥锁。 */ std::mutex geometry_mutex; /** * @brief 着色器组资源池。 */ utl::free_list 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() }; 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(); // skip submesh data and goto next LOD blob.skip(blob.reader()); } 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() }; // 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(); // const u32 id_count{ blob.reader() }; // 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() }; assert(lod_count); if (lod_count > 1) return false; blob.skip(sizeof(f32)); // skip threhold const u32 submesh_count{ blob.reader() }; 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 shader{ std::make_unique(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& 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]); } } } }