ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

wgpu texture_arrays 示例深度解析:纹理绑定数组、非均匀索引与兼容性回退

wgpu texture_arrays 示例深度解析:纹理绑定数组、非均匀索引与兼容性回退 wgpu texture_arrays 示例深度解析纹理绑定数组、非均匀索引与兼容性回退【免费下载链接】wgpuA cross-platform, safe, pure-Rust graphics API.项目地址: https://gitcode.com/GitHub_Trending/wg/wgpu导读texture_arrays是 wgpu 官方功能示例集examples/features中专门演示纹理绑定数组binding array of textures用法的实例它把多张 2D 纹理和采样器打包进绑定数组在片段着色器中通过动态索引选择具体纹理并同时展示**均匀索引uniform indexing与非均匀索引non-uniform indexing**两种取色方式。阅读本文后你将掌握绑定数组在 wgpu 中的声明方式BindGroupLayoutcount字段与 WGSLbinding_array语法、相关 Feature 与 Limits 的申请逻辑、如何在运行时通过环境变量在两条代码路径间切换以及当硬件不支持非均匀索引时 wgpu 官方示例采用的自定义 uniform 回退方案。这个示例是理解 wgpu 绑定数组TEXTURE_BINDING_ARRAY最直接、可运行的开箱范例。一、示例定位与运行方式该示例位于仓库examples/features/src/texture_arrays/目录下注册在wgpu-examples这个 bin 中见 examples/features/Cargo.tomlbin 名为wgpu-examples入口为src/main.rs并由 examples/features/src/main.rs 中的ExampleDesc表登记为可执行名称texture_arrays。运行命令原文档给出的运行方式为READMEcargo run --bin wgpu-examples texture_arrays在仓库根目录执行即可。命令会启动一个 winit 窗口1024×768画面由四个等大的纯色矩形组成 2×2 网格左上红、右上绿、左下蓝、右下白。这四个色块分别来自四张独立的 1×1 纹理红、绿、蓝、白通过绑定数组索引采样得到——这正是纹理绑定数组这一特性最直观的运行效果。运行时行为开关WGPU_TEXTURE_ARRAY_STYLE示例支持通过环境变量强制指定片段着色器的索引方式mod.rs环境变量取值不区分大小写行为说明nonuniform或non_uniform强制走非均匀索引路径使用non_uniform_indexing.wgsl的non_uniform_main入口uniform强制走均匀索引回退路径使用indexing.wgsl的uniform_main入口并置uniform_workaround true未设置或其他值根据设备特性自动选择见下文特性探测与自动选择例如# 强制使用非均匀索引路径 WGPU_TEXTURE_ARRAY_STYLEnonuniform cargo run --bin wgpu-examples texture_arrays # 强制使用 uniform 回退路径 WGPU_TEXTURE_ARRAY_STYLEuniform cargo run --bin wgpu-examples texture_arrays当设置uniform时控制台会打印Using fragment entry point uniform_main设置nonuniform时打印Using fragment entry point non_uniform_main见 mod.rs。二、绑定数组特性与 Limits 申请纹理绑定数组不是默认可用能力需要在请求设备前显式声明 Feature 与 Limits。必须的 Feature示例中定义了三个相关的特征要求mod.rsfn optional_features() - wgpu::Features { wgpu::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING } fn required_features() - wgpu::Features { wgpu::Features::TEXTURE_BINDING_ARRAY }TEXTURE_BINDING_ARRAY必需允许在着色器中创建纹理绑定数组即texture_array[uniform_value]这种写法wgpu-types 中对其定义为允许用户在着色器中创建数组的资源绑定见 wgpu-types/src/features.rs 附近。示例把它作为required_features意味着如果适配器不支持该特性示例将直接无法初始化。SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING可选允许着色器用动态非均匀值对采样纹理/存储缓冲绑定数组进行索引例如texture_array[vertex_data]见 wgpu-types/src/features.rs 附近。它被放在optional_features中——设备可能不支持此时示例自动降级。必须的 Limitsfn required_limits() - wgpu::Limits { wgpu::Limits { max_binding_array_elements_per_shader_stage: 6, max_binding_array_sampler_elements_per_shader_stage: 2, ..wgpu::Limits::downlevel_defaults() } }这里申请的两个 limit 与绑定数组直接对应字段定义见 wgpu-types/src/limits.rsmax_binding_array_elements_per_shader_stage单个着色器阶段内绑定数组可容纳的元素总数。示例申请 6两组纹理绑定数组每组 2 个共 4 个纹理 2 个采样器。wgpu 文档注释指出当绑定数组被支持时所有设备实际可支持高达 500,0000 表示默认不支持。max_binding_array_sampler_elements_per_shader_stage绑定数组中采样器的数量上限申请 2采样器数组重复绑定同一个采样器两次。注释指出绑定数组受支持时设备可支持 1,000。其余限制使用downlevel_defaults()保证示例在尽可能广泛的硬件上运行框架默认的required_limits是downlevel_webgl2_defaults见 examples/features/src/framework.rs。特性探测与自动选择在init中示例根据设备实际支持的特性 环境变量覆盖决定使用哪个片段着色器入口mod.rslet fragment_entry_point match (device.features(), env_override) { (_, Some(false)) { uniform_workaround true; uniform_main } (_, Some(true)) non_uniform_main, (f, _) if f.contains(Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING) { non_uniform_main } _ { uniform_workaround true; uniform_main } };自动选择逻辑只要设备支持非均匀索引特性就使用non_uniform_main否则回退到uniform_main。环境变量优先级最高可强行覆盖自动选择——这也是测试两条路径的便捷手段。一个值得注意的实现细节由于 naga 的能力评估发生在校验validate阶段而非写入write阶段即使某个着色器模块最终未被使用只要它包含当前设备不支持的能力就无法通过创建校验。因此示例把非均匀索引着色器放进了独立的 shader modulenon_uniform_indexing.wgsl仅在确认走非均匀路径时才创建它否则复用基础模块indexing.wgsl见 mod.rs。三、资源准备四张纹理、采样器与绑定数组顶点与索引数据示例绘制的是两个并排的矩形左矩形 右矩形各由两个三角形组成每个顶点携带位置、纹理坐标和纹理数组索引_index取 0 或 1见 mod.rs。顶点布局为[Float32x2, Float32x2, Sint32]位置、UV、索引见 mod.rs。顶点着色器把这个整型索引原样透传给片段阶段并用interpolate(flat)声明为平坦插值见 indexing.wgsl确保每个像素拿到的是所属三角形对应的精确索引而非插值结果。纹理创建与数据写入四张纹理共享同一个基础描述符mod.rslet texture_descriptor wgpu::TextureDescriptor { size: wgpu::Extent3d::default(), // 1x1x1 mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::Rgba8UnormSrgb, usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, view_formats: [], label: None, };每张 1×1、格式Rgba8UnormSrgb用途为可绑定 可写。随后用queue.write_texture分别写入纯色数据红[255,0,0,255]、绿[0,255,0,255]、蓝[0,0,255,255]、白[255,255,255,255]见 mod.rs 与 mod.rs。每张纹理再通过create_view得到对应的TextureView供绑定数组引用。绑定数组的 BindGroupLayout 声明绑定数组在 API 层的核心是BindGroupLayoutEntry中的count字段设为NonZeroU32即表示该 binding 是一个绑定数组None表示单资源绑定见 mod.rslet bind_group_layout device.create_bind_group_layout(wgpu::BindGroupLayoutDescriptor { label: Some(bind group layout), entries: [ // binding 02 个过滤型 2D 浮点纹理红、绿 wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStages::FRAGMENT, ty: wgpu::BindingType::Texture { sample_type: wgpu::TextureSampleType::Float { filterable: true }, view_dimension: wgpu::TextureViewDimension::D2, multisampled: false, }, count: NonZeroU32::new(2), }, // binding 12 个过滤型 2D 浮点纹理蓝、白 wgpu::BindGroupLayoutEntry { binding: 1, // ... 同上 ... count: NonZeroU32::new(2), }, // binding 22 个采样器绑定同一个 sampler 两次 wgpu::BindGroupLayoutEntry { binding: 2, visibility: wgpu::ShaderStages::FRAGMENT, ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), count: NonZeroU32::new(2), }, ], });对应的 BindGroup 使用数组形式的资源绑定BindingResource::TextureViewArray([...])与BindingResource::SamplerArray([sampler, sampler])mod.rslet bind_group device.create_bind_group(wgpu::BindGroupDescriptor { entries: [ wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::TextureViewArray([red_texture_view, green_texture_view]), }, wgpu::BindGroupEntry { binding: 1, resource: wgpu::BindingResource::TextureViewArray([blue_texture_view, white_texture_view]), }, wgpu::BindGroupEntry { binding: 2, resource: wgpu::BindingResource::SamplerArray([sampler, sampler]), }, ], layout: bind_group_layout, label: Some(bind group), });注意采样器数组把同一个 sampler 实例绑定了两次——绑定数组并不要求每个槽位必须是独立对象这展示了重复绑定的合法用法。着色器侧的绑定数组声明在 WGSL 中绑定数组通过binding_arrayT声明并在文件开头需要enable wgpu_binding_array;语言扩展见 indexing.wgslenable wgpu_binding_array; group(0) binding(0) var texture_array_top: binding_arraytexture_2df32; group(0) binding(1) var texture_array_bottom: binding_arraytexture_2df32; group(0) binding(2) var sampler_array: binding_arraysampler;注意纹理绑定数组binding_arraytexture_2df32本身只要求TEXTURE_BINDING_ARRAY特性而binding_arraysampler这类采样器数组对应max_binding_array_sampler_elements_per_shader_stagelimit。两者结合使用正是本示例覆盖的完整场景。四、均匀索引路径indexing.wgsl 的实现原理indexing.wgsl同时包含顶点着色器vert_main和片段着色器uniform_main是默认/回退路径使用的模块。其片段着色器完整逻辑如下indexing.wgslstruct Uniforms { index: u32, } group(1) binding(0) varuniform uniforms: Uniforms; fragment fn uniform_main(fragment: FragmentInput) - location(0) vec4f32 { var outval: vec3f32; if fragment.tex_coord.y 0.5 { outval textureSampleLevel( texture_array_top[uniforms.index], sampler_array[uniforms.index], fragment.tex_coord, 0.0 ).rgb; } else { outval textureSampleLevel( texture_array_bottom[uniforms.index], sampler_array[uniforms.index], fragment.tex_coord, 0.0 ).rgb; } return vec4f32(outval.x, outval.y, outval.z, 1.0); }该路径的关键设计索引来自 uniform数组下标uniforms.index来自 group(1) 的 uniform 缓冲。uniform 值在整个绘制调用内对所有着色器调用都相同属于动态均匀dynamically uniform索引任何支持绑定数组的设备都能执行无需非均匀索引特性。动态偏移机制uniform 缓冲绑定被声明为has_dynamic_offset: true、min_binding_size: 4字节mod.rs运行时通过set_bind_group(1, self.uniform_bind_group, [offset])传入偏移。渲染阶段利用这一点在同一 pass 内连续绘制两次用不同偏移切换索引值mod.rs// uniform 回退路径分两次绘制分别指定偏移 0 和 256 rpass.set_bind_group(0, self.bind_group, []); rpass.set_bind_group(1, self.uniform_bind_group, [0]); // index 0 rpass.draw_indexed(0..6, 0, 0..1); // 左矩形 rpass.set_bind_group(1, self.uniform_bind_group, [256]); // index 1 rpass.draw_indexed(6..12, 0, 0..1); // 右矩形其中texture_index_buffer是一个 128 个 u32 的 uniform 缓冲512 字节偏移 0 处写入 0、偏移 256即第 64 个 u32处写入 1mod.rs——动态偏移 256 字节恰好让uniforms.index读到第 64 个 u32 的值 1。纹理数组分上下两组画面按tex_coord.y 0.5分成上半top与下半bottom两行。上半行两个矩形使用texture_array_top红、绿下半行使用texture_array_bottom蓝、白这样 4 个色块来自 4 张不同的纹理清晰验证了数组索引与采样结果的对应关系。五、非均匀索引路径non_uniform_indexing.wgsl 的差异non_uniform_indexing.wgslnon_uniform_indexing.wgsl与基础模块的片段着色器几乎一致唯一区别是数组下标来源fragment fn non_uniform_main(fragment: FragmentInput) - location(0) vec4f32 { var outval: vec3f32; if fragment.tex_coord.y 0.5 { outval textureSampleLevel( texture_array_top[fragment.index], // ← 非均匀索引 sampler_array[fragment.index], // ← 非均匀索引 fragment.tex_coord, 0.0 ).rgb; } else { outval textureSampleLevel( texture_array_bottom[fragment.index], sampler_array[fragment.index], fragment.tex_coord, 0.0 ).rgb; } return vec4f32(outval.x, outval.y, outval.z, 1.0); }这里下标是每个像素各不相同的fragment.index由顶点属性平坦插值而来。在同一个绘制调用内不同片元可能命中数组中不同的纹理这是典型的非均匀索引。它能够提供更强的表达力——例如按像素/顶点数据自由选择贴图而不必把每张纹理单独绑成独立 binding 或拆分绘制调用。代价是必须依赖SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING特性且渲染器实现往往需要借助 descriptor indexing 等底层机制。非均匀路径下整个场景只需一次draw_indexed(0..12, 0, 0..1)即可完成mod.rsrpass.set_bind_group(0, self.bind_group, []); rpass.set_bind_group(1, self.uniform_bind_group, [0]); rpass.draw_indexed(0..12, 0, 0..1); // 一次绘制全部 12 个索引这正是两种路径的根本差异均匀索引路径用两次绘制 动态偏移规避能力限制非均匀索引路径用一次绘制 着色器内动态索引换取简洁与灵活。六、渲染管线与集成测试渲染管线组装管线使用上述 bind group layout 组绑定数组 uniform 动态偏移组构建 pipeline layoutmod.rs片段目标格式取config.view_formats[0]顶点阶段固定使用vert_main片段阶段根据前面解析出的入口名选择uniform_main或non_uniform_main。渲染时先set_pipeline、绑定顶点/索引缓冲再按路径选择一次或两次 draw见上文。示例级 GPU 测试该示例注册了三个 GPU 测试mod.rs与两种路径一一对应TEST默认自动选择路径TEST_UNIFORM验证 uniform 回退路径TEST_NON_UNIFORM显式启用SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING验证非均匀路径。三者均以 screenshot.png 作为参考图1024×768使用Mean(0.0001)的像素均值比较容差并开启GPU_BASED_VALIDATION同时针对 MoltenVKmacOS Vulkan 转译层标记了已知失败用例验证错误为 shader library 编译失败。这些测试被汇总进 examples/features/src/lib.rs 的all_tests()列表与其它示例测试一起由wgpu_test::gpu_test_main!统一调度执行——意味着示例输出不仅是人工可看的也是自动化回归测试的基准。七、实战要点总结关注点结论运行命令cargo run --bin wgpu-examples texture_arrays仓库根目录下执行强制路径切换WGPU_TEXTURE_ARRAY_STYLEnonuniform/uniform不区分大小写必需特性TEXTURE_BINDING_ARRAY可选特性SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING不支持时自动回退必需 Limitsmax_binding_array_elements_per_shader_stage ≥ 6、max_binding_array_sampler_elements_per_shader_stage ≥ 2API 侧数组声明BindGroupLayoutEntry 的count: NonZeroU32资源用TextureViewArray/SamplerArray着色器侧数组声明enable wgpu_binding_array;binding_arraytexture_2df32/binding_arraysampler均匀索引下标来自 uniform动态偏移切换一次绑定、分多次 draw非均匀索引下标来自逐顶点/逐像素数据单次 draw需额外特性支持如果想在自己的 wgpu 工程中复现该能力可直接参考 mod.rs 的完整实现从required_features/required_limits声明、绑定数组 layout 与 bind group 构造到双着色器模块的运行时选择全部代码均已开源可读配合环境变量开关与三个 GPU 测试是学习与验证 wgpu 绑定数组语义的可靠起点。【免费下载链接】wgpuA cross-platform, safe, pure-Rust graphics API.项目地址: https://gitcode.com/GitHub_Trending/wg/wgpu创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表