昌平区事业单位公共知识培训网站网站建设需要ui吗

张小明 2025/12/29 22:33:42
昌平区事业单位公共知识培训网站,网站建设需要ui吗,交流建筑的网站,天津高端网站建设企业上一篇#xff1a;从磁盘加载纹理 | 下一篇#xff1a;材质系统 | 返回目录 #x1f4da; 快速导航 #x1f4cb; 目录 引言学习目标系统架构概览哈希表容器实现纹理系统设计引用计数机制纹理获取与释放自动释放特性默认纹理管理系统集成着色器重命名使用示例常见问题练习…上一篇从磁盘加载纹理 | 下一篇材质系统 | 返回目录 快速导航 目录引言学习目标系统架构概览哈希表容器实现纹理系统设计引用计数机制纹理获取与释放自动释放特性默认纹理管理系统集成着色器重命名使用示例常见问题练习与挑战下一步 引言在上一个教程中我们实现了从磁盘加载纹理的基本功能。但是当前的实现存在几个问题内存管理混乱- 不清楚何时应该释放纹理重复加载- 相同的纹理可能被加载多次手动管理- 需要手动调用load_texture和destroy_texture无资源追踪- 不知道有哪些纹理被加载了这些问题在大型游戏中会导致严重的内存泄漏和性能问题。我们需要一个纹理系统来统一管理所有纹理资源。本教程将实现一个完整的纹理系统包括哈希表容器用于快速查找引用计数自动管理生命周期纹理缓存避免重复加载自动释放机制 学习目标目标描述 理解资源管理学习游戏引擎中的资源管理模式 实现哈希表创建高效的字符串到数据的映射 引用计数掌握引用计数的原理和实现 纹理缓存避免重复加载相同资源 自动释放实现智能的资源生命周期管理系统架构概览让我们先看看新的纹理系统架构渲染器纹理系统应用层acquire/releaselookupallocatecreate/destroyRenderer FrontendVulkan BackendTexture SystemHash Table纹理池游戏代码旧架构 vs 新架构旧架构手动管理 ┌─────────────────────────────────────┐ │ Game Code │ │ texture my_tex; │ │ load_texture(foo, my_tex); │ │ // 使用纹理 │ │ destroy_texture(my_tex); │ └─────────────────────────────────────┘ 问题 - 手动管理生命周期 - 可能重复加载 - 容易内存泄漏 新架构系统管理 ┌─────────────────────────────────────┐ │ Game Code │ │ texture* my_tex │ │ texture_system_acquire(foo); │ │ // 使用纹理 │ │ texture_system_release(foo); │ └─────────────────────────────────────┘ 优点 ✓ 自动缓存 ✓ 引用计数 ✓ 自动释放 ✓ 统一管理哈希表容器实现纹理系统需要快速根据名称查找纹理。我们实现一个简单的哈希表。哈希表结构设计engine/src/containers/hashtable.h#pragmaonce#includedefines.h/** * brief 简单的哈希表实现。 * * 对于非指针类型表保存值的副本。 * 对于指针类型使用_ptr系列函数。 * 表不拥有指针的内存需要外部管理。 */typedefstructhashtable{u64 element_size;// 每个元素的大小字节u32 element_count;// 最大元素数量不可调整b8 is_pointer_type;// 是否存储指针类型void*memory;// 内存块}hashtable;哈希函数使用简单的字符串哈希算法engine/src/containers/hashtable.c#includehashtable.h#includecore/kmemory.h#includecore/logger.h/** * brief 计算字符串的哈希值 * param name 要哈希的字符串 * param element_count 元素总数用于取模 * return 哈希值0到element_count-1 */u64hash_name(constchar*name,u32 element_count){// 使用素数作为乘数减少哈希冲突staticconstu64 multiplier97;unsignedconstchar*us;u64 hash0;// 遍历字符串的每个字符for(us(unsignedconstchar*)name;*us;us){hashhash*multiplier*us;}// 对表大小取模确保索引在范围内hash%element_count;returnhash;}哈希算法示例字符串 cobblestone 的哈希计算 multiplier 97 hash 0 hash 0 * 97 c(99) 99 hash 99 * 97 o(111) 9714 hash 9714 * 97 b(98) 942356 ... 最终 hash 某个大数 hash % element_count 索引位置注意这是一个简单的哈希函数没有处理碰撞。在production环境中应该使用更健壮的哈希算法如MurmurHash、xxHash并处理碰撞链地址法或开放寻址法。哈希表创建/** * brief 创建哈希表 * param element_size 元素大小字节 * param element_count 最大元素数 * param memory 预分配的内存块 * param is_pointer_type 是否存储指针 * param out_hashtable 输出的哈希表 */voidhashtable_create(u64 element_size,u32 element_count,void*memory,b8 is_pointer_type,hashtable*out_hashtable){if(!memory||!out_hashtable){KERROR(hashtable_create failed! memory and out_hashtable are required.);return;}if(!element_count||!element_size){KERROR(element_size and element_count must be positive non-zero.);return;}out_hashtable-memorymemory;out_hashtable-element_countelement_count;out_hashtable-element_sizeelement_size;out_hashtable-is_pointer_typeis_pointer_type;// 清零内存kzero_memory(out_hashtable-memory,element_size*element_count);}哈希表操作Set操作存储值/** * brief 在哈希表中设置值非指针类型 * param table 哈希表 * param name 键名 * param value 要存储的值 */b8hashtable_set(hashtable*table,constchar*name,void*value){if(!table||!name||!value){KERROR(hashtable_set requires table, name and value.);returnfalse;}if(table-is_pointer_type){KERROR(hashtable_set should not be used with pointer types. Use hashtable_set_ptr.);returnfalse;}// 计算哈希值u64 hashhash_name(name,table-element_count);// 复制数据到对应位置kcopy_memory(table-memory(table-element_size*hash),value,table-element_size);returntrue;}Get操作获取值/** * brief 从哈希表获取值非指针类型 * param table 哈希表 * param name 键名 * param out_value 输出值 */b8hashtable_get(hashtable*table,constchar*name,void*out_value){if(!table||!name||!out_value){KWARN(hashtable_get requires table, name and out_value.);returnfalse;}if(table-is_pointer_type){KERROR(hashtable_get should not be used with pointer types. Use hashtable_get_ptr.);returnfalse;}u64 hashhash_name(name,table-element_count);kcopy_memory(out_value,table-memory(table-element_size*hash),table-element_size);returntrue;}Fill操作填充默认值/** * brief 用指定值填充整个哈希表 * param table 哈希表 * param value 默认值 */b8hashtable_fill(hashtable*table,void*value){if(!table||!value){KWARN(hashtable_fill requires table and value.);returnfalse;}if(table-is_pointer_type){KERROR(hashtable_fill should not be used with pointer types.);returnfalse;}for(u32 i0;itable-element_count;i){kcopy_memory(table-memory(table-element_size*i),value,table-element_size);}returntrue;}哈希表内存布局hashtable结构 ┌──────────────────────────────────────┐ │ element_size sizeof(texture_ref)│ │ element_count 65536 │ │ is_pointer_type false │ │ memory ───┐ │ └──────────────────────┼───────────────┘ │ ▼ ┌──────────────────────────────┐ │ Element 0 (texture_ref) │ ├──────────────────────────────┤ │ Element 1 (texture_ref) │ ├──────────────────────────────┤ │ ... │ ├──────────────────────────────┤ │ Element 65535 │ └──────────────────────────────┘ 访问流程 name cobblestone → hash hash_name(cobblestone, 65536) 12345 → offset element_size * 12345 → memory offset 目标位置纹理系统设计现在我们可以实现纹理系统了。纹理引用结构engine/src/systems/texture_system.c/** * brief 纹理引用信息 */typedefstructtexture_reference{u64 reference_count;// 引用计数u32 handle;// 纹理数组中的索引b8 auto_release;// 是否自动释放}texture_reference;纹理系统状态typedefstructtexture_system_state{texture_system_config config;// 配置texture default_texture;// 默认纹理// 已注册纹理数组texture*registered_textures;// 哈希表用于快速查找hashtable registered_texture_table;}texture_system_state;statictexture_system_state*state_ptr0;配置结构engine/src/systems/texture_system.h#pragmaonce#includerenderer/renderer_types.inltypedefstructtexture_system_config{u32 max_texture_count;// 最大纹理数量}texture_system_config;#defineDEFAULT_TEXTURE_NAMEdefault// 系统函数b8texture_system_initialize(u64*memory_requirement,void*state,texture_system_config config);voidtexture_system_shutdown(void*state);// 纹理操作texture*texture_system_acquire(constchar*name,b8 auto_release);voidtexture_system_release(constchar*name);// 默认纹理texture*texture_system_get_default_texture();系统架构Texture System内存布局 ┌────────────────────────────────────────┐ │ texture_system_state (结构体) │ ├────────────────────────────────────────┤ │ registered_textures[65536] (数组) │ │ - texture 0 │ │ - texture 1 │ │ - ... │ │ - texture 65535 │ ├────────────────────────────────────────┤ │ hashtable memory (哈希表数据) │ │ - texture_reference[65536] │ └────────────────────────────────────────┘ 查找流程 texture_system_acquire(cobblestone) → hashtable_get(cobblestone, ref) → ref.handle 5 → return registered_textures[5]引用计数机制引用计数是自动内存管理的核心。引用计数原理引用计数生命周期 1. 首次获取 texture* t1 acquire(foo, true); → ref_count 1 → 加载纹理 2. 第二次获取 texture* t2 acquire(foo, true); → ref_count 2 → 返回已加载的纹理不重复加载 3. 第一次释放 release(foo); → ref_count 1 → 保持纹理还有引用 4. 第二次释放 release(foo); → ref_count 0 → 如果 auto_releasetrue销毁纹理引用计数图示ref_count0, handleINVALIDacquire() → ref_count1acquire() → ref_countrelease() → ref_count--release() ref_count0 auto_releaserelease() ref_count0NotLoadedLoadedInUse纹理获取与释放系统初始化b8texture_system_initialize(u64*memory_requirement,void*state,texture_system_config config){if(config.max_texture_count0){KFATAL(texture_system_initialize - config.max_texture_count must be 0.);returnfalse;}// 计算内存需求结构体 纹理数组 哈希表u64 struct_requirementsizeof(texture_system_state);u64 array_requirementsizeof(texture)*config.max_texture_count;u64 hashtable_requirementsizeof(texture_reference)*config.max_texture_count;*memory_requirementstruct_requirementarray_requirementhashtable_requirement;if(!state){returntrue;// 第一次调用只返回内存需求}state_ptrstate;state_ptr-configconfig;// 设置数组指针在状态结构之后void*array_blockstatestruct_requirement;state_ptr-registered_texturesarray_block;// 设置哈希表内存在数组之后void*hashtable_blockarray_blockarray_requirement;// 创建哈希表hashtable_create(sizeof(texture_reference),config.max_texture_count,hashtable_block,false,state_ptr-registered_texture_table);// 用无效引用填充哈希表texture_reference invalid_ref;invalid_ref.auto_releasefalse;invalid_ref.handleINVALID_ID;invalid_ref.reference_count0;hashtable_fill(state_ptr-registered_texture_table,invalid_ref);// 初始化所有纹理为无效u32 countstate_ptr-config.max_texture_count;for(u32 i0;icount;i){state_ptr-registered_textures[i].idINVALID_ID;state_ptr-registered_textures[i].generationINVALID_ID;}// 创建默认纹理create_default_textures(state_ptr);returntrue;}纹理获取Acquire/** * brief 获取纹理增加引用计数必要时加载 * param name 纹理名称 * param auto_release 引用计数归零时是否自动释放 * return 纹理指针失败返回NULL */texture*texture_system_acquire(constchar*name,b8 auto_release){// 特殊处理默认纹理if(strings_equali(name,DEFAULT_TEXTURE_NAME)){KWARN(Use texture_system_get_default_texture for default texture.);returnstate_ptr-default_texture;}texture_reference ref;if(state_ptrhashtable_get(state_ptr-registered_texture_table,name,ref)){// auto_release只能在首次加载时设置if(ref.reference_count0){ref.auto_releaseauto_release;}ref.reference_count;if(ref.handleINVALID_ID){// 纹理不存在需要加载// 1. 找到一个空闲槽位u32 countstate_ptr-config.max_texture_count;texture*t0;for(u32 i0;icount;i){if(state_ptr-registered_textures[i].idINVALID_ID){ref.handlei;tstate_ptr-registered_textures[i];break;}}// 2. 确保找到空闲槽位if(!t||ref.handleINVALID_ID){KFATAL(texture_system_acquire - No more texture slots available.);return0;}// 3. 加载纹理if(!load_texture(name,t)){KERROR(Failed to load texture %s.,name);return0;}// 4. 设置纹理IDt-idref.handle;KTRACE(Texture %s loaded, ref_count%i.,name,ref.reference_count);}else{KTRACE(Texture %s already exists, ref_count%i.,name,ref.reference_count);}// 更新哈希表hashtable_set(state_ptr-registered_texture_table,name,ref);returnstate_ptr-registered_textures[ref.handle];}KERROR(texture_system_acquire failed for %s.,name);return0;}纹理释放Release/** * brief 释放纹理减少引用计数必要时销毁 * param name 纹理名称 */voidtexture_system_release(constchar*name){// 忽略默认纹理的释放请求if(strings_equali(name,DEFAULT_TEXTURE_NAME)){return;}texture_reference ref;if(state_ptrhashtable_get(state_ptr-registered_texture_table,name,ref)){if(ref.reference_count0){KWARN(Tried to release non-existent texture: %s,name);return;}ref.reference_count--;if(ref.reference_count0ref.auto_release){// 引用计数归零且auto_releasetrue销毁纹理texture*tstate_ptr-registered_textures[ref.handle];// 销毁GPU资源renderer_destroy_texture(t);// 重置数组条目kzero_memory(t,sizeof(texture));t-idINVALID_ID;t-generationINVALID_ID;// 重置引用ref.handleINVALID_ID;ref.auto_releasefalse;KTRACE(Released texture %s. Unloaded (ref_count0, auto_releasetrue).,name);}else{KTRACE(Released texture %s, ref_count%i (auto_release%s).,name,ref.reference_count,ref.auto_release?true:false);}// 更新哈希表hashtable_set(state_ptr-registered_texture_table,name,ref);}else{KERROR(texture_system_release failed for %s.,name);}}获取与释放流程图flowchart TD A[acquire纹理] -- B{在哈希表中?} B --|否| Z[返回NULL] B --|是| C[ref_count] C -- D{handle有效?} D --|是| E[返回已存在纹理] D --|否| F[查找空闲槽位] F -- G{找到空闲?} G --|否| H[错误无空间] G --|是| I[load_texture] I -- J{加载成功?} J --|否| K[返回NULL] J --|是| L[设置handle和ID] L -- M[更新哈希表] M -- N[返回纹理指针] Release[release纹理] -- R1{在哈希表中?} R1 --|否| R2[错误日志] R1 --|是| R3[ref_count--] R3 -- R4{ref_count0br/且auto_release?} R4 --|否| R5[只更新引用计数] R4 --|是| R6[销毁纹理] R6 -- R7[重置handle] R5 -- R8[更新哈希表] R7 -- R8自动释放特性auto_release标志决定了纹理的生命周期管理策略。auto_release的两种模式模式1auto_release true自动管理// 场景临时纹理使用完即释放texture*temp_textexture_system_acquire(temporary,true);// 使用纹理...texture_system_release(temporary);// ref_count0 → 自动销毁适用场景临时纹理UI元素、特效等动态加载的资源内存紧张时需要及时释放的资源模式2auto_release false手动管理// 场景常驻纹理整个游戏期间保持加载texture*ui_textexture_system_acquire(main_ui,false);// 多次acquire和releasetexture_system_release(main_ui);// ref_count0 → 保持加载// 仍然可以使用ui_tex适用场景常驻内存的资源主UI、玩家角色等频繁使用的纹理预加载的资源auto_release对比特性auto_release trueauto_release falseref_count0时自动销毁纹理保持加载状态内存管理自动需手动调用destroy适用场景临时资源常驻资源重新acquire需要重新加载立即可用auto_release设置规则// 首次acquire时设置auto_releasetexture*t1texture_system_acquire(foo,true);// 设置为true// 后续acquire无法更改texture*t2texture_system_acquire(foo,false);// 忽略仍为true代码实现if(ref.reference_count0){ref.auto_releaseauto_release;// 只在首次加载时设置}默认纹理管理默认纹理是特殊的总是可用且不被销毁。创建默认纹理b8create_default_textures(texture_system_state*state){KTRACE(Creating default texture...);constu32 tex_dimension256;constu32 channels4;constu32 pixel_counttex_dimension*tex_dimension;u8 pixels[pixel_count*channels];kset_memory(pixels,255,sizeof(u8)*pixel_count*channels);// 创建棋盘格图案for(u64 row0;rowtex_dimension;row){for(u64 col0;coltex_dimension;col){u64 index(row*tex_dimension)col;u64 index_bppindex*channels;if(row%2){if(col%2){pixels[index_bpp0]0;pixels[index_bpp1]0;}}else{if(!(col%2)){pixels[index_bpp0]0;pixels[index_bpp1]0;}}}}renderer_create_texture(DEFAULT_TEXTURE_NAME,tex_dimension,tex_dimension,4,pixels,false,state-default_texture);// 设置generation为INVALID_ID标记为特殊纹理state-default_texture.generationINVALID_ID;returntrue;}获取默认纹理texture*texture_system_get_default_texture(){if(state_ptr){returnstate_ptr-default_texture;}KERROR(texture_system_get_default_texture called before initialization!);return0;}系统集成现在将纹理系统集成到应用程序中。应用程序集成engine/src/core/application.c#includesystems/texture_system.htypedefstructapplication_state{// ... 现有字段 ...u64 texture_system_memory_requirement;void*texture_system_state;}application_state;在application_create中初始化b8application_create(game*game_inst){// ... 现有初始化代码 ...// 初始化纹理系统texture_system_config texture_sys_config;texture_sys_config.max_texture_count65536;// 最多65536个纹理// 第一次调用获取内存需求texture_system_initialize(app_state-texture_system_memory_requirement,0,texture_sys_config);// 分配内存app_state-texture_system_statelinear_allocator_allocate(app_state-systems_allocator,app_state-texture_system_memory_requirement);// 第二次调用实际初始化if(!texture_system_initialize(app_state-texture_system_memory_requirement,app_state-texture_system_state,texture_sys_config)){KFATAL(Failed to initialize texture system.);returnfalse;}// ... 其他系统初始化 ...}在application_run关闭时b8application_run(){// ... 运行循环 ...// 关闭系统texture_system_shutdown(app_state-texture_system_state);// ... 其他系统关闭 ...}渲染器集成engine/src/renderer/renderer_frontend.c移除手动管理的代码使用纹理系统typedefstructrenderer_system_state{renderer_backend backend;mat4 projection;mat4 view;f32 near_clip;f32 far_clip;// TODO: temporary - 改为指针texture*test_diffuse;}renderer_system_state;在渲染中使用b8renderer_draw_frame(render_packet*packet){if(renderer_begin_frame(packet-delta_time)){state_ptr-backend.update_global_state(...);mat4 modelmat4_translation((vec3){0,0,0});geometry_render_data data{};data.object_id0;data.modelmodel;// 如果纹理不存在使用默认纹理if(!state_ptr-test_diffuse){state_ptr-test_diffusetexture_system_get_default_texture();}data.textures[0]state_ptr-test_diffuse;state_ptr-backend.update_object(data);// ... 结束帧 ...}}调试事件更新使用acquire/release替代手动加载b8event_on_debug_event(u16 code,void*sender,void*listener_inst,event_context data){constchar*names[3]{cobblestone,paving,paving2};statici8 choice2;// 保存旧名称constchar*old_namenames[choice];// 切换到下一个choice;choice%3;// 获取新纹理state_ptr-test_diffusetexture_system_acquire(names[choice],true);// 释放旧纹理texture_system_release(old_name);returntrue;}着色器重命名本次提交还将着色器从Object Shader重命名为Material Shader为后续的材质系统做准备。文件重命名重命名 Builtin.ObjectShader.vert.glsl → Builtin.MaterialShader.vert.glsl Builtin.ObjectShader.frag.glsl → Builtin.MaterialShader.frag.glsl vulkan_object_shader.c → vulkan_material_shader.c vulkan_object_shader.h → vulkan_material_shader.h类型重命名// 旧名称typedefstructvulkan_object_shader{...}vulkan_object_shader;voidvulkan_object_shader_create(...);voidvulkan_object_shader_use(...);// 新名称typedefstructvulkan_material_shader{...}vulkan_material_shader;voidvulkan_material_shader_create(...);voidvulkan_material_shader_use(...);为什么重命名Object Shader对象着色器 - 暗示与单个对象绑定 - 不清楚渲染什么属性 Material Shader材质着色器 ✓ 明确表示渲染材质属性 ✓ 为材质系统铺路 ✓ 更符合通用术语使用示例示例1临时纹理voidrender_explosion_effect(){// 获取爆炸特效纹理texture*explosiontexture_system_acquire(explosion,true);// 渲染爆炸render_particle_effect(explosion);// 释放纹理texture_system_release(explosion);// → ref_count0, auto_releasetrue → 自动销毁}示例2共享纹理voidsetup_ui(){// 多个UI元素共享同一个纹理texture*button_textexture_system_acquire(button,true);create_ui_button(Start,button_tex);// ref_count2create_ui_button(Options,button_tex);// ref_count3create_ui_button(Quit,button_tex);// ref_count4texture_system_release(button);// ref_count1// 纹理仍然存在因为UI按钮还在使用}voiddestroy_ui_button(ui_button*btn){texture_system_release(button);// ref_count--// 当最后一个按钮销毁时纹理也会被释放}示例3常驻纹理voidpreload_game_assets(){// 预加载常用纹理设置auto_releasefalsetexture_system_acquire(player_skin,false);texture_system_acquire(main_ui,false);texture_system_acquire(world_tileset,false);// 这些纹理会一直保持加载状态}voiduse_player_texture(){// 即使没有acquire纹理仍然可用texture*playertexture_system_acquire(player_skin,false);render_player(player);texture_system_release(player_skin);// ref_count可能为0但纹理不会被销毁auto_releasefalse}示例4纹理热重载voidreload_texture(constchar*name){// 注意当前实现不支持热重载已加载的纹理// 需要先完全释放然后重新获取texture_reference ref;hashtable_get(texture_table,name,ref);if(ref.reference_count0){KWARN(Cannot reload texture %s while in use (ref_count%i),name,ref.reference_count);return;}// 重新加载texture*ttexture_system_acquire(name,true);// ...}❓ 常见问题❓ 哈希表冲突怎么办当前实现是一个简化版本不处理哈希冲突。如果两个不同的名称哈希到同一个索引后者会覆盖前者。解决方案链地址法Chainingtypedefstructhash_entry{constchar*key;texture_reference value;structhash_entry*next;}hash_entry;开放寻址法Open Addressingu64 hashhash_name(name,count);while(table[hash].occupied!strings_equal(table[hash].key,name)){hash(hash1)%count;// 线性探测}更大的表// 使用远大于实际需求的表大小config.max_texture_count65536;// 实际只用几千个❓ 为什么不在acquire时自动设置auto_release因为首次acquire决定了资源的生命周期策略。如果允许修改texture*t1acquire(foo,false);// 期望常驻texture*t2acquire(foo,true);// 意外改为自动释放release(foo);// t1期望保持但被销毁了release(foo);// ref_count0 → 纹理被销毁// t1现在指向无效内存当前设计保证了一致性第一次acquire设定策略后续使用者必须遵守。❓ texture_system_acquire返回的指针是否安全短期内安全但有风险texture*ttexture_system_acquire(foo,true);// t指向registered_textures[handle]// 如果其他代码释放了所有引用texture_system_release(foo);// ref_count0 → 纹理被销毁// t现在是悬空指针render(t);// 未定义行为最佳实践在使用期间保持acquiretexture*tacquire(foo,true);render(t);release(foo);// 立即释放或使用generation检查u32 expected_gent-generation;render(t);if(t-generation!expected_gen){KWARN(Texture was reloaded during use!);}❓ max_texture_count能否动态调整当前实现不支持动态调整因为哈希表大小固定数组预分配需要rehash所有条目支持动态调整需要实现哈希表扩容重新分配数组rehash所有现有条目更新所有handle对于大多数游戏65536个纹理槽位足够用了。如果真的需要更多应该在初始化时设置。❓ 纹理系统的内存开销有多大以max_texture_count65536为例texture_system_state结构: ~64 bytes registered_textures数组: 65536 * sizeof(texture) ≈ 65536 * 64 4 MB hashtable数据: 65536 * sizeof(texture_reference) 65536 * 16 1 MB 总计约 5 MB不包括实际纹理数据实际GPU纹理数据会占用更多512x512 RGBA纹理 1 MB1024x1024 RGBA纹理 4 MB2048x2048 RGBA纹理 16 MB 练习与挑战练习1实现纹理使用统计添加功能来跟踪纹理使用情况typedefstructtexture_stats{u32 total_loaded;u32 total_memory_used;u32 peak_count;}texture_stats;texture_statstexture_system_get_stats();查看提示在texture_system_state中添加u32 current_loaded_count;u32 peak_loaded_count;u64 total_memory_used;在acquire时递增release时递减calculate memory from widthheight4。练习2实现哈希冲突检测添加调试功能来检测哈希冲突voidtexture_system_debug_collisions();查看提示遍历所有已加载的纹理计算它们的哈希值检查是否有不同名称映射到同一个哈希。for(i0;icount;i){if(textures[i].id!INVALID_ID){u64 hash1hash_name(textures[i].name,count);for(ji1;jcount;j){if(textures[j].id!INVALID_ID){u64 hash2hash_name(textures[j].name,count);if(hash1hash2){KWARN(Collision: %s and %s,names...);}}}}}练习3实现纹理预加载清单实现从文件加载纹理清单并预加载b8texture_system_preload_manifest(constchar*manifest_file);清单文件格式textures.manifestplayer_skin auto main_ui persistent world_tileset persistent explosion_01 auto查看提示解析文件每一行提取纹理名称和auto_release标志调用 texture_system_acquirecharline[256];while(read_line(file,line)){charname[128];charmode[32];sscanf(line,%s %s,name,mode);b8 auto_relstrings_equal(mode,auto);texture_system_acquire(name,auto_rel);} 下一步在本教程中我们实现了完整的纹理系统✅ 哈希表容器实现✅ 纹理资源管理✅ 引用计数机制✅ 自动释放特性✅ 默认纹理管理✅ 系统集成纹理系统是资源管理的基础。在下一篇教程中我们可以使用类似的模式实现其他资源系统材质系统Material System网格系统Mesh System着色器系统Shader System音频系统Audio System所有这些系统都会使用类似的引用计数和缓存机制。结语恭喜你完成了本教程纹理系统是游戏引擎中最重要的子系统之一。我们实现了一个生产级的资源管理系统包括哈希表查找、引用计数、自动释放等高级特性。虽然还有优化空间哈希冲突处理、动态扩容等但现在的实现已经足够健壮和高效。关键要点回顾哈希表提供O(1)的查找性能引用计数自动管理资源生命周期auto_release标志支持不同的使用模式统一的系统接口简化资源管理避免重复加载节省内存和加载时间资源管理是游戏引擎的核心掌握这些概念对于开发任何大型软件都非常重要。如果你有任何问题或建议欢迎在GitHub上提出issue。关注公众号获取更多引擎开发资讯觉得有帮助请作者喝杯咖啡 作者: 上手实验室 项目地址: https://github.com/travisvroman/kohi上一篇从磁盘加载纹理 | 下一篇待定
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

唐山网站定制如何免费开网店的步骤

表格数据提取难点突破:Anything-LLM解析Excel技巧 在财务、运营和科研等日常工作中,你是否曾为“从一堆Excel表格里找一个数字”而反复翻页?更别提当领导突然问:“去年华东区哪个销售员的退货率最高?”时,那…

张小明 2025/12/26 0:56:02 网站建设

网站需要怎么做的电子商务网站开发遇到的问题

每日一学:基础知识精讲ok,终于也是要写完了,真是令人激动。话不多说有请今天的主角——封装(Encapsulation),依然用邮轮运输的场景讲透核心逻辑。封装的核心:“打包 控权”其本质可以总结两个方…

张小明 2025/12/29 15:15:07 网站建设

二级网页打不开是什么原因seo权威入门教程

摘要:昨晚生产环境突发告警,某核心查询接口P99耗时直接打满。排查过程极其惊险,最后发现竟是几行“看似人畜无害”的代码惹的祸。本文不讲虚的理论,直接复盘这次事故中揪出的5个性能杀手,建议收藏自查!1. 杀…

张小明 2025/12/26 0:54:55 网站建设

北京专业网站维护公司网站建设平台的比较

01 POST篇 要在Postman中对POST请求进行压力测试,可以按照以下步骤进行操作: 打开Postman应用程序并创建一个新的请求集合(Collection)。 在请求集合中创建一个新的请求,并选择HTTP方法为POST。 在请求URL字段中输入…

张小明 2025/12/26 0:54:22 网站建设

浏览器网站免费进入城乡厅建设部网站首页

2025语音交互新标杆:Step-Audio-Chat千亿参数模型全面评测与行业变革 【免费下载链接】Step-Audio-Chat 项目地址: https://ai.gitcode.com/StepFun/Step-Audio-Chat 导语 StepFun公司推出的1300亿参数多模态语音大模型Step-Audio-Chat,通过整合…

张小明 2025/12/26 0:53:49 网站建设

架设网站flash不显示文化建设新闻

为什么90%的SEO从业者都在使用这款神器? 【免费下载链接】GM_script 我就是来分享脚本玩玩的 项目地址: https://gitcode.com/gh_mirrors/gm/GM_script 每天面对海量的关键词数据,你是否感到力不从心?在搜索引擎算法的频繁更新中&…

张小明 2025/12/26 0:52:42 网站建设