1. 概述virglrenderer 的tests/目录包含的不是与 vtest_server 配合使用的客户端测试而是直接针对 virglrenderer 库 API 的单元测试集合。这些测试通过直接调用libvirglrenderer的 API 来验证各种功能使用 Check 框架进行测试管理。1.1 测试架构特点直接API测试直接调用virgl_renderer_*函数不通过socket通信单元测试框架使用Check测试框架进行测试管理内存测试在进程内存中进行渲染测试不需要外部服务器功能验证专注于验证 virglrenderer 核心功能的正确性2. 目录结构分析tests/ ├── large_shader.h # 大型着色器测试数据 ├── meson.build # 构建配置文件 ├── test_virgl_cmd.c # 渲染命令测试 ├── test_virgl_fence.c # 围栏同步测试 ├── test_virgl_init.c # 初始化和基础功能测试 ├── test_virgl_resource.c # 资源管理测试 ├── test_virgl_strbuf.c # 字符串缓冲区测试 ├── test_virgl_transfer.c # 数据传输测试 ├── testvirgl.c # 测试工具函数实现 ├── testvirgl.h # 测试工具函数头文件 ├── testvirgl_encode.c # 命令编码函数实现 ├── testvirgl_encode.h # 命令编码函数头文件 ├── test_fuzzer_formats.c # 格式模糊测试 ├── valgrind.suppressions # Valgrind内存检查配置 └── fuzzer/ # 模糊测试相关文件 ├── meson.build ├── virgl_drm_fuzzer.c # DRM接口模糊测试 └── virgl_fuzzer.c # 通用模糊测试3. 核心测试组件详解3.1 测试基础设施 (testvirgl.h/c)核心数据结构// 命令缓冲区结构structvirgl_cmd_buf{unsignedcdw;// 当前命令字数uint32_t*buf;// 命令缓冲区};// 虚拟渲染上下文structvirgl_context{void(*flush)(structvirgl_context*ctx);// 刷新函数structvirgl_cmd_buf*cbuf;// 命令缓冲区intctx_id;// 上下文ID};// 虚拟资源结构structvirgl_resource{structpipe_resourcebase;// 基础资源信息uint32_thandle;// 资源句柄structiovec*iovs;// I/O向量数组intniovs;// I/O向量数量};主要工具函数// 资源初始化函数voidtestvirgl_init_simple_buffer(structvirgl_renderer_resource_create_args*res,inthandle);voidtestvirgl_init_simple_2d_resource(structvirgl_renderer_resource_create_args*res,inthandle);// 上下文管理inttestvirgl_init_single_ctx(void);voidtestvirgl_fini_single_ctx(void);// 命令缓冲区管理inttestvirgl_init_ctx_cmdbuf(structvirgl_context*ctx);inttestvirgl_ctx_send_cmdbuf(structvirgl_context*ctx);voidtestvirgl_fini_ctx_cmdbuf(structvirgl_context*ctx);// 资源创建工具inttestvirgl_create_backed_simple_2d_res(structvirgl_resource*res,inthandle,intw,inth);inttestvirgl_create_backed_simple_buffer(structvirgl_resource*res,inthandle,intsize,intbind);3.2 命令编码模块 (testvirgl_encode.h/c)这个模块提供了将Gallium管道状态对象编码为virgl命令的功能状态对象编码// 混合状态编码intvirgl_encode_blend_state(structvirgl_context*ctx,uint32_thandle,conststructpipe_blend_state*blend_state);// 深度模板状态编码intvirgl_encode_dsa_state(structvirgl_context*ctx,uint32_thandle,conststructpipe_depth_stencil_alpha_state*dsa_state);// 光栅化状态编码intvirgl_encode_rasterizer_state(structvirgl_context*ctx,uint32_thandle,conststructpipe_rasterizer_state*state);// 着色器编码intvirgl_encode_shader_state(structvirgl_context*ctx,uint32_thandle,uint32_ttype,conststructtgsi_token*tokens,uint32_tso_info);渲染命令编码// 清屏命令intvirgl_encode_clear(structvirgl_context*ctx,unsignedbuffers,constunionpipe_color_union*color,doubledepth,unsignedstencil);// 绘制命令intvirgl_encode_draw_vbo(structvirgl_context*ctx,conststructpipe_draw_info*info,conststructpipe_draw_indirect_info*indirect,conststructpipe_draw_start_count_bias*draw);// 资源操作intvirgl_encode_resource_copy_region(structvirgl_context*ctx,structvirgl_resource*dst_res,unsigneddst_level,unsigneddstx,unsigneddsty,unsigneddstz,structvirgl_resource*src_res,unsignedsrc_level,conststructpipe_box*src_box);4. 主要测试模块功能分析4.1 初始化测试 (test_virgl_init.c)这是最基础的测试模块验证virglrenderer的初始化和清理功能主要测试用例// 测试无回调函数的初始化应该失败START_TEST(virgl_init_no_cbs){intretvirgl_renderer_init(mystruct,0,NULL);ck_assert_int_eq(ret,-1);// 期望失败}END_TEST// 测试无用户数据的初始化应该失败START_TEST(virgl_init_no_cookie){intretvirgl_renderer_init(NULL,0,test_cbs);ck_assert_int_eq(ret,-1);// 期望失败}END_TEST// 测试版本不匹配应该失败START_TEST(virgl_init_wrong_cbs_version){structvirgl_renderer_callbackstestcbs;testcbs.versionVIRGL_RENDERER_CALLBACKS_VERSION1;intretvirgl_renderer_init(mystruct,0,testcbs);ck_assert_int_eq(ret,-1);// 期望失败}END_TEST测试覆盖范围✅ 参数验证测试✅ 回调函数版本验证✅ 重复初始化检测✅ 多实例初始化测试✅ 正常初始化和清理流程4.2 渲染命令测试 (test_virgl_cmd.c)这是最复杂的测试模块包含1952行代码测试各种渲染操作对象ID重叠测试START_TEST(virgl_test_overlap_obj_id){structvirgl_contextctx;intctx_handle1;// 创建混合状态对象structpipe_blend_stateblend;memset(blend,0,sizeof(blend));blend.rt[0].colormaskPIPE_MASK_RGBA;virgl_encode_blend_state(ctx,ctx_handle,blend);// 创建同名的深度模板状态对象测试ID冲突处理structpipe_depth_stencil_alpha_statedsa;memset(dsa,0,sizeof(dsa));dsa.depth.writemask1;dsa.depth.funcPIPE_FUNC_LESS;virgl_encode_dsa_state(ctx,ctx_handle,dsa);// 相同handle}END_TEST清屏和传输测试START_TEST(virgl_test_clear){structvirgl_contextctx;structvirgl_resourceres;unionpipe_color_union color;// 创建2D资源testvirgl_create_backed_simple_2d_res(res,1,50,50);virgl_renderer_ctx_attach_resource(ctx.ctx_id,res.handle);// 创建渲染表面structvirgl_surfacesurf;surf.base.formatPIPE_FORMAT_B8G8R8X8_UNORM;// 执行清屏操作color.ui[0]0xff00ff00;// 绿色virgl_encode_clear(ctx,PIPE_CLEAR_COLOR0,color,0.0,0);// 验证清屏结果structvirgl_boxbox{0,50,0,50,0,1};uint32_t*ptrmalloc(50*50*4);testvirgl_transfer_from_host(res,box,ptr,50*4,0);// 检查像素颜色for(inti0;i50*50;i){ck_assert_int_eq(ptr[i],test_green);}}END_TEST复杂渲染测试Blit操作测试纹理间复制几何着色器测试复杂着色器渲染变换反馈测试GPU数据回读多重采样测试抗锯齿渲染视口状态测试视口变换采样器视图测试纹理采样4.3 资源管理测试 (test_virgl_resource.c)专注于测试各种资源的创建、管理和销毁资源创建测试START_TEST(virgl_test_resource_create){structvirgl_renderer_resource_create_argsres;// 测试1D纹理创建testvirgl_init_simple_1d_resource(res,1);intretvirgl_renderer_resource_create(res,NULL,0);ck_assert_int_eq(ret,0);// 测试2D纹理创建testvirgl_init_simple_2d_resource(res,2);retvirgl_renderer_resource_create(res,NULL,0);ck_assert_int_eq(ret,0);// 测试缓冲区创建testvirgl_init_simple_buffer(res,3);retvirgl_renderer_resource_create(res,NULL,0);ck_assert_int_eq(ret,0);}END_TEST资源绑定和映射测试START_TEST(virgl_test_resource_attach_backing){structvirgl_resourceres;// 创建带backing store的资源testvirgl_create_backed_simple_2d_res(res,1,256,256);// 测试资源附加到上下文virgl_renderer_ctx_attach_resource(1,res.handle);// 测试资源分离virgl_renderer_ctx_detach_resource(1,res.handle);}END_TEST4.4 数据传输测试 (test_virgl_transfer.c)测试主机和GPU之间的数据传输传输功能测试START_TEST(virgl_test_transfer_read_write){structvirgl_resourceres;structvirgl_boxbox{0,256,0,256,0,1};// 创建测试资源testvirgl_create_backed_simple_2d_res(res,1,256,256);// 准备测试数据uint32_t*test_datamalloc(256*256*4);for(inti0;i256*256;i){test_data[i]0xAABBCCDD;}// 写入数据到GPUtestvirgl_transfer_to_host(res,box,test_data,256*4,0);// 从GPU读取数据uint32_t*readbackmalloc(256*256*4);testvirgl_transfer_from_host(res,box,readback,256*4,0);// 验证数据完整性for(inti0;i256*256;i){ck_assert_int_eq(readback[i],test_data[i]);}}END_TEST4.5 围栏同步测试 (test_virgl_fence.c)测试GPU和CPU之间的同步机制围栏创建和等待测试START_TEST(virgl_test_fence_basic){/* 见 tests/test_virgl_fence.c提交 fence 后 poll再取回最后完成的 fence 值 */uint32_ttarget_seqno1;testvirgl_reset_fence();/* 提交 fence参数seqno, ctx_id0 */virgl_renderer_create_fence(target_seqno,0);/* 轮询以触发 fence 回调 */virgl_renderer_poll();/* 验证最后完成的 fence 值 */ck_assert_int_eq(testvirgl_get_last_fence(),target_seqno);}END_TEST4.6 字符串缓冲区测试 (test_virgl_strbuf.c)测试内部字符串缓冲区实现缓冲区操作测试START_TEST(virgl_test_strbuf_basic){/* 真实 API 在 src/vrend/vrend_strbuf.h栈上结构 alloc/append/free直接访问 .buf */structvrend_strbufsb;strbuf_alloc(sb,1024);// 初始化并预分配不是 createstrbuf_append(sb,Hello);strbuf_append(sb, );strbuf_append(sb,World);// 直接访问缓冲区 sb.buf无 get_str 函数ck_assert_str_eq(sb.buf,Hello World);strbuf_free(sb);// 不是 destroy}END_TEST5. 模糊测试模块 (fuzzer/)5.1 通用模糊测试 (virgl_fuzzer.c)使用libFuzzer框架进行随机输入测试intLLVMFuzzerTestOneInput(constuint8_t*data,size_tsize){staticbool initializedfalse;if(!initialized){// 初始化渲染器virgl_renderer_init(cookie,0,fuzzer_cbs);virgl_renderer_context_create(ctx_id,strlen(name),name);initializedtrue;}if(size8){// 创建随机资源create_resource_from_fuzzer_data(data,ctx_id);// 提交随机命令size_tcmd_sizesize-8;if(cmd_size0){virgl_renderer_submit_cmd((void*)(data8),ctx_id,cmd_size/sizeof(uint32_t));}}return0;}5.2 DRM模糊测试 (virgl_drm_fuzzer.c)专门针对DRM接口的模糊测试测试与内核DRM子系统的交互。6. 测试框架集成6.1 构建系统 (meson.build)check_dep dependency(check) # 测试库 libvrtest_sources [ testvirgl.c, testvirgl.h, testvirgl_encode.c, testvirgl_encode.h, ] libvrtest static_library( vrtest, libvrtest_sources, dependencies : [libvirgl_dep, gallium_dep, check_dep] ) # 测试程序 tests [ [test_virgl_init, test_virgl_init.c], [test_virgl_cmd, test_virgl_cmd.c], [test_virgl_resource, test_virgl_resource.c], [test_virgl_transfer, test_virgl_transfer.c], [test_virgl_fence, test_virgl_fence.c], [test_virgl_strbuf, test_virgl_strbuf.c], ]6.2 测试运行# 编译测试meson compile-Cbuild# 运行所有测试mesontest-Cbuild# 运行特定测试build/tests/test_virgl_init# 内存检查valgrind--suppressionstests/valgrind.suppressions\build/tests/test_virgl_cmd7. 测试数据和配置7.1 大型着色器测试 (large_shader.h)包含复杂着色器的测试数据// 预定义的大型顶点着色器staticconstcharlarge_vertex_shader[]{/* 复杂的TGSI着色器字节码 */};// 预定义的大型片段着色器staticconstcharlarge_fragment_shader[]{/* 复杂的TGSI着色器字节码 */};7.2 Valgrind配置 (valgrind.suppressions)内存检查工具的抑制配置# OpenGL驱动相关的已知问题 { mesa_dri_suppression Memcheck:Leak ... obj:*/dri/*_dri.so } # 系统库相关抑制 { glib_suppression Memcheck:Leak ... obj:*/libglib-2.0.so* }8. 运行和调试指南9.1 基本测试运行# 快速测试cdbuildmaketest# 详细输出./tests/test_virgl_init ./tests/test_virgl_cmd ./tests/test_virgl_resource9.2 调试特定测试# 使用GDB调试gdb ./tests/test_virgl_cmd(gdb)run(gdb)bt# 运行特定测试用例CK_RUN_CASEvirgl_test_clear./tests/test_virgl_cmd# 内存泄漏检测valgrind --leak-checkfull ./tests/test_virgl_cmd9.3 性能分析# CPU性能分析perf record ./tests/test_virgl_cmd perf report# GPU性能分析需要GPU工具支持nvidia-nsight ./tests/test_virgl_cmd# NVIDIAradeon_profile ./tests/test_virgl_cmd# AMD9. 与vtest_server的区别注这里的tests/是进程内直连的单元测试与 vtest_serverC/S 架构、render_server 属于不同的东西三者对比见附录 D.3。特性Tests目录VTest Server测试方式直接API调用Socket通信协议运行环境单进程内存客户端-服务器测试目标API功能验证协议兼容性隔离性无进程隔离完整进程隔离适用场景开发阶段验证集成测试复杂度简单直接需要协议实现10. 小结virglrenderer 的tests/是直连 libvirglrenderer 的单元测试套件Check 框架 Valgrind fuzzer覆盖初始化、资源、命令、传输、fence、strbuf 等。开发新功能 / 修 bug 时应配套加测试。它与需要 socket 的 vtest_server 是两回事。