内容简介:文档列表见:【草稿】接下来的故事围绕
文档列表见: Rust 移动端跨平台复杂图形渲染项目开发系列总结(目录)
【草稿】
接下来的故事围绕 RawCommandBuffer
定义的两个核心方法展开:
bind_graphics_pipeline(&GraphicsPipeline) bind_graphics_descriptor_sets(PipelineLayout, DescriptorSet) 复制代码
函数原型:
/// Bind a graphics pipeline. /// /// # Errors /// /// This function does not return an error. Invalid usage of this function /// will result in an error on `finish`. /// /// - Command buffer must be in recording state. /// - Only queues with graphics capability support this function. fn bind_graphics_pipeline(&mut self, pipeline: &B::GraphicsPipeline); /// Takes an iterator of graphics `DescriptorSet`'s, and binds them to the command buffer. /// `first_set` is the index that the first descriptor is mapped to in the command buffer. fn bind_graphics_descriptor_sets<I, J>( &mut self, layout: &B::PipelineLayout, first_set: usize, sets: I, offsets: J, ) where I: IntoIterator, I::Item: Borrow<B::DescriptorSet>, J: IntoIterator, J::Item: Borrow<DescriptorSetOffset>; 复制代码
这两个方法涉及三个重要数据结构:GraphicsPipeline、PipelineLayout、DescriptorSet,它们的创建顺序是相反的,从后到前。下面逐一介绍。
DescriptorSet
初始化流程如下:
- 用pso::DescriptorSetLayoutBinding分别描述Shader声明的Uniform变量并组成数组,比如texture2D、sampler和UniformBlock中的每个变量。
- 传递前面的pso::DescriptorSetLayoutBinding数组到Device创建DescriptorSetLayout。
- 用pso::DescriptorRangeDesc 汇总描述 Shader声明的Set数量与所有Uniform变量并组成数组。
- 传递前面的pso::DescriptorRangeDesc数组到Device创建DescriptorPool。
- 传递前面的DescriptorSetLayout到DescriptorPool创建DescriptorSet, 此时DescriptorSet并无实际数据 。
- 通过Device写入实际数据到DescriptorSet 。
DescriptorSet初始化流程示例
假设Fragment Shader定义如下uniform变量:
layout(set = 0, binding = 0) uniform texture2D u_texture; layout(set = 0, binding = 1) uniform sampler u_sampler; layout(set = 0, binding = 2) uniform texture2D u_texture2; layout(set = 0, binding = 3) uniform sampler u_sampler2; layout(set = 0, binding = 4) uniform UBOCol { vec4 color; } color_dat; 复制代码
那么,对应的DescriptorSetLayout和DescriptorSetLayoutBinding为:
let set_layout = device .create_descriptor_set_layout( &[ pso::DescriptorSetLayoutBinding { binding: 0, ty: pso::DescriptorType::SampledImage, count: 1, stage_flags: ShaderStageFlags::FRAGMENT, }, pso::DescriptorSetLayoutBinding { binding: 1, ty: pso::DescriptorType::Sampler, count: 1, stage_flags: ShaderStageFlags::FRAGMENT, }, pso::DescriptorSetLayoutBinding { binding: 2, ty: pso::DescriptorType::SampledImage, count: 1, stage_flags: ShaderStageFlags::FRAGMENT, }, pso::DescriptorSetLayoutBinding { binding: 3, ty: pso::DescriptorType::Sampler, count: 1, stage_flags: ShaderStageFlags::FRAGMENT, }, pso::DescriptorSetLayoutBinding { binding: 4, ty: pso::DescriptorType::UniformBuffer, count: 1, stage_flags: ShaderStageFlags::FRAGMENT, }, ], &[], // Ignore immutable_samplers ) .expect("Can't create descriptor set layout"); let mut desc_pool = device .create_descriptor_pool( 1, // sets &[ pso::DescriptorRangeDesc { ty: pso::DescriptorType::SampledImage, count: 2, }, pso::DescriptorRangeDesc { ty: pso::DescriptorType::Sampler, count: 2, }, pso::DescriptorRangeDesc { ty: pso::DescriptorType::UniformBuffer, count: 1, }, ], ) .expect("Can't create descriptor pool"); // 分配资源 let desc_set/* B::DescriptorSet */ = desc_pool.allocate_set(&set_layout).unwrap(); // 写入实际数据 device.write_descriptor_sets(vec![ pso::DescriptorSetWrite { set: &desc_set, binding: 0, array_offset: 0, descriptors: Some(pso::Descriptor::Image(&image_srv, image::Layout::Undefined)), }, pso::DescriptorSetWrite { set: &desc_set, binding: 1, array_offset: 0, descriptors: Some(pso::Descriptor::Sampler(&sampler)), }, pso::DescriptorSetWrite { set: &desc_set, binding: 2, array_offset: 0, descriptors: Some(pso::Descriptor::Image(&image_srv2, image::Layout::Undefined)), }, pso::DescriptorSetWrite { set: &desc_set, binding: 3, array_offset: 0, descriptors: Some(pso::Descriptor::Sampler(&sampler2)), }, pso::DescriptorSetWrite { set: &desc_set, binding: 4, array_offset: 0, descriptors: Some(pso::Descriptor::Buffer(&uniform_buffer, Some(0)..Some(1))), }, ]); 复制代码
相关操作的函数原型
/// Create a descriptor set layout. /// /// A descriptor set layout object is defined by an array of zero or more descriptor bindings. /// Each individual descriptor binding is specified by a descriptor type, a count (array size) /// of the number of descriptors in the binding, a set of shader stages that **can** access the /// binding, and (if using immutable samplers) an array of sampler descriptors. fn create_descriptor_set_layout<I, J>( &self, bindings: I, immutable_samplers: J, ) -> Result<B::DescriptorSetLayout, OutOfMemory> where I: IntoIterator, I::Item: Borrow<pso::DescriptorSetLayoutBinding>, J: IntoIterator, J::Item: Borrow<B::Sampler>; /// Create a descriptor pool. /// /// Descriptor pools allow allocation of descriptor sets. /// The pool can't be modified directly, only through updating descriptor sets. fn create_descriptor_pool<I>(&self, max_sets: usize, descriptor_ranges: I) -> Result<B::DescriptorPool, OutOfMemory> where I: IntoIterator, I::Item: Borrow<pso::DescriptorRangeDesc>; /// Allocate a descriptor set from the pool. /// /// The descriptor set will be allocated from the pool according to the corresponding set layout. However, /// specific descriptors must still be written to the set before use using a [`DescriptorSetWrite`] or /// [`DescriptorSetCopy`]. /// /// Descriptors will become invalid once the pool is reset. Usage of invalidated descriptor sets results /// in undefined behavior. /// /// [`DescriptorSetWrite`]: struct.DescriptorSetWrite.html /// [`DescriptorSetCopy`]: struct.DescriptorSetCopy.html fn allocate_set(&mut self, layout: &B::DescriptorSetLayout) -> Result<B::DescriptorSet, AllocationError> { let mut sets = Vec::with_capacity(1); self.allocate_sets(Some(layout), &mut sets) .map(|_| sets.remove(0)) } /// Allocate one or multiple descriptor sets from the pool. /// /// The descriptor set will be allocated from the pool according to the corresponding set layout. However, /// specific descriptors must still be written to the set before use using a [`DescriptorSetWrite`] or /// [`DescriptorSetCopy`]. /// /// Each descriptor set will be allocated from the pool according to the corresponding set layout. /// Descriptors will become invalid once the pool is reset. Usage of invalidated descriptor sets results /// in undefined behavior. /// /// [`DescriptorSetWrite`]: struct.DescriptorSetWrite.html /// [`DescriptorSetCopy`]: struct.DescriptorSetCopy.html fn allocate_sets<I>(&mut self, layouts: I, sets: &mut Vec<B::DescriptorSet>) -> Result<(), AllocationError> where I: IntoIterator, I::Item: Borrow<B::DescriptorSetLayout>, { let base = sets.len(); for layout in layouts { match self.allocate_set(layout.borrow()) { Ok(set) => sets.push(set), Err(e) => { self.free_sets(sets.drain(base ..)); return Err(e) } } } Ok(()) } /// Specifying the parameters of a descriptor set write operation fn write_descriptor_sets<'a, I, J>(&self, write_iter: I) where I: IntoIterator<Item = pso::DescriptorSetWrite<'a, B, J>>, J: IntoIterator, J::Item: Borrow<pso::Descriptor<'a, B>>; 复制代码
DescriptorSet相关数据结构定义
DescriptorSetLayout定义
A descriptor set layout object is defined by an array of zero or more descriptor bindings. Each individual descriptor binding is specified by a descriptor type, a count (array size) of the number of descriptors in the binding, a set of shader stages that can access the binding, and (if using immutable samplers) an array of sampler descriptors.
DescriptorSetLayoutBinding定义
Structure specifying a descriptor set layout binding
Immutable Samplers定义
todo
DescriptorSetWrite
/// Writes the actual descriptors to be bound into a descriptor set. Should be provided /// to the `write_descriptor_sets` method of a `Device`. #[allow(missing_docs)] pub struct DescriptorSetWrite<'a, B: Backend, WI> where WI: IntoIterator, WI::Item: Borrow<Descriptor<'a, B>> { pub set: &'a B::DescriptorSet, /// *Note*: when there is more descriptors provided than /// array elements left in the specified binding starting /// at specified, offset, the updates are spilled onto /// the next binding (starting with offset 0), and so on. pub binding: DescriptorBinding, pub array_offset: DescriptorArrayIndex, pub descriptors: WI, } 复制代码
PipelineLayout
初始化流程如下:
- 由前面创建的DescriptorSetLayout + pso::ShaderStageFlags向Device申请创建PipelineLayout实例。
PipelineLayout初始化流程示例
let pipeline_layout = device .create_pipeline_layout( std::iter::once(&set_layout), &[(pso::ShaderStageFlags::VERTEX, 0..8)], ) .expect("Can't create pipeline layout"); 复制代码
相关操作的函数原型
/// Create a new pipeline layout object. /// /// # Arguments /// /// * `set_layouts` - Descriptor set layouts /// * `push_constants` - Ranges of push constants. A shader stage may only contain one push /// constant block. The length of the range indicates the number of u32 constants occupied /// by the push constant block. /// /// # PipelineLayout /// /// Access to descriptor sets from a pipeline is accomplished through a *pipeline layout*. /// Zero or more descriptor set layouts and zero or more push constant ranges are combined to /// form a pipeline layout object which describes the complete set of resources that **can** be /// accessed by a pipeline. The pipeline layout represents a sequence of descriptor sets with /// each having a specific layout. This sequence of layouts is used to determine the interface /// between shader stages and shader resources. Each pipeline is created using a pipeline layout. fn create_pipeline_layout<IS, IR>( &self, set_layouts: IS, push_constant: IR, ) -> Result<B::PipelineLayout, OutOfMemory> where IS: IntoIterator, IS::Item: Borrow<B::DescriptorSetLayout>, IR: IntoIterator, IR::Item: Borrow<(pso::ShaderStageFlags, Range<u32>)>; 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 以OpenGL/ES视角介绍gfx-hal(Vulkan) Texture接口使用
- 以OpenGL/ES视角介绍gfx-hal(Vulkan) Framebuffer接口使用
- 企业视角看攻防演练
- 另一个视角看待这次 antd
- 架构视角:文件的通用存储原理
- 许式伟:架构设计的宏观视角
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。