mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 22:34:43 +00:00
Add DescriptorSetLayoutCreateInfo
and PipelineLayoutCreateInfo
(#1834)
* Add `DescriptorSetLayoutCreateInfo` and `PipelineLayoutCreateInfo` * DescriptorType non_exhaustive
This commit is contained in:
parent
51c5d197bf
commit
786683c2a9
@ -148,7 +148,7 @@ fn main() {
|
||||
//
|
||||
// If you want to run the pipeline on multiple different buffers, you need to create multiple
|
||||
// descriptor sets that each contain the buffer you want to run the shader on.
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[WriteDescriptorSet::buffer(0, data_buffer.clone())],
|
||||
|
@ -112,12 +112,7 @@ impl AmbientLightingSystem {
|
||||
color: [ambient_color[0], ambient_color[1], ambient_color[2], 1.0],
|
||||
};
|
||||
|
||||
let layout = self
|
||||
.pipeline
|
||||
.layout()
|
||||
.descriptor_set_layouts()
|
||||
.get(0)
|
||||
.unwrap();
|
||||
let layout = self.pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let descriptor_set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[WriteDescriptorSet::image_view(0, color_input)],
|
||||
|
@ -123,12 +123,7 @@ impl DirectionalLightingSystem {
|
||||
direction: direction.extend(0.0).into(),
|
||||
};
|
||||
|
||||
let layout = self
|
||||
.pipeline
|
||||
.layout()
|
||||
.descriptor_set_layouts()
|
||||
.get(0)
|
||||
.unwrap();
|
||||
let layout = self.pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let descriptor_set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[
|
||||
|
@ -134,12 +134,7 @@ impl PointLightingSystem {
|
||||
position: position.extend(0.0).into(),
|
||||
};
|
||||
|
||||
let layout = self
|
||||
.pipeline
|
||||
.layout()
|
||||
.descriptor_set_layouts()
|
||||
.get(0)
|
||||
.unwrap();
|
||||
let layout = self.pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let descriptor_set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[
|
||||
|
@ -17,6 +17,7 @@
|
||||
use std::mem;
|
||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
|
||||
use vulkano::descriptor_set::layout::DescriptorType;
|
||||
use vulkano::descriptor_set::{DescriptorSet, PersistentDescriptorSet, WriteDescriptorSet};
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
|
||||
@ -102,8 +103,9 @@ fn main() {
|
||||
shader.entry_point("main").unwrap(),
|
||||
&(),
|
||||
None,
|
||||
|set_descs| {
|
||||
set_descs[0].set_buffer_dynamic(0);
|
||||
|layout_create_infos| {
|
||||
let binding = layout_create_infos[0].bindings.get_mut(&0).unwrap();
|
||||
binding.descriptor_type = DescriptorType::UniformBufferDynamic;
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
@ -155,7 +157,7 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[
|
||||
|
@ -194,7 +194,7 @@ fn main() {
|
||||
.unwrap();
|
||||
let view = ImageView::new(image.clone()).unwrap();
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[WriteDescriptorSet::image_view(0, view.clone())],
|
||||
|
@ -179,7 +179,7 @@ fn main() {
|
||||
}
|
||||
});
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
|
||||
let set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
|
@ -92,7 +92,9 @@ fn main() {
|
||||
let queue = queues.next().unwrap();
|
||||
|
||||
let (mut swapchain, images) = {
|
||||
let surface_capabilities = physical_device.surface_capabilities(&surface, Default::default()).unwrap();
|
||||
let surface_capabilities = physical_device
|
||||
.surface_capabilities(&surface, Default::default())
|
||||
.unwrap();
|
||||
let image_format = Some(
|
||||
physical_device
|
||||
.surface_formats(&surface, Default::default())
|
||||
@ -279,7 +281,7 @@ fn main() {
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[WriteDescriptorSet::image_view_sampler(
|
||||
|
@ -215,7 +215,7 @@ fn main() {
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[WriteDescriptorSet::image_view_sampler(
|
||||
|
@ -145,7 +145,7 @@ void main() {
|
||||
immutable_data_buffer
|
||||
};
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[
|
||||
|
@ -218,14 +218,15 @@ fn main() {
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()).blend_alpha())
|
||||
.render_pass(subpass)
|
||||
.with_auto_layout(device.clone(), |set_descs| {
|
||||
.with_auto_layout(device.clone(), |layout_create_infos| {
|
||||
// Modify the auto-generated layout by setting an immutable sampler to
|
||||
// set 0 binding 0.
|
||||
set_descs[0].set_immutable_samplers(0, [sampler]);
|
||||
let binding = layout_create_infos[0].bindings.get_mut(&0).unwrap();
|
||||
binding.immutable_samplers = vec![sampler];
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
|
||||
// Use `image_view` instead of `image_view_sampler`, since the sampler is already in the layout.
|
||||
let set = PersistentDescriptorSet::new(
|
||||
|
@ -347,11 +347,7 @@ fn main() {
|
||||
.unwrap();
|
||||
|
||||
// Pass the two buffers to the compute shader
|
||||
let layout = compute_pipeline
|
||||
.layout()
|
||||
.descriptor_set_layouts()
|
||||
.get(0)
|
||||
.unwrap();
|
||||
let layout = compute_pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let cs_desciptor_set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[
|
||||
|
@ -97,7 +97,7 @@ impl FractalComputePipeline {
|
||||
// Resize image if needed
|
||||
let img_dims = image.image().dimensions().width_height();
|
||||
let pipeline_layout = self.pipeline.layout();
|
||||
let desc_layout = pipeline_layout.descriptor_set_layouts().get(0).unwrap();
|
||||
let desc_layout = pipeline_layout.set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
desc_layout.clone(),
|
||||
[
|
||||
|
@ -106,12 +106,7 @@ impl PixelsDrawPipeline {
|
||||
&self,
|
||||
image: Arc<dyn ImageViewAbstract>,
|
||||
) -> Arc<PersistentDescriptorSet> {
|
||||
let layout = self
|
||||
.pipeline
|
||||
.layout()
|
||||
.descriptor_set_layouts()
|
||||
.get(0)
|
||||
.unwrap();
|
||||
let layout = self.pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let sampler = Sampler::start(self.gfx_queue.device().clone())
|
||||
.filter(Filter::Linear)
|
||||
.address_mode(SamplerAddressMode::Repeat)
|
||||
|
@ -134,7 +134,7 @@ impl GameOfLifeComputePipeline {
|
||||
// Resize image if needed
|
||||
let img_dims = self.image.image().dimensions().width_height();
|
||||
let pipeline_layout = self.compute_life_pipeline.layout();
|
||||
let desc_layout = pipeline_layout.descriptor_set_layouts().get(0).unwrap();
|
||||
let desc_layout = pipeline_layout.set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
desc_layout.clone(),
|
||||
[
|
||||
|
@ -106,12 +106,7 @@ impl PixelsDrawPipeline {
|
||||
&self,
|
||||
image: Arc<dyn ImageViewAbstract>,
|
||||
) -> Arc<PersistentDescriptorSet> {
|
||||
let layout = self
|
||||
.pipeline
|
||||
.layout()
|
||||
.descriptor_set_layouts()
|
||||
.get(0)
|
||||
.unwrap();
|
||||
let layout = self.pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let sampler = Sampler::start(self.gfx_queue.device().clone())
|
||||
.filter(Filter::Nearest)
|
||||
.address_mode(SamplerAddressMode::Repeat)
|
||||
|
@ -106,7 +106,7 @@ fn main() {
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[WriteDescriptorSet::buffer(0, data_buffer.clone())],
|
||||
|
@ -210,9 +210,11 @@ fn main() {
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()).blend_alpha())
|
||||
.render_pass(subpass)
|
||||
.with_auto_layout(device.clone(), |set_descs| {
|
||||
set_descs[0].set_push_descriptor(true);
|
||||
set_descs[0].set_immutable_samplers(0, [sampler]);
|
||||
.with_auto_layout(device.clone(), |layout_create_infos| {
|
||||
let create_info = &mut layout_create_infos[0];
|
||||
let binding = create_info.bindings.get_mut(&0).unwrap();
|
||||
create_info.push_descriptor = true;
|
||||
binding.immutable_samplers = vec![sampler];
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
|
@ -13,7 +13,7 @@ use std::sync::Arc;
|
||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
|
||||
use vulkano::descriptor_set::layout::{
|
||||
DescriptorSetDesc, DescriptorSetLayout, DescriptorSetLayoutError,
|
||||
DescriptorSetLayout, DescriptorSetLayoutCreateInfo, DescriptorSetLayoutCreationError,
|
||||
};
|
||||
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
@ -27,7 +27,7 @@ use vulkano::instance::{Instance, InstanceCreateInfo};
|
||||
use vulkano::pipeline::graphics::color_blend::ColorBlendState;
|
||||
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
|
||||
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
|
||||
use vulkano::pipeline::layout::PipelineLayout;
|
||||
use vulkano::pipeline::layout::{PipelineLayout, PipelineLayoutCreateInfo};
|
||||
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
|
||||
use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass};
|
||||
use vulkano::sampler::{Filter, Sampler, SamplerAddressMode};
|
||||
@ -294,26 +294,34 @@ fn main() {
|
||||
.unwrap();
|
||||
|
||||
let pipeline_layout = {
|
||||
let mut descriptor_set_descs: Vec<_> = DescriptorSetDesc::from_requirements(
|
||||
let mut layout_create_infos: Vec<_> = DescriptorSetLayoutCreateInfo::from_requirements(
|
||||
fs.entry_point("main").unwrap().descriptor_requirements(),
|
||||
);
|
||||
|
||||
// Set 0, Binding 0
|
||||
descriptor_set_descs[0].set_variable_descriptor_count(0, 2);
|
||||
let binding = layout_create_infos[0].bindings.get_mut(&0).unwrap();
|
||||
binding.variable_descriptor_count = true;
|
||||
binding.descriptor_count = 2;
|
||||
|
||||
let descriptor_set_layouts = descriptor_set_descs
|
||||
let set_layouts = layout_create_infos
|
||||
.into_iter()
|
||||
.map(|desc| Ok(DescriptorSetLayout::new(device.clone(), desc.clone())?))
|
||||
.collect::<Result<Vec<_>, DescriptorSetLayoutError>>()
|
||||
.collect::<Result<Vec<_>, DescriptorSetLayoutCreationError>>()
|
||||
.unwrap();
|
||||
|
||||
PipelineLayout::new(
|
||||
device.clone(),
|
||||
descriptor_set_layouts,
|
||||
fs.entry_point("main")
|
||||
.unwrap()
|
||||
.push_constant_requirements()
|
||||
.cloned(),
|
||||
PipelineLayoutCreateInfo {
|
||||
set_layouts,
|
||||
push_constant_ranges: fs
|
||||
.entry_point("main")
|
||||
.unwrap()
|
||||
.push_constant_requirements()
|
||||
.cloned()
|
||||
.into_iter()
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
@ -329,7 +337,7 @@ fn main() {
|
||||
.with_pipeline_layout(device.clone(), pipeline_layout)
|
||||
.unwrap();
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new_variable(
|
||||
layout.clone(),
|
||||
2,
|
||||
|
@ -111,7 +111,7 @@ fn main() {
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[WriteDescriptorSet::buffer(0, data_buffer.clone())],
|
||||
|
@ -108,7 +108,7 @@ fn main() {
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[WriteDescriptorSet::buffer(0, data_buffer.clone())],
|
||||
|
@ -172,7 +172,7 @@ fn main() {
|
||||
data_buffer: Arc<CpuAccessibleBuffer<[u32]>>,
|
||||
parameters: shaders::ty::Parameters,
|
||||
) {
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[WriteDescriptorSet::buffer(0, data_buffer.clone())],
|
||||
|
@ -110,7 +110,7 @@ fn main() {
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[WriteDescriptorSet::buffer(0, data_buffer.clone())],
|
||||
|
@ -244,7 +244,7 @@ fn main() {
|
||||
uniform_buffer.next(uniform_data).unwrap()
|
||||
};
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)],
|
||||
|
@ -223,7 +223,7 @@ fn main() {
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::new(
|
||||
layout.clone(),
|
||||
[WriteDescriptorSet::image_view_sampler(
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
use fnv::FnvHashMap;
|
||||
use proc_macro2::TokenStream;
|
||||
use vulkano::pipeline::layout::PipelineLayoutPcRange;
|
||||
use vulkano::pipeline::layout::PushConstantRange;
|
||||
use vulkano::shader::spirv::ExecutionModel;
|
||||
use vulkano::shader::{
|
||||
DescriptorIdentifier, DescriptorRequirements, ShaderExecution, ShaderInterfaceEntry,
|
||||
@ -219,10 +219,10 @@ fn write_descriptor_requirements(
|
||||
}
|
||||
|
||||
fn write_push_constant_requirements(
|
||||
push_constant_requirements: &Option<PipelineLayoutPcRange>,
|
||||
push_constant_requirements: &Option<PushConstantRange>,
|
||||
) -> TokenStream {
|
||||
match push_constant_requirements {
|
||||
Some(PipelineLayoutPcRange {
|
||||
Some(PushConstantRange {
|
||||
offset,
|
||||
size,
|
||||
stages,
|
||||
@ -262,10 +262,10 @@ fn write_push_constant_requirements(
|
||||
};
|
||||
|
||||
quote! {
|
||||
Some(::vulkano::pipeline::layout::PipelineLayoutPcRange {
|
||||
Some(::vulkano::pipeline::layout::PushConstantRange {
|
||||
stages: #stages,
|
||||
offset: #offset,
|
||||
size: #size,
|
||||
stages: #stages,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -538,7 +538,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
|
||||
assert!(
|
||||
first_set as usize + descriptor_sets.len()
|
||||
<= pipeline_layout.descriptor_set_layouts().len(),
|
||||
<= pipeline_layout.set_layouts().len(),
|
||||
"the highest descriptor set slot being bound must be less than the number of sets in pipeline_layout"
|
||||
);
|
||||
|
||||
@ -548,7 +548,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
self.device().internal_object()
|
||||
);
|
||||
|
||||
let pipeline_set = &pipeline_layout.descriptor_set_layouts()[first_set as usize + num];
|
||||
let pipeline_set = &pipeline_layout.set_layouts()[first_set as usize + num];
|
||||
assert!(
|
||||
pipeline_set.is_compatible_with(set.as_ref().0.layout()),
|
||||
"the element of descriptor_sets being bound to slot {} is not compatible with the corresponding slot in pipeline_layout",
|
||||
@ -1916,12 +1916,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
"the khr_push_descriptor extension must be enabled on the device"
|
||||
);
|
||||
assert!(
|
||||
set_num as usize <= pipeline_layout.descriptor_set_layouts().len(),
|
||||
set_num as usize <= pipeline_layout.set_layouts().len(),
|
||||
"the descriptor set slot being bound must be less than the number of sets in pipeline_layout"
|
||||
);
|
||||
|
||||
let descriptor_writes: SmallVec<[_; 8]> = descriptor_writes.into_iter().collect();
|
||||
let descriptor_set_layout = &pipeline_layout.descriptor_set_layouts()[set_num as usize];
|
||||
let descriptor_set_layout = &pipeline_layout.set_layouts()[set_num as usize];
|
||||
|
||||
for write in &descriptor_writes {
|
||||
check_descriptor_write(write, descriptor_set_layout, 0).unwrap();
|
||||
|
@ -796,8 +796,8 @@ impl CurrentState {
|
||||
// isn't compatible with the corresponding set in the new pipeline layout.
|
||||
// If an incompatible set was found, all bound sets from that slot onwards will
|
||||
// be disturbed.
|
||||
let current_layouts = state.pipeline_layout.descriptor_set_layouts();
|
||||
let new_layouts = pipeline_layout.descriptor_set_layouts();
|
||||
let current_layouts = state.pipeline_layout.set_layouts();
|
||||
let new_layouts = pipeline_layout.set_layouts();
|
||||
let max = (current_layouts.len() as u32).min(first_set + num_descriptor_sets);
|
||||
(0..max).find(|&num| {
|
||||
let num = num as usize;
|
||||
@ -812,7 +812,7 @@ impl CurrentState {
|
||||
.retain(|&num, _| num < invalidate_from);
|
||||
state.pipeline_layout = pipeline_layout;
|
||||
} else if (first_set + num_descriptor_sets) as usize
|
||||
>= state.pipeline_layout.descriptor_set_layouts().len()
|
||||
>= state.pipeline_layout.set_layouts().len()
|
||||
{
|
||||
// New layout is a superset of the old one.
|
||||
state.pipeline_layout = pipeline_layout;
|
||||
|
@ -1697,8 +1697,8 @@ impl SyncCommandBufferBuilder {
|
||||
set_num,
|
||||
1,
|
||||
);
|
||||
let layout = state.pipeline_layout.descriptor_set_layouts()[set_num as usize].as_ref();
|
||||
debug_assert!(layout.desc().is_push_descriptor());
|
||||
let layout = state.pipeline_layout.set_layouts()[set_num as usize].as_ref();
|
||||
debug_assert!(layout.push_descriptor());
|
||||
|
||||
let set_resources = match state
|
||||
.descriptor_sets
|
||||
@ -2698,10 +2698,9 @@ impl SyncCommandBufferBuilder {
|
||||
|
||||
for ((set, binding), reqs) in descriptor_requirements {
|
||||
// TODO: Can things be refactored so that the pipeline layout isn't needed at all?
|
||||
let descriptor_type = state.pipeline_layout.descriptor_set_layouts()[set as usize]
|
||||
.descriptor(binding)
|
||||
.unwrap()
|
||||
.ty;
|
||||
let descriptor_type = state.pipeline_layout.set_layouts()[set as usize].bindings()
|
||||
[&binding]
|
||||
.descriptor_type;
|
||||
|
||||
// TODO: Maybe include this on DescriptorRequirements?
|
||||
let access = PipelineMemoryAccess {
|
||||
|
@ -488,13 +488,15 @@ mod tests {
|
||||
use crate::command_buffer::AutoCommandBufferBuilder;
|
||||
use crate::command_buffer::CommandBufferLevel;
|
||||
use crate::command_buffer::CommandBufferUsage;
|
||||
use crate::descriptor_set::layout::DescriptorDesc;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayout;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayoutBinding;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayoutCreateInfo;
|
||||
use crate::descriptor_set::layout::DescriptorType;
|
||||
use crate::descriptor_set::PersistentDescriptorSet;
|
||||
use crate::descriptor_set::WriteDescriptorSet;
|
||||
use crate::device::Device;
|
||||
use crate::pipeline::layout::PipelineLayout;
|
||||
use crate::pipeline::layout::PipelineLayoutCreateInfo;
|
||||
use crate::pipeline::PipelineBindPoint;
|
||||
use crate::sampler::Sampler;
|
||||
use crate::shader::ShaderStages;
|
||||
@ -647,18 +649,27 @@ mod tests {
|
||||
.unwrap();
|
||||
let set_layout = DescriptorSetLayout::new(
|
||||
device.clone(),
|
||||
[Some(DescriptorDesc {
|
||||
ty: DescriptorType::Sampler,
|
||||
descriptor_count: 1,
|
||||
variable_count: false,
|
||||
stages: ShaderStages::all(),
|
||||
immutable_samplers: Vec::new(),
|
||||
})],
|
||||
DescriptorSetLayoutCreateInfo {
|
||||
bindings: [(
|
||||
0,
|
||||
DescriptorSetLayoutBinding {
|
||||
stages: ShaderStages::all(),
|
||||
..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::Sampler)
|
||||
},
|
||||
)]
|
||||
.into(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let pipeline_layout = PipelineLayout::new(
|
||||
device.clone(),
|
||||
PipelineLayoutCreateInfo {
|
||||
set_layouts: [set_layout.clone(), set_layout.clone()].into(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let pipeline_layout =
|
||||
PipelineLayout::new(device.clone(), [set_layout.clone(), set_layout.clone()], [])
|
||||
.unwrap();
|
||||
|
||||
let set = PersistentDescriptorSet::new(
|
||||
set_layout.clone(),
|
||||
@ -705,11 +716,14 @@ mod tests {
|
||||
|
||||
let pipeline_layout = PipelineLayout::new(
|
||||
device.clone(),
|
||||
[
|
||||
DescriptorSetLayout::new(device.clone(), []).unwrap(),
|
||||
set_layout.clone(),
|
||||
],
|
||||
[],
|
||||
PipelineLayoutCreateInfo {
|
||||
set_layouts: [
|
||||
DescriptorSetLayout::new(device.clone(), Default::default()).unwrap(),
|
||||
set_layout.clone(),
|
||||
]
|
||||
.into(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -337,9 +337,7 @@ impl UnsafeCommandBufferBuilder {
|
||||
let dynamic_offsets: SmallVec<[u32; 32]> = dynamic_offsets.into_iter().collect();
|
||||
|
||||
let num_bindings = sets.len() as u32;
|
||||
debug_assert!(
|
||||
first_set + num_bindings <= pipeline_layout.descriptor_set_layouts().len() as u32
|
||||
);
|
||||
debug_assert!(first_set + num_bindings <= pipeline_layout.set_layouts().len() as u32);
|
||||
|
||||
fns.v1_0.cmd_bind_descriptor_sets(
|
||||
cmd,
|
||||
@ -1393,13 +1391,12 @@ impl UnsafeCommandBufferBuilder {
|
||||
let (infos, mut writes): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = descriptor_writes
|
||||
.into_iter()
|
||||
.map(|write| {
|
||||
let descriptor = pipeline_layout.descriptor_set_layouts()[set_num as usize]
|
||||
.descriptor(write.binding())
|
||||
.unwrap();
|
||||
let binding =
|
||||
&pipeline_layout.set_layouts()[set_num as usize].bindings()[&write.binding()];
|
||||
|
||||
(
|
||||
write.to_vulkan_info(descriptor.ty),
|
||||
write.to_vulkan(ash::vk::DescriptorSet::null(), descriptor.ty),
|
||||
write.to_vulkan_info(binding.descriptor_type),
|
||||
write.to_vulkan(ash::vk::DescriptorSet::null(), binding.descriptor_type),
|
||||
)
|
||||
})
|
||||
.unzip();
|
||||
|
@ -50,15 +50,13 @@ pub(in super::super) fn check_descriptor_sets_validity<'a, P: Pipeline>(
|
||||
}
|
||||
|
||||
for ((set_num, binding_num), reqs) in descriptor_requirements {
|
||||
let layout_binding = pipeline.layout().descriptor_set_layouts()[set_num as usize]
|
||||
.desc()
|
||||
.descriptor(binding_num)
|
||||
.unwrap();
|
||||
let layout_binding =
|
||||
&pipeline.layout().set_layouts()[set_num as usize].bindings()[&binding_num];
|
||||
|
||||
let check_buffer = |index: u32, buffer: &Arc<dyn BufferAccess>| Ok(());
|
||||
|
||||
let check_buffer_view = |index: u32, buffer_view: &Arc<dyn BufferViewAbstract>| {
|
||||
if layout_binding.ty == DescriptorType::StorageTexelBuffer {
|
||||
if layout_binding.descriptor_type == DescriptorType::StorageTexelBuffer {
|
||||
// VUID-vkCmdDispatch-OpTypeImage-06423
|
||||
if reqs.image_format.is_none()
|
||||
&& reqs.storage_write.contains(&index)
|
||||
@ -87,7 +85,7 @@ pub(in super::super) fn check_descriptor_sets_validity<'a, P: Pipeline>(
|
||||
return Err(InvalidDescriptorResource::StorageImageAtomicNotSupported);
|
||||
}
|
||||
|
||||
if layout_binding.ty == DescriptorType::StorageImage {
|
||||
if layout_binding.descriptor_type == DescriptorType::StorageImage {
|
||||
// VUID-vkCmdDispatch-OpTypeImage-06423
|
||||
if reqs.image_format.is_none()
|
||||
&& reqs.storage_write.contains(&index)
|
||||
|
852
vulkano/src/descriptor_set/layout.rs
Normal file
852
vulkano/src/descriptor_set/layout.rs
Normal file
@ -0,0 +1,852 @@
|
||||
// Copyright (c) 2021 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
//! Describes the layout of all descriptors within a descriptor set.
|
||||
//!
|
||||
//! When creating a new descriptor set, you must provide a *layout* object to create it from.
|
||||
|
||||
use super::pool::DescriptorsCount;
|
||||
use crate::{
|
||||
check_errors,
|
||||
device::{Device, DeviceOwned},
|
||||
sampler::Sampler,
|
||||
shader::{DescriptorRequirements, ShaderStages},
|
||||
OomError, Version, VulkanObject,
|
||||
};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
error, fmt,
|
||||
hash::{Hash, Hasher},
|
||||
mem::MaybeUninit,
|
||||
ptr,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
/// Describes to the Vulkan implementation the layout of all descriptors within a descriptor set.
|
||||
#[derive(Debug)]
|
||||
pub struct DescriptorSetLayout {
|
||||
handle: ash::vk::DescriptorSetLayout,
|
||||
device: Arc<Device>,
|
||||
|
||||
bindings: BTreeMap<u32, DescriptorSetLayoutBinding>,
|
||||
push_descriptor: bool,
|
||||
|
||||
descriptors_count: DescriptorsCount,
|
||||
}
|
||||
|
||||
impl DescriptorSetLayout {
|
||||
/// Creates a new `DescriptorSetLayout`.
|
||||
pub fn new(
|
||||
device: Arc<Device>,
|
||||
mut create_info: DescriptorSetLayoutCreateInfo,
|
||||
) -> Result<Arc<DescriptorSetLayout>, DescriptorSetLayoutCreationError> {
|
||||
let descriptors_count = Self::validate(&device, &mut create_info)?;
|
||||
let handle = unsafe { Self::create(&device, &create_info)? };
|
||||
|
||||
let DescriptorSetLayoutCreateInfo {
|
||||
bindings,
|
||||
push_descriptor,
|
||||
_ne: _,
|
||||
} = create_info;
|
||||
|
||||
Ok(Arc::new(DescriptorSetLayout {
|
||||
handle,
|
||||
device,
|
||||
|
||||
bindings,
|
||||
push_descriptor,
|
||||
|
||||
descriptors_count,
|
||||
}))
|
||||
}
|
||||
|
||||
fn validate(
|
||||
device: &Device,
|
||||
create_info: &mut DescriptorSetLayoutCreateInfo,
|
||||
) -> Result<DescriptorsCount, DescriptorSetLayoutCreationError> {
|
||||
let &mut DescriptorSetLayoutCreateInfo {
|
||||
ref bindings,
|
||||
push_descriptor,
|
||||
_ne: _,
|
||||
} = create_info;
|
||||
|
||||
let mut descriptors_count = DescriptorsCount::zero();
|
||||
|
||||
if push_descriptor {
|
||||
if !device.enabled_extensions().khr_push_descriptor {
|
||||
return Err(DescriptorSetLayoutCreationError::ExtensionNotEnabled {
|
||||
extension: "khr_push_descriptor",
|
||||
reason: "description was set to be a push descriptor",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let highest_binding_num = bindings.keys().copied().next_back();
|
||||
|
||||
for (&binding_num, binding) in bindings.iter() {
|
||||
descriptors_count.add_num(binding.descriptor_type, binding.descriptor_count);
|
||||
|
||||
if push_descriptor {
|
||||
// VUID-VkDescriptorSetLayoutCreateInfo-flags-00280
|
||||
if matches!(
|
||||
binding.descriptor_type,
|
||||
DescriptorType::StorageBufferDynamic | DescriptorType::UniformBufferDynamic
|
||||
) {
|
||||
return Err(
|
||||
DescriptorSetLayoutCreationError::PushDescriptorDescriptorTypeIncompatible {
|
||||
binding_num,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-flags-03003
|
||||
if binding.variable_descriptor_count {
|
||||
return Err(
|
||||
DescriptorSetLayoutCreationError::PushDescriptorVariableDescriptorCount {
|
||||
binding_num,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if !binding.immutable_samplers.is_empty() {
|
||||
if binding
|
||||
.immutable_samplers
|
||||
.iter()
|
||||
.any(|sampler| sampler.sampler_ycbcr_conversion().is_some())
|
||||
{
|
||||
if !matches!(
|
||||
binding.descriptor_type,
|
||||
DescriptorType::CombinedImageSampler
|
||||
) {
|
||||
return Err(
|
||||
DescriptorSetLayoutCreationError::ImmutableSamplersDescriptorTypeIncompatible {
|
||||
binding_num,
|
||||
},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if !matches!(
|
||||
binding.descriptor_type,
|
||||
DescriptorType::Sampler | DescriptorType::CombinedImageSampler
|
||||
) {
|
||||
return Err(
|
||||
DescriptorSetLayoutCreationError::ImmutableSamplersDescriptorTypeIncompatible {
|
||||
binding_num,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// VUID-VkDescriptorSetLayoutBinding-descriptorType-00282
|
||||
if binding.descriptor_count != binding.immutable_samplers.len() as u32 {
|
||||
return Err(
|
||||
DescriptorSetLayoutCreationError::ImmutableSamplersCountMismatch {
|
||||
binding_num,
|
||||
sampler_count: binding.immutable_samplers.len() as u32,
|
||||
descriptor_count: binding.descriptor_count,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// VUID-VkDescriptorSetLayoutBinding-descriptorType-01510
|
||||
// If descriptorType is VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT and descriptorCount is not 0, then stageFlags must be 0 or VK_SHADER_STAGE_FRAGMENT_BIT
|
||||
|
||||
if binding.variable_descriptor_count {
|
||||
// VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingVariableDescriptorCount-03014
|
||||
if !device
|
||||
.enabled_features()
|
||||
.descriptor_binding_variable_descriptor_count
|
||||
{
|
||||
return Err(DescriptorSetLayoutCreationError::FeatureNotEnabled {
|
||||
feature: "descriptor_binding_variable_descriptor_count",
|
||||
reason: "binding has a variable count",
|
||||
});
|
||||
}
|
||||
|
||||
// VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-pBindingFlags-03004
|
||||
if Some(binding_num) != highest_binding_num {
|
||||
return Err(
|
||||
DescriptorSetLayoutCreationError::VariableDescriptorCountBindingNotHighest {
|
||||
binding_num,
|
||||
highest_binding_num: highest_binding_num.unwrap(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-pBindingFlags-03015
|
||||
if matches!(
|
||||
binding.descriptor_type,
|
||||
DescriptorType::UniformBufferDynamic | DescriptorType::StorageBufferDynamic
|
||||
) {
|
||||
return Err(
|
||||
DescriptorSetLayoutCreationError::VariableDescriptorCountDescriptorTypeIncompatible {
|
||||
binding_num,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VUID-VkDescriptorSetLayoutCreateInfo-flags-00281
|
||||
if push_descriptor
|
||||
&& descriptors_count.total()
|
||||
> device
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_push_descriptors
|
||||
.unwrap_or(0)
|
||||
{
|
||||
return Err(
|
||||
DescriptorSetLayoutCreationError::MaxPushDescriptorsExceeded {
|
||||
provided: descriptors_count.total(),
|
||||
max_supported: device
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_push_descriptors
|
||||
.unwrap_or(0),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Ok(descriptors_count)
|
||||
}
|
||||
|
||||
unsafe fn create(
|
||||
device: &Device,
|
||||
create_info: &DescriptorSetLayoutCreateInfo,
|
||||
) -> Result<ash::vk::DescriptorSetLayout, DescriptorSetLayoutCreationError> {
|
||||
let &DescriptorSetLayoutCreateInfo {
|
||||
ref bindings,
|
||||
push_descriptor,
|
||||
_ne: _,
|
||||
} = create_info;
|
||||
|
||||
let mut bindings_vk = Vec::with_capacity(bindings.len());
|
||||
let mut binding_flags_vk = Vec::with_capacity(bindings.len());
|
||||
let mut immutable_samplers_vk: Vec<Box<[ash::vk::Sampler]>> = Vec::new(); // only to keep the arrays of handles alive
|
||||
let mut flags = ash::vk::DescriptorSetLayoutCreateFlags::empty();
|
||||
|
||||
if push_descriptor {
|
||||
flags |= ash::vk::DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR_KHR;
|
||||
}
|
||||
|
||||
for (&binding_num, binding) in bindings.iter() {
|
||||
let mut binding_flags = ash::vk::DescriptorBindingFlags::empty();
|
||||
|
||||
let p_immutable_samplers = if !binding.immutable_samplers.is_empty() {
|
||||
// VUID-VkDescriptorSetLayoutBinding-descriptorType-00282
|
||||
let sampler_handles = binding
|
||||
.immutable_samplers
|
||||
.iter()
|
||||
.map(|s| s.internal_object())
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice();
|
||||
let p_immutable_samplers = sampler_handles.as_ptr();
|
||||
immutable_samplers_vk.push(sampler_handles);
|
||||
p_immutable_samplers
|
||||
} else {
|
||||
ptr::null()
|
||||
};
|
||||
|
||||
if binding.variable_descriptor_count {
|
||||
binding_flags |= ash::vk::DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT;
|
||||
}
|
||||
|
||||
// VUID-VkDescriptorSetLayoutCreateInfo-binding-00279
|
||||
// Guaranteed by BTreeMap
|
||||
bindings_vk.push(ash::vk::DescriptorSetLayoutBinding {
|
||||
binding: binding_num,
|
||||
descriptor_type: binding.descriptor_type.into(),
|
||||
descriptor_count: binding.descriptor_count,
|
||||
stage_flags: binding.stages.into(),
|
||||
p_immutable_samplers,
|
||||
});
|
||||
binding_flags_vk.push(binding_flags);
|
||||
}
|
||||
|
||||
let mut binding_flags_create_info = if device.api_version() >= Version::V1_2
|
||||
|| device.enabled_extensions().ext_descriptor_indexing
|
||||
{
|
||||
Some(ash::vk::DescriptorSetLayoutBindingFlagsCreateInfo {
|
||||
// VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-bindingCount-03002
|
||||
binding_count: binding_flags_vk.len() as u32,
|
||||
p_binding_flags: binding_flags_vk.as_ptr(),
|
||||
..Default::default()
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut create_info = ash::vk::DescriptorSetLayoutCreateInfo {
|
||||
flags,
|
||||
binding_count: bindings_vk.len() as u32,
|
||||
p_bindings: bindings_vk.as_ptr(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if let Some(binding_flags_create_info) = binding_flags_create_info.as_mut() {
|
||||
binding_flags_create_info.p_next = create_info.p_next;
|
||||
create_info.p_next = binding_flags_create_info as *const _ as *const _;
|
||||
}
|
||||
|
||||
let handle = {
|
||||
let fns = device.fns();
|
||||
let mut output = MaybeUninit::uninit();
|
||||
check_errors(fns.v1_0.create_descriptor_set_layout(
|
||||
device.internal_object(),
|
||||
&create_info,
|
||||
ptr::null(),
|
||||
output.as_mut_ptr(),
|
||||
))
|
||||
.map_err(|e| OomError::from(e))?;
|
||||
output.assume_init()
|
||||
};
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
/// Returns the bindings of the descriptor set layout.
|
||||
#[inline]
|
||||
pub fn bindings(&self) -> &BTreeMap<u32, DescriptorSetLayoutBinding> {
|
||||
&self.bindings
|
||||
}
|
||||
|
||||
/// Returns whether the descriptor set layout is for push descriptors or regular descriptor
|
||||
/// sets.
|
||||
#[inline]
|
||||
pub fn push_descriptor(&self) -> bool {
|
||||
self.push_descriptor
|
||||
}
|
||||
|
||||
/// Returns the number of descriptors of each type.
|
||||
#[inline]
|
||||
pub fn descriptors_count(&self) -> &DescriptorsCount {
|
||||
&self.descriptors_count
|
||||
}
|
||||
|
||||
/// If the highest-numbered binding has a variable count, returns its `descriptor_count`.
|
||||
/// Otherwise returns `0`.
|
||||
#[inline]
|
||||
pub fn variable_descriptor_count(&self) -> u32 {
|
||||
self.bindings
|
||||
.values()
|
||||
.next_back()
|
||||
.map(|binding| {
|
||||
if binding.variable_descriptor_count {
|
||||
binding.descriptor_count
|
||||
} else {
|
||||
0
|
||||
}
|
||||
})
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Returns whether `self` is compatible with `other`.
|
||||
///
|
||||
/// "Compatible" in this sense is defined by the Vulkan specification under the section
|
||||
/// "Pipeline layout compatibility": either the two are the same descriptor set layout object,
|
||||
/// or they must be identically defined to the Vulkan API.
|
||||
#[inline]
|
||||
pub fn is_compatible_with(&self, other: &DescriptorSetLayout) -> bool {
|
||||
self == other
|
||||
|| (self.bindings == other.bindings && self.push_descriptor == other.push_descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DescriptorSetLayout {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let fns = self.device.fns();
|
||||
fns.v1_0.destroy_descriptor_set_layout(
|
||||
self.device.internal_object(),
|
||||
self.handle,
|
||||
ptr::null(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl VulkanObject for DescriptorSetLayout {
|
||||
type Object = ash::vk::DescriptorSetLayout;
|
||||
|
||||
#[inline]
|
||||
fn internal_object(&self) -> ash::vk::DescriptorSetLayout {
|
||||
self.handle
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl DeviceOwned for DescriptorSetLayout {
|
||||
#[inline]
|
||||
fn device(&self) -> &Arc<Device> {
|
||||
&self.device
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for DescriptorSetLayout {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.handle == other.handle && self.device() == other.device()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for DescriptorSetLayout {}
|
||||
|
||||
impl Hash for DescriptorSetLayout {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.handle.hash(state);
|
||||
self.device().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// Error related to descriptor set layout.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum DescriptorSetLayoutCreationError {
|
||||
/// Out of Memory.
|
||||
OomError(OomError),
|
||||
|
||||
ExtensionNotEnabled {
|
||||
extension: &'static str,
|
||||
reason: &'static str,
|
||||
},
|
||||
FeatureNotEnabled {
|
||||
feature: &'static str,
|
||||
reason: &'static str,
|
||||
},
|
||||
|
||||
/// A binding includes immutable samplers but their number differs from `descriptor_count`.
|
||||
ImmutableSamplersCountMismatch {
|
||||
binding_num: u32,
|
||||
sampler_count: u32,
|
||||
descriptor_count: u32,
|
||||
},
|
||||
|
||||
/// A binding includes immutable samplers but it has an incompatible `descriptor_type`.
|
||||
ImmutableSamplersDescriptorTypeIncompatible { binding_num: u32 },
|
||||
|
||||
/// More descriptors were provided in all bindings than the
|
||||
/// [`max_push_descriptors`](crate::device::Properties::max_push_descriptors) limit.
|
||||
MaxPushDescriptorsExceeded { provided: u32, max_supported: u32 },
|
||||
|
||||
/// `push_descriptor` is enabled, but a binding has an incompatible `descriptor_type`.
|
||||
PushDescriptorDescriptorTypeIncompatible { binding_num: u32 },
|
||||
|
||||
/// `push_descriptor` is enabled, but a binding has `variable_descriptor_count` enabled.
|
||||
PushDescriptorVariableDescriptorCount { binding_num: u32 },
|
||||
|
||||
/// A binding has `variable_descriptor_count` enabled, but it is not the highest-numbered
|
||||
/// binding.
|
||||
VariableDescriptorCountBindingNotHighest {
|
||||
binding_num: u32,
|
||||
highest_binding_num: u32,
|
||||
},
|
||||
|
||||
/// A binding has `variable_descriptor_count` enabled, but it has an incompatible
|
||||
/// `descriptor_type`.
|
||||
VariableDescriptorCountDescriptorTypeIncompatible { binding_num: u32 },
|
||||
}
|
||||
|
||||
impl From<OomError> for DescriptorSetLayoutCreationError {
|
||||
fn from(error: OomError) -> Self {
|
||||
Self::OomError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for DescriptorSetLayoutCreationError {}
|
||||
|
||||
impl std::fmt::Display for DescriptorSetLayoutCreationError {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
match *self {
|
||||
Self::OomError(_) => {
|
||||
write!(fmt, "out of memory")
|
||||
}
|
||||
Self::ExtensionNotEnabled { extension, reason } => write!(
|
||||
fmt,
|
||||
"the extension {} must be enabled: {}",
|
||||
extension, reason
|
||||
),
|
||||
Self::FeatureNotEnabled { feature, reason } => {
|
||||
write!(fmt, "the feature {} must be enabled: {}", feature, reason)
|
||||
}
|
||||
Self::ImmutableSamplersCountMismatch { binding_num, sampler_count, descriptor_count } => write!(
|
||||
fmt,
|
||||
"binding {} includes immutable samplers but their number ({}) differs from `descriptor_count` ({})",
|
||||
binding_num, sampler_count, descriptor_count,
|
||||
),
|
||||
Self::ImmutableSamplersDescriptorTypeIncompatible { binding_num } => write!(
|
||||
fmt,
|
||||
"binding {} includes immutable samplers but it has an incompatible `descriptor_type`",
|
||||
binding_num,
|
||||
),
|
||||
Self::MaxPushDescriptorsExceeded {
|
||||
provided,
|
||||
max_supported,
|
||||
} => write!(
|
||||
fmt,
|
||||
"more descriptors were provided in all bindings ({}) than the `max_push_descriptors` limit ({})",
|
||||
provided, max_supported,
|
||||
),
|
||||
Self::PushDescriptorDescriptorTypeIncompatible { binding_num } => write!(
|
||||
fmt,
|
||||
"`push_descriptor` is enabled, but binding {} has an incompatible `descriptor_type`",
|
||||
binding_num,
|
||||
),
|
||||
Self::PushDescriptorVariableDescriptorCount { binding_num } => write!(
|
||||
fmt,
|
||||
"`push_descriptor` is enabled, but binding {} has `variable_descriptor_count` enabled",
|
||||
binding_num,
|
||||
),
|
||||
Self::VariableDescriptorCountBindingNotHighest { binding_num, highest_binding_num } => write!(
|
||||
fmt,
|
||||
"binding {} has `variable_descriptor_count` enabled, but it is not the highest-numbered binding ({})",
|
||||
binding_num, highest_binding_num,
|
||||
),
|
||||
Self::VariableDescriptorCountDescriptorTypeIncompatible { binding_num } => write!(
|
||||
fmt,
|
||||
"binding {} has `variable_descriptor_count` enabled, but it has an incompatible `descriptor_type`",
|
||||
binding_num,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters to create a new `DescriptorSetLayout`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DescriptorSetLayoutCreateInfo {
|
||||
/// The bindings of the desriptor set layout. These are specified according to binding number.
|
||||
///
|
||||
/// It is generally advisable to keep the binding numbers low. Higher binding numbers may
|
||||
/// use more memory inside Vulkan.
|
||||
///
|
||||
/// The default value is empty.
|
||||
pub bindings: BTreeMap<u32, DescriptorSetLayoutBinding>,
|
||||
|
||||
/// Whether the descriptor set layout should be created for push descriptors.
|
||||
///
|
||||
/// If `true`, the layout can only be used for push descriptors, and if `false`, it can only
|
||||
/// be used for regular descriptor sets.
|
||||
///
|
||||
/// If set to `true`, the
|
||||
/// [`khr_push_descriptor`](crate::device::DeviceExtensions::khr_push_descriptor) extension must
|
||||
/// be enabled on the device, and there are several restrictions:
|
||||
/// - There must be no bindings with a type of [`DescriptorType::UniformBufferDynamic`]
|
||||
/// or [`DescriptorType::StorageBufferDynamic`].
|
||||
/// - There must be no bindings with `variable_descriptor_count` enabled.
|
||||
/// - The total number of descriptors across all bindings must be less than the
|
||||
/// [`max_push_descriptors`](crate::device::Properties::max_push_descriptors) limit.
|
||||
///
|
||||
/// The default value is `false`.
|
||||
pub push_descriptor: bool,
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
impl Default for DescriptorSetLayoutCreateInfo {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bindings: BTreeMap::new(),
|
||||
push_descriptor: false,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DescriptorSetLayoutCreateInfo {
|
||||
/// Builds a list of `DescriptorSetLayoutCreateInfo` from an iterator of `DescriptorRequirement`
|
||||
/// originating from a shader.
|
||||
#[inline]
|
||||
pub fn from_requirements<'a>(
|
||||
descriptor_requirements: impl IntoIterator<Item = ((u32, u32), &'a DescriptorRequirements)>,
|
||||
) -> Vec<Self> {
|
||||
let mut create_infos: Vec<Self> = Vec::new();
|
||||
|
||||
for ((set_num, binding_num), reqs) in descriptor_requirements {
|
||||
let set_num = set_num as usize;
|
||||
|
||||
if set_num >= create_infos.len() {
|
||||
create_infos.resize(set_num + 1, Self::default());
|
||||
}
|
||||
|
||||
let bindings = &mut create_infos[set_num].bindings;
|
||||
bindings.insert(binding_num, reqs.into());
|
||||
}
|
||||
|
||||
create_infos
|
||||
}
|
||||
}
|
||||
|
||||
/// A binding in a descriptor set layout.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct DescriptorSetLayoutBinding {
|
||||
/// The content and layout of each array element of a binding.
|
||||
///
|
||||
/// There is no default value.
|
||||
pub descriptor_type: DescriptorType,
|
||||
|
||||
/// How many descriptors (array elements) this binding is made of.
|
||||
///
|
||||
/// If the binding is a single element rather than an array, then you must specify `1`.
|
||||
///
|
||||
/// The default value is `1`.
|
||||
pub descriptor_count: u32,
|
||||
|
||||
/// Whether the binding has a variable number of descriptors.
|
||||
///
|
||||
/// If set to `true`, the
|
||||
/// [`descriptor_binding_variable_descriptor_count`](crate::device::Features::descriptor_binding_variable_descriptor_count)
|
||||
/// feature must be enabled. The value of `descriptor_count` specifies the maximum number of
|
||||
/// descriptors allowed.
|
||||
///
|
||||
/// There may only be one binding with a variable count in a descriptor set, and it must be the
|
||||
/// binding with the highest binding number. The `descriptor_type` must not be
|
||||
/// [`DescriptorType::UniformBufferDynamic`] or [`DescriptorType::StorageBufferDynamic`].
|
||||
///
|
||||
/// The default value is `false`.
|
||||
pub variable_descriptor_count: bool,
|
||||
|
||||
/// Which shader stages are going to access the descriptors in this binding.
|
||||
///
|
||||
/// The default value is [`ShaderStages::none()`], which must be overridden.
|
||||
pub stages: ShaderStages,
|
||||
|
||||
/// Samplers that are included as a fixed part of the descriptor set layout. Once bound, they
|
||||
/// do not need to be provided when creating a descriptor set.
|
||||
///
|
||||
/// The list must be either empty, or contain exactly `descriptor_count` samplers. It can only
|
||||
/// be non-empty if `descriptor_type` is [`DescriptorType::Sampler`] or
|
||||
/// [`DescriptorType::CombinedImageSampler`]. If any of the samplers has an attached sampler
|
||||
/// YCbCr conversion, then only [`DescriptorType::CombinedImageSampler`] is allowed.
|
||||
///
|
||||
/// The default value is empty.
|
||||
pub immutable_samplers: Vec<Arc<Sampler>>,
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
impl DescriptorSetLayoutBinding {
|
||||
/// Returns a `DescriptorSetLayoutBinding` with the given type.
|
||||
#[inline]
|
||||
pub fn descriptor_type(descriptor_type: DescriptorType) -> Self {
|
||||
Self {
|
||||
descriptor_type,
|
||||
descriptor_count: 1,
|
||||
variable_descriptor_count: false,
|
||||
stages: ShaderStages::none(),
|
||||
immutable_samplers: Vec::new(),
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether the descriptor of a pipeline layout `self` is compatible with the
|
||||
/// requirements of a shader `other`.
|
||||
#[inline]
|
||||
pub fn ensure_compatible_with_shader(
|
||||
&self,
|
||||
descriptor_requirements: &DescriptorRequirements,
|
||||
) -> Result<(), DescriptorRequirementsNotMet> {
|
||||
let DescriptorRequirements {
|
||||
descriptor_types,
|
||||
descriptor_count,
|
||||
image_format,
|
||||
image_multisampled,
|
||||
image_scalar_type,
|
||||
image_view_type,
|
||||
sampler_compare,
|
||||
sampler_no_unnormalized_coordinates,
|
||||
sampler_no_ycbcr_conversion,
|
||||
sampler_with_images,
|
||||
stages,
|
||||
storage_image_atomic,
|
||||
storage_read,
|
||||
storage_write,
|
||||
} = descriptor_requirements;
|
||||
|
||||
if !descriptor_types.contains(&self.descriptor_type) {
|
||||
return Err(DescriptorRequirementsNotMet::DescriptorType {
|
||||
required: descriptor_types.clone(),
|
||||
obtained: self.descriptor_type,
|
||||
});
|
||||
}
|
||||
|
||||
if self.descriptor_count < *descriptor_count {
|
||||
return Err(DescriptorRequirementsNotMet::DescriptorCount {
|
||||
required: *descriptor_count,
|
||||
obtained: self.descriptor_count,
|
||||
});
|
||||
}
|
||||
|
||||
if !self.stages.is_superset_of(stages) {
|
||||
return Err(DescriptorRequirementsNotMet::ShaderStages {
|
||||
required: *stages,
|
||||
obtained: self.stages,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&DescriptorRequirements> for DescriptorSetLayoutBinding {
|
||||
fn from(reqs: &DescriptorRequirements) -> Self {
|
||||
Self {
|
||||
descriptor_type: reqs.descriptor_types[0],
|
||||
descriptor_count: reqs.descriptor_count,
|
||||
variable_descriptor_count: false,
|
||||
stages: reqs.stages,
|
||||
immutable_samplers: Vec::new(),
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error when checking whether the requirements for a binding have been met.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum DescriptorRequirementsNotMet {
|
||||
/// The binding's `descriptor_type` is not one of those required.
|
||||
DescriptorType {
|
||||
required: Vec<DescriptorType>,
|
||||
obtained: DescriptorType,
|
||||
},
|
||||
|
||||
/// The binding's `descriptor_count` is less than what is required.
|
||||
DescriptorCount { required: u32, obtained: u32 },
|
||||
|
||||
/// The binding's `stages` does not contain the stages that are required.
|
||||
ShaderStages {
|
||||
required: ShaderStages,
|
||||
obtained: ShaderStages,
|
||||
},
|
||||
}
|
||||
|
||||
impl error::Error for DescriptorRequirementsNotMet {}
|
||||
|
||||
impl fmt::Display for DescriptorRequirementsNotMet {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
Self::DescriptorType { required, obtained } => write!(
|
||||
fmt,
|
||||
"the descriptor's type ({:?}) is not one of those required ({:?})",
|
||||
obtained, required
|
||||
),
|
||||
Self::DescriptorCount { required, obtained } => write!(
|
||||
fmt,
|
||||
"the descriptor count ({}) is less than what is required ({})",
|
||||
obtained, required
|
||||
),
|
||||
Self::ShaderStages { required, obtained } => write!(
|
||||
fmt,
|
||||
"the descriptor's shader stages do not contain the stages that are required",
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes what kind of resource may later be bound to a descriptor.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
#[non_exhaustive]
|
||||
pub enum DescriptorType {
|
||||
/// Describes how a `SampledImage` descriptor should be read.
|
||||
Sampler = ash::vk::DescriptorType::SAMPLER.as_raw(),
|
||||
|
||||
/// Combines `SampledImage` and `Sampler` in one descriptor.
|
||||
CombinedImageSampler = ash::vk::DescriptorType::COMBINED_IMAGE_SAMPLER.as_raw(),
|
||||
|
||||
/// Gives read-only access to an image via a sampler. The image must be combined with a sampler
|
||||
/// inside the shader.
|
||||
SampledImage = ash::vk::DescriptorType::SAMPLED_IMAGE.as_raw(),
|
||||
|
||||
/// Gives read and/or write access to individual pixels in an image. The image cannot be
|
||||
/// sampled, so you have exactly specify which pixel to read or write.
|
||||
StorageImage = ash::vk::DescriptorType::STORAGE_IMAGE.as_raw(),
|
||||
|
||||
/// Gives read-only access to the content of a buffer, interpreted as an array of texel data.
|
||||
UniformTexelBuffer = ash::vk::DescriptorType::UNIFORM_TEXEL_BUFFER.as_raw(),
|
||||
|
||||
/// Gives read and/or write access to the content of a buffer, interpreted as an array of texel
|
||||
/// data. Less restrictive but sometimes slower than a uniform texel buffer.
|
||||
StorageTexelBuffer = ash::vk::DescriptorType::STORAGE_TEXEL_BUFFER.as_raw(),
|
||||
|
||||
/// Gives read-only access to the content of a buffer, interpreted as a structure.
|
||||
UniformBuffer = ash::vk::DescriptorType::UNIFORM_BUFFER.as_raw(),
|
||||
|
||||
/// Gives read and/or write access to the content of a buffer, interpreted as a structure. Less
|
||||
/// restrictive but sometimes slower than a uniform buffer.
|
||||
StorageBuffer = ash::vk::DescriptorType::STORAGE_BUFFER.as_raw(),
|
||||
|
||||
/// As `UniformBuffer`, but the offset within the buffer is specified at the time the descriptor
|
||||
/// set is bound, rather than when the descriptor set is updated.
|
||||
UniformBufferDynamic = ash::vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC.as_raw(),
|
||||
|
||||
/// As `StorageBuffer`, but the offset within the buffer is specified at the time the descriptor
|
||||
/// set is bound, rather than when the descriptor set is updated.
|
||||
StorageBufferDynamic = ash::vk::DescriptorType::STORAGE_BUFFER_DYNAMIC.as_raw(),
|
||||
|
||||
/// Gives access to an image inside a fragment shader via a render pass. You can only access the
|
||||
/// pixel that is currently being processed by the fragment shader.
|
||||
InputAttachment = ash::vk::DescriptorType::INPUT_ATTACHMENT.as_raw(),
|
||||
}
|
||||
|
||||
impl From<DescriptorType> for ash::vk::DescriptorType {
|
||||
#[inline]
|
||||
fn from(val: DescriptorType) -> Self {
|
||||
Self::from_raw(val as i32)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::descriptor_set::layout::DescriptorSetLayout;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayoutBinding;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayoutCreateInfo;
|
||||
use crate::descriptor_set::layout::DescriptorType;
|
||||
use crate::descriptor_set::pool::DescriptorsCount;
|
||||
use crate::shader::ShaderStages;
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
let _layout = DescriptorSetLayout::new(device, Default::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_create() {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
|
||||
let sl = DescriptorSetLayout::new(
|
||||
device.clone(),
|
||||
DescriptorSetLayoutCreateInfo {
|
||||
bindings: [(
|
||||
0,
|
||||
DescriptorSetLayoutBinding {
|
||||
stages: ShaderStages::all_graphics(),
|
||||
..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer)
|
||||
},
|
||||
)]
|
||||
.into(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
sl.descriptors_count(),
|
||||
&DescriptorsCount {
|
||||
uniform_buffer: 1,
|
||||
..DescriptorsCount::zero()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -1,446 +0,0 @@
|
||||
// Copyright (c) 2016 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
//! Description of a single descriptor.
|
||||
//!
|
||||
//! This module contains traits and structs related to describing a single descriptor. A descriptor
|
||||
//! is a slot where you can bind a buffer or an image so that it can be accessed from your shaders.
|
||||
//! In order to specify which buffer or image to bind to a descriptor, see the `descriptor_set`
|
||||
//! module.
|
||||
//!
|
||||
//! There are four different kinds of descriptors that give access to buffers:
|
||||
//!
|
||||
//! - Uniform texel buffers. Gives read-only access to the content of a buffer. Only supports
|
||||
//! certain buffer formats.
|
||||
//! - Storage texel buffers. Gives read and/or write access to the content of a buffer. Only
|
||||
//! supports certain buffer formats. Less restrictive but sometimes slower than uniform texel
|
||||
//! buffers.
|
||||
//! - Uniform buffers. Gives read-only access to the content of a buffer. Less restrictive but
|
||||
//! sometimes slower than uniform texel buffers.
|
||||
//! - Storage buffers. Gives read and/or write access to the content of a buffer. Less restrictive
|
||||
//! but sometimes slower than uniform buffers and storage texel buffers.
|
||||
//!
|
||||
//! There are five different kinds of descriptors related to images:
|
||||
//!
|
||||
//! - Storage images. Gives read and/or write access to individual pixels in an image. The image
|
||||
//! cannot be sampled. In other words, you have exactly specify which pixel to read or write.
|
||||
//! - Sampled images. Gives read-only access to an image. Before you can use a sampled image in a
|
||||
//! a shader, you have to combine it with a sampler (see below). The sampler describes how
|
||||
//! reading the image will behave.
|
||||
//! - Samplers. Doesn't contain an image but a sampler object that describes how an image will be
|
||||
//! accessed. This is meant to be combined with a sampled image (see above).
|
||||
//! - Combined image and sampler. Similar to a sampled image, but also directly includes the
|
||||
//! sampler which indicates how the sampling is done.
|
||||
//! - Input attachments. The fastest but also most restrictive access to images. Must be integrated
|
||||
//! in a render pass. Can only give access to the same pixel as the one you're processing.
|
||||
//!
|
||||
|
||||
use crate::sampler::Sampler;
|
||||
use crate::shader::DescriptorRequirements;
|
||||
use crate::shader::ShaderStages;
|
||||
use smallvec::SmallVec;
|
||||
use std::cmp;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct DescriptorSetDesc {
|
||||
descriptors: SmallVec<[Option<DescriptorDesc>; 4]>,
|
||||
push_descriptor: bool,
|
||||
}
|
||||
|
||||
impl DescriptorSetDesc {
|
||||
/// Builds a new `DescriptorSetDesc` with the given descriptors.
|
||||
///
|
||||
/// The descriptors must be passed in the order of the bindings. In order words, descriptor
|
||||
/// at bind point 0 first, then descriptor at bind point 1, and so on. If a binding must remain
|
||||
/// empty, you can make the iterator yield `None` for an element.
|
||||
#[inline]
|
||||
pub fn new<I>(descriptors: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = Option<DescriptorDesc>>,
|
||||
{
|
||||
Self {
|
||||
descriptors: descriptors.into_iter().collect(),
|
||||
push_descriptor: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a list of `DescriptorSetDesc` from an iterator of `DescriptorRequirement` originating
|
||||
/// from a shader.
|
||||
#[inline]
|
||||
pub fn from_requirements<'a>(
|
||||
descriptor_requirements: impl IntoIterator<Item = ((u32, u32), &'a DescriptorRequirements)>,
|
||||
) -> Vec<Self> {
|
||||
let mut descriptor_sets: Vec<Self> = Vec::new();
|
||||
|
||||
for ((set_num, binding_num), reqs) in descriptor_requirements {
|
||||
let set_num = set_num as usize;
|
||||
let binding_num = binding_num as usize;
|
||||
|
||||
if set_num >= descriptor_sets.len() {
|
||||
descriptor_sets.resize(set_num + 1, Self::default());
|
||||
}
|
||||
|
||||
let descriptors = &mut descriptor_sets[set_num].descriptors;
|
||||
|
||||
if binding_num >= descriptors.len() {
|
||||
descriptors.resize(binding_num + 1, None);
|
||||
}
|
||||
|
||||
descriptors[binding_num] = Some(reqs.into());
|
||||
}
|
||||
|
||||
descriptor_sets
|
||||
}
|
||||
|
||||
/// Builds a new empty `DescriptorSetDesc`.
|
||||
#[inline]
|
||||
pub fn empty() -> DescriptorSetDesc {
|
||||
DescriptorSetDesc {
|
||||
descriptors: SmallVec::new(),
|
||||
push_descriptor: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the descriptors in the set.
|
||||
#[inline]
|
||||
pub fn bindings(&self) -> &[Option<DescriptorDesc>] {
|
||||
&self.descriptors
|
||||
}
|
||||
|
||||
/// Returns the descriptor with the given binding number, or `None` if the binding is empty.
|
||||
#[inline]
|
||||
pub fn descriptor(&self, num: u32) -> Option<&DescriptorDesc> {
|
||||
self.descriptors.get(num as usize).and_then(|b| b.as_ref())
|
||||
}
|
||||
|
||||
/// Returns whether the description is set to be a push descriptor.
|
||||
#[inline]
|
||||
pub fn is_push_descriptor(&self) -> bool {
|
||||
self.push_descriptor
|
||||
}
|
||||
|
||||
/// Changes a buffer descriptor's type to dynamic.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - Panics if the description is set to be a push descriptor.
|
||||
/// - Panics if `binding_num` does not refer to a `StorageBuffer` or `UniformBuffer` descriptor.
|
||||
pub fn set_buffer_dynamic(&mut self, binding_num: u32) {
|
||||
assert!(
|
||||
!self.push_descriptor,
|
||||
"push descriptor is enabled, which does not allow dynamic buffer descriptors"
|
||||
);
|
||||
assert!(
|
||||
self.descriptor(binding_num).map_or(false, |desc| matches!(
|
||||
desc.ty,
|
||||
DescriptorType::StorageBuffer | DescriptorType::UniformBuffer
|
||||
)),
|
||||
"tried to make the non-buffer descriptor at binding {} a dynamic buffer",
|
||||
binding_num
|
||||
);
|
||||
|
||||
let binding = self
|
||||
.descriptors
|
||||
.get_mut(binding_num as usize)
|
||||
.and_then(|b| b.as_mut());
|
||||
|
||||
if let Some(desc) = binding {
|
||||
match &desc.ty {
|
||||
DescriptorType::StorageBuffer => {
|
||||
desc.ty = DescriptorType::StorageBufferDynamic;
|
||||
}
|
||||
DescriptorType::UniformBuffer => {
|
||||
desc.ty = DescriptorType::UniformBufferDynamic;
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the immutable samplers for a sampler or combined image sampler descriptor.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - Panics if the binding number does not refer to a sampler or combined image sampler
|
||||
/// descriptor.
|
||||
pub fn set_immutable_samplers(
|
||||
&mut self,
|
||||
binding_num: u32,
|
||||
samplers: impl IntoIterator<Item = Arc<Sampler>>,
|
||||
) {
|
||||
let immutable_samplers = self
|
||||
.descriptors
|
||||
.get_mut(binding_num as usize)
|
||||
.and_then(|b| b.as_mut())
|
||||
.and_then(|desc| match desc.ty {
|
||||
DescriptorType::Sampler | DescriptorType::CombinedImageSampler => {
|
||||
Some(&mut desc.immutable_samplers)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.expect("binding_num does not refer to a sampler or combined image sampler descriptor");
|
||||
|
||||
immutable_samplers.clear();
|
||||
immutable_samplers.extend(samplers.into_iter());
|
||||
}
|
||||
|
||||
/// Sets the descriptor set layout to use push descriptors instead of descriptor sets.
|
||||
///
|
||||
/// If set to enabled, the
|
||||
/// [`khr_push_descriptor`](crate::device::DeviceExtensions::khr_push_descriptor) extension must
|
||||
/// be enabled on the device.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - If enabled, panics if the description contains a dynamic buffer descriptor.
|
||||
pub fn set_push_descriptor(&mut self, enabled: bool) {
|
||||
if enabled {
|
||||
assert!(
|
||||
!self.descriptors.iter().flatten().any(|desc| {
|
||||
matches!(
|
||||
desc.ty,
|
||||
DescriptorType::UniformBufferDynamic | DescriptorType::StorageBufferDynamic
|
||||
)
|
||||
}),
|
||||
"descriptor set contains a dynamic buffer descriptor"
|
||||
);
|
||||
}
|
||||
self.push_descriptor = enabled;
|
||||
}
|
||||
|
||||
/// Sets the descriptor count for a descriptor that has a variable count.
|
||||
pub fn set_variable_descriptor_count(&mut self, binding_num: u32, descriptor_count: u32) {
|
||||
// TODO: Errors instead of panic
|
||||
|
||||
match self
|
||||
.descriptors
|
||||
.get_mut(binding_num as usize)
|
||||
.and_then(|b| b.as_mut())
|
||||
{
|
||||
Some(desc) => {
|
||||
desc.variable_count = true;
|
||||
desc.descriptor_count = descriptor_count;
|
||||
}
|
||||
None => panic!("descriptor is empty"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether `self` is compatible with `other`.
|
||||
///
|
||||
/// "Compatible" in this sense is defined by the Vulkan specification under the section
|
||||
/// "Pipeline layout compatibility": the two must be identically defined to the Vulkan API,
|
||||
/// meaning that all descriptors are compatible and flags are identical.
|
||||
#[inline]
|
||||
pub fn is_compatible_with(&self, other: &DescriptorSetDesc) -> bool {
|
||||
if self.push_descriptor != other.push_descriptor {
|
||||
return false;
|
||||
}
|
||||
|
||||
let num_bindings = cmp::max(self.descriptors.len(), other.descriptors.len()) as u32;
|
||||
(0..num_bindings).all(|binding_num| {
|
||||
match (self.descriptor(binding_num), other.descriptor(binding_num)) {
|
||||
(None, None) => true,
|
||||
(Some(first), Some(second)) => first == second,
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> From<I> for DescriptorSetDesc
|
||||
where
|
||||
I: IntoIterator<Item = Option<DescriptorDesc>>,
|
||||
{
|
||||
#[inline]
|
||||
fn from(val: I) -> Self {
|
||||
DescriptorSetDesc {
|
||||
descriptors: val.into_iter().collect(),
|
||||
push_descriptor: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains the exact description of a single descriptor.
|
||||
///
|
||||
/// > **Note**: You are free to fill a `DescriptorDesc` struct the way you want, but its validity
|
||||
/// > will be checked when you create a pipeline layout, a descriptor set, or when you try to bind
|
||||
/// > a descriptor set.
|
||||
// TODO: add example
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct DescriptorDesc {
|
||||
/// Describes the content and layout of each array element of a descriptor.
|
||||
pub ty: DescriptorType,
|
||||
|
||||
/// How many array elements this descriptor is made of. The value 0 is invalid and may trigger
|
||||
/// a panic depending on the situation.
|
||||
pub descriptor_count: u32,
|
||||
|
||||
/// True if the descriptor has a variable descriptor count. The value of `descriptor_count`
|
||||
/// is taken as the maximum number of descriptors allowed. There may only be one binding with a
|
||||
/// variable count in a descriptor set, and it must be the last binding.
|
||||
pub variable_count: bool,
|
||||
|
||||
/// Which shader stages are going to access this descriptor.
|
||||
pub stages: ShaderStages,
|
||||
|
||||
/// Samplers that are included as a fixed part of the descriptor set layout. Once bound, they
|
||||
/// do not need to be provided when creating a descriptor set.
|
||||
///
|
||||
/// The list must be either empty, or contain exactly `descriptor_count` samplers. It must be
|
||||
/// empty if `ty` is something other than `Sampler` or `CombinedImageSampler`. If any of the
|
||||
/// samplers has an attached sampler YCbCr conversion, then only `CombinedImageSampler` is
|
||||
/// allowed.
|
||||
pub immutable_samplers: Vec<Arc<Sampler>>,
|
||||
}
|
||||
|
||||
impl DescriptorDesc {
|
||||
/// Checks whether the descriptor of a pipeline layout `self` is compatible with the descriptor
|
||||
/// of a shader `other`.
|
||||
#[inline]
|
||||
pub fn ensure_compatible_with_shader(
|
||||
&self,
|
||||
descriptor_requirements: &DescriptorRequirements,
|
||||
) -> Result<(), DescriptorRequirementsNotMet> {
|
||||
let DescriptorRequirements {
|
||||
descriptor_types,
|
||||
descriptor_count,
|
||||
image_format,
|
||||
image_multisampled,
|
||||
image_scalar_type,
|
||||
image_view_type,
|
||||
sampler_compare,
|
||||
sampler_no_unnormalized_coordinates,
|
||||
sampler_no_ycbcr_conversion,
|
||||
sampler_with_images,
|
||||
stages,
|
||||
storage_image_atomic,
|
||||
storage_read,
|
||||
storage_write,
|
||||
} = descriptor_requirements;
|
||||
|
||||
if !descriptor_types.contains(&self.ty) {
|
||||
return Err(DescriptorRequirementsNotMet::DescriptorType {
|
||||
required: descriptor_types.clone(),
|
||||
obtained: self.ty,
|
||||
});
|
||||
}
|
||||
|
||||
if self.descriptor_count < *descriptor_count {
|
||||
return Err(DescriptorRequirementsNotMet::DescriptorCount {
|
||||
required: *descriptor_count,
|
||||
obtained: self.descriptor_count,
|
||||
});
|
||||
}
|
||||
|
||||
if !self.stages.is_superset_of(stages) {
|
||||
return Err(DescriptorRequirementsNotMet::ShaderStages {
|
||||
required: *stages,
|
||||
obtained: self.stages,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&DescriptorRequirements> for DescriptorDesc {
|
||||
fn from(reqs: &DescriptorRequirements) -> Self {
|
||||
let ty = match reqs.descriptor_types[0] {
|
||||
DescriptorType::Sampler => DescriptorType::Sampler,
|
||||
DescriptorType::CombinedImageSampler => DescriptorType::CombinedImageSampler,
|
||||
DescriptorType::SampledImage => DescriptorType::SampledImage,
|
||||
DescriptorType::StorageImage => DescriptorType::StorageImage,
|
||||
DescriptorType::UniformTexelBuffer => DescriptorType::UniformTexelBuffer,
|
||||
DescriptorType::StorageTexelBuffer => DescriptorType::StorageTexelBuffer,
|
||||
DescriptorType::UniformBuffer => DescriptorType::UniformBuffer,
|
||||
DescriptorType::StorageBuffer => DescriptorType::StorageBuffer,
|
||||
DescriptorType::UniformBufferDynamic => DescriptorType::UniformBufferDynamic,
|
||||
DescriptorType::StorageBufferDynamic => DescriptorType::StorageBufferDynamic,
|
||||
DescriptorType::InputAttachment => DescriptorType::InputAttachment,
|
||||
};
|
||||
|
||||
Self {
|
||||
ty,
|
||||
descriptor_count: reqs.descriptor_count,
|
||||
variable_count: false,
|
||||
stages: reqs.stages,
|
||||
immutable_samplers: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes what kind of resource may later be bound to a descriptor.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum DescriptorType {
|
||||
Sampler = ash::vk::DescriptorType::SAMPLER.as_raw(),
|
||||
CombinedImageSampler = ash::vk::DescriptorType::COMBINED_IMAGE_SAMPLER.as_raw(),
|
||||
SampledImage = ash::vk::DescriptorType::SAMPLED_IMAGE.as_raw(),
|
||||
StorageImage = ash::vk::DescriptorType::STORAGE_IMAGE.as_raw(),
|
||||
UniformTexelBuffer = ash::vk::DescriptorType::UNIFORM_TEXEL_BUFFER.as_raw(),
|
||||
StorageTexelBuffer = ash::vk::DescriptorType::STORAGE_TEXEL_BUFFER.as_raw(),
|
||||
UniformBuffer = ash::vk::DescriptorType::UNIFORM_BUFFER.as_raw(),
|
||||
StorageBuffer = ash::vk::DescriptorType::STORAGE_BUFFER.as_raw(),
|
||||
UniformBufferDynamic = ash::vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC.as_raw(),
|
||||
StorageBufferDynamic = ash::vk::DescriptorType::STORAGE_BUFFER_DYNAMIC.as_raw(),
|
||||
InputAttachment = ash::vk::DescriptorType::INPUT_ATTACHMENT.as_raw(),
|
||||
}
|
||||
|
||||
impl From<DescriptorType> for ash::vk::DescriptorType {
|
||||
#[inline]
|
||||
fn from(val: DescriptorType) -> Self {
|
||||
Self::from_raw(val as i32)
|
||||
}
|
||||
}
|
||||
|
||||
/// Error when checking whether the requirements for a descriptor have been met.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum DescriptorRequirementsNotMet {
|
||||
/// The descriptor's type is not one of those required.
|
||||
DescriptorType {
|
||||
required: Vec<DescriptorType>,
|
||||
obtained: DescriptorType,
|
||||
},
|
||||
|
||||
/// The descriptor count is less than what is required.
|
||||
DescriptorCount { required: u32, obtained: u32 },
|
||||
|
||||
/// The descriptor's shader stages do not contain the stages that are required.
|
||||
ShaderStages {
|
||||
required: ShaderStages,
|
||||
obtained: ShaderStages,
|
||||
},
|
||||
}
|
||||
|
||||
impl error::Error for DescriptorRequirementsNotMet {}
|
||||
|
||||
impl fmt::Display for DescriptorRequirementsNotMet {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
Self::DescriptorType { required, obtained } => write!(
|
||||
fmt,
|
||||
"the descriptor's type ({:?}) is not one of those required ({:?})",
|
||||
obtained, required
|
||||
),
|
||||
Self::DescriptorCount { required, obtained } => write!(
|
||||
fmt,
|
||||
"the descriptor count ({}) is less than what is required ({})",
|
||||
obtained, required
|
||||
),
|
||||
Self::ShaderStages { required, obtained } => write!(
|
||||
fmt,
|
||||
"the descriptor's shader stages do not contain the stages that are required",
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
// Copyright (c) 2021 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
//! Describes the layout of all descriptors within a descriptor set.
|
||||
//!
|
||||
//! When creating a new descriptor set, you must provide a *layout* object to create it from. You
|
||||
//! can create a descriptor set layout manually, but it is normally created automatically by each
|
||||
//! pipeline layout.
|
||||
|
||||
pub use self::desc::DescriptorDesc;
|
||||
pub use self::desc::DescriptorRequirementsNotMet;
|
||||
pub use self::desc::DescriptorSetDesc;
|
||||
pub use self::desc::DescriptorType;
|
||||
pub use self::sys::DescriptorSetLayout;
|
||||
pub use self::sys::DescriptorSetLayoutError;
|
||||
|
||||
mod desc;
|
||||
mod sys;
|
@ -1,504 +0,0 @@
|
||||
// Copyright (c) 2016 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use crate::check_errors;
|
||||
use crate::descriptor_set::layout::DescriptorDesc;
|
||||
use crate::descriptor_set::layout::DescriptorSetDesc;
|
||||
use crate::descriptor_set::layout::DescriptorType;
|
||||
use crate::descriptor_set::pool::DescriptorsCount;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::OomError;
|
||||
use crate::Version;
|
||||
use crate::VulkanObject;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Describes to the Vulkan implementation the layout of all descriptors within a descriptor set.
|
||||
#[derive(Debug)]
|
||||
pub struct DescriptorSetLayout {
|
||||
// The layout.
|
||||
handle: ash::vk::DescriptorSetLayout,
|
||||
// The device this layout belongs to.
|
||||
device: Arc<Device>,
|
||||
// Descriptors.
|
||||
desc: DescriptorSetDesc,
|
||||
// Number of descriptors of each type.
|
||||
descriptors_count: DescriptorsCount,
|
||||
}
|
||||
|
||||
impl DescriptorSetLayout {
|
||||
/// Builds a new `DescriptorSetLayout` with the given descriptors.
|
||||
///
|
||||
/// The descriptors must be passed in the order of the bindings. In order words, descriptor
|
||||
/// at bind point 0 first, then descriptor at bind point 1, and so on. If a binding must remain
|
||||
/// empty, you can make the iterator yield `None` for an element.
|
||||
pub fn new<D>(
|
||||
device: Arc<Device>,
|
||||
set_desc: D,
|
||||
) -> Result<Arc<DescriptorSetLayout>, DescriptorSetLayoutError>
|
||||
where
|
||||
D: Into<DescriptorSetDesc>,
|
||||
{
|
||||
let set_desc = set_desc.into();
|
||||
let mut descriptors_count = DescriptorsCount::zero();
|
||||
let bindings = set_desc.bindings();
|
||||
let mut bindings_vk = Vec::with_capacity(bindings.len());
|
||||
let mut binding_flags_vk = Vec::with_capacity(bindings.len());
|
||||
let mut immutable_samplers_vk: Vec<Box<[ash::vk::Sampler]>> = Vec::new(); // only to keep the arrays of handles alive
|
||||
|
||||
let mut flags = ash::vk::DescriptorSetLayoutCreateFlags::empty();
|
||||
|
||||
if set_desc.is_push_descriptor() {
|
||||
if !device.enabled_extensions().khr_push_descriptor {
|
||||
return Err(DescriptorSetLayoutError::ExtensionNotEnabled {
|
||||
extension: "khr_push_descriptor",
|
||||
reason: "description was set to be a push descriptor",
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: VUID-VkDescriptorSetLayoutCreateInfo-flags-04590
|
||||
// If flags contains VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, flags must
|
||||
// not contain VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE
|
||||
|
||||
flags |= ash::vk::DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR_KHR;
|
||||
}
|
||||
|
||||
for (binding, binding_desc) in bindings.iter().enumerate() {
|
||||
let binding_desc = match binding_desc {
|
||||
Some(d) => d,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
// FIXME: it is not legal to pass eg. the TESSELLATION_SHADER bit when the device
|
||||
// doesn't have tess shaders enabled
|
||||
|
||||
let ty = binding_desc.ty;
|
||||
|
||||
if set_desc.is_push_descriptor() {
|
||||
if matches!(
|
||||
ty,
|
||||
DescriptorType::StorageBufferDynamic | DescriptorType::UniformBufferDynamic
|
||||
) {
|
||||
return Err(DescriptorSetLayoutError::PushDescriptorDynamicBuffer);
|
||||
}
|
||||
|
||||
if binding_desc.variable_count {
|
||||
return Err(DescriptorSetLayoutError::PushDescriptorVariableCount);
|
||||
}
|
||||
|
||||
// TODO: VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-flags-03003
|
||||
// If VkDescriptorSetLayoutCreateInfo::flags includes
|
||||
// VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR,
|
||||
// then all elements of pBindingFlags must not include
|
||||
// VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT,
|
||||
// VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, or
|
||||
// VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT
|
||||
|
||||
// TODO: VUID-VkDescriptorSetLayoutCreateInfo-flags-02208
|
||||
// If flags contains VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, then all
|
||||
// elements of pBindings must not have a descriptorType of
|
||||
// VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT
|
||||
|
||||
// TODO: VUID-VkDescriptorSetLayoutCreateInfo-flags-04591
|
||||
// If flags contains VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR,
|
||||
// pBindings must not have a descriptorType of VK_DESCRIPTOR_TYPE_MUTABLE_VALVE
|
||||
}
|
||||
|
||||
descriptors_count.add_num(ty, binding_desc.descriptor_count);
|
||||
let mut binding_flags = ash::vk::DescriptorBindingFlags::empty();
|
||||
|
||||
let p_immutable_samplers = if !binding_desc.immutable_samplers.is_empty() {
|
||||
if binding_desc
|
||||
.immutable_samplers
|
||||
.iter()
|
||||
.any(|sampler| sampler.sampler_ycbcr_conversion().is_some())
|
||||
{
|
||||
if !matches!(ty, DescriptorType::CombinedImageSampler) {
|
||||
return Err(DescriptorSetLayoutError::ImmutableSamplersWrongDescriptorType);
|
||||
}
|
||||
} else {
|
||||
if !matches!(
|
||||
ty,
|
||||
DescriptorType::Sampler | DescriptorType::CombinedImageSampler
|
||||
) {
|
||||
return Err(DescriptorSetLayoutError::ImmutableSamplersWrongDescriptorType);
|
||||
}
|
||||
}
|
||||
|
||||
if binding_desc.descriptor_count != binding_desc.immutable_samplers.len() as u32 {
|
||||
return Err(DescriptorSetLayoutError::ImmutableSamplersCountMismatch {
|
||||
descriptor_count: binding_desc.descriptor_count,
|
||||
sampler_count: binding_desc.immutable_samplers.len() as u32,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: VUID-VkDescriptorSetLayoutBinding-pImmutableSamplers-04009
|
||||
// The sampler objects indicated by pImmutableSamplers must not have a borderColor
|
||||
// with one of the values VK_BORDER_COLOR_FLOAT_CUSTOM_EXT or
|
||||
// VK_BORDER_COLOR_INT_CUSTOM_EXT
|
||||
|
||||
let sampler_handles = binding_desc
|
||||
.immutable_samplers
|
||||
.iter()
|
||||
.map(|s| s.internal_object())
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice();
|
||||
let p_immutable_samplers = sampler_handles.as_ptr();
|
||||
immutable_samplers_vk.push(sampler_handles);
|
||||
p_immutable_samplers
|
||||
} else {
|
||||
ptr::null()
|
||||
};
|
||||
|
||||
if binding_desc.variable_count {
|
||||
if binding != bindings.len() - 1 {
|
||||
return Err(DescriptorSetLayoutError::VariableCountDescMustBeLast);
|
||||
}
|
||||
|
||||
if binding_desc.ty == DescriptorType::UniformBufferDynamic
|
||||
|| binding_desc.ty == DescriptorType::StorageBufferDynamic
|
||||
{
|
||||
return Err(DescriptorSetLayoutError::VariableCountDescMustNotBeDynamic);
|
||||
}
|
||||
|
||||
if !device.enabled_features().runtime_descriptor_array {
|
||||
return Err(DescriptorSetLayoutError::FeatureNotEnabled {
|
||||
feature: "runtime_descriptor_array",
|
||||
reason: "binding has a variable count",
|
||||
});
|
||||
}
|
||||
|
||||
if !device
|
||||
.enabled_features()
|
||||
.descriptor_binding_variable_descriptor_count
|
||||
{
|
||||
return Err(DescriptorSetLayoutError::FeatureNotEnabled {
|
||||
feature: "descriptor_binding_variable_descriptor_count",
|
||||
reason: "binding has a variable count",
|
||||
});
|
||||
}
|
||||
|
||||
binding_flags |= ash::vk::DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT;
|
||||
}
|
||||
|
||||
bindings_vk.push(ash::vk::DescriptorSetLayoutBinding {
|
||||
binding: binding as u32,
|
||||
descriptor_type: ty.into(),
|
||||
descriptor_count: binding_desc.descriptor_count,
|
||||
stage_flags: binding_desc.stages.into(),
|
||||
p_immutable_samplers,
|
||||
});
|
||||
binding_flags_vk.push(binding_flags);
|
||||
}
|
||||
|
||||
if set_desc.is_push_descriptor()
|
||||
&& descriptors_count.total()
|
||||
> device
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_push_descriptors
|
||||
.unwrap_or(0)
|
||||
{
|
||||
return Err(DescriptorSetLayoutError::MaxPushDescriptorsExceeded {
|
||||
max: device
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_push_descriptors
|
||||
.unwrap_or(0),
|
||||
obtained: descriptors_count.total(),
|
||||
});
|
||||
}
|
||||
|
||||
let handle = unsafe {
|
||||
let binding_flags_infos = if device.api_version() >= Version::V1_2
|
||||
|| device.enabled_extensions().ext_descriptor_indexing
|
||||
{
|
||||
Some(ash::vk::DescriptorSetLayoutBindingFlagsCreateInfo {
|
||||
// Note that it seems legal to have no descriptor at all in the set.
|
||||
binding_count: binding_flags_vk.len() as u32,
|
||||
p_binding_flags: binding_flags_vk.as_ptr(),
|
||||
..Default::default()
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let infos = ash::vk::DescriptorSetLayoutCreateInfo {
|
||||
flags,
|
||||
binding_count: bindings_vk.len() as u32,
|
||||
p_bindings: bindings_vk.as_ptr(),
|
||||
p_next: if let Some(next) = binding_flags_infos.as_ref() {
|
||||
next as *const _ as *const _
|
||||
} else {
|
||||
ptr::null()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut output = MaybeUninit::uninit();
|
||||
let fns = device.fns();
|
||||
|
||||
check_errors(fns.v1_0.create_descriptor_set_layout(
|
||||
device.internal_object(),
|
||||
&infos,
|
||||
ptr::null(),
|
||||
output.as_mut_ptr(),
|
||||
))
|
||||
.map_err(|e| OomError::from(e))?;
|
||||
|
||||
output.assume_init()
|
||||
};
|
||||
|
||||
Ok(Arc::new(DescriptorSetLayout {
|
||||
handle,
|
||||
device,
|
||||
desc: set_desc,
|
||||
descriptors_count,
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn desc(&self) -> &DescriptorSetDesc {
|
||||
&self.desc
|
||||
}
|
||||
|
||||
/// Returns the number of descriptors of each type.
|
||||
#[inline]
|
||||
pub fn descriptors_count(&self) -> &DescriptorsCount {
|
||||
&self.descriptors_count
|
||||
}
|
||||
|
||||
/// If the last binding has a variable count, returns its `descriptor_count`. Otherwise returns
|
||||
/// 0.
|
||||
#[inline]
|
||||
pub fn variable_descriptor_count(&self) -> u32 {
|
||||
self.desc
|
||||
.bindings()
|
||||
.last()
|
||||
.and_then(|binding| binding.as_ref())
|
||||
.map(|binding| {
|
||||
if binding.variable_count {
|
||||
binding.descriptor_count
|
||||
} else {
|
||||
0
|
||||
}
|
||||
})
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Returns the number of binding slots in the set.
|
||||
#[inline]
|
||||
pub fn num_bindings(&self) -> u32 {
|
||||
self.desc.bindings().len() as u32
|
||||
}
|
||||
|
||||
/// Returns a description of a descriptor, or `None` if out of range.
|
||||
#[inline]
|
||||
pub fn descriptor(&self, binding: u32) -> Option<DescriptorDesc> {
|
||||
self.desc
|
||||
.bindings()
|
||||
.get(binding as usize)
|
||||
.cloned()
|
||||
.unwrap_or(None)
|
||||
}
|
||||
|
||||
/// Returns whether `self` is compatible with `other`.
|
||||
///
|
||||
/// "Compatible" in this sense is defined by the Vulkan specification under the section
|
||||
/// "Pipeline layout compatibility": either the two are the same descriptor set layout, or they
|
||||
/// must be identically defined to the Vulkan API.
|
||||
#[inline]
|
||||
pub fn is_compatible_with(&self, other: &DescriptorSetLayout) -> bool {
|
||||
self.handle == other.handle || self.desc.is_compatible_with(&other.desc)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl DeviceOwned for DescriptorSetLayout {
|
||||
#[inline]
|
||||
fn device(&self) -> &Arc<Device> {
|
||||
&self.device
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl VulkanObject for DescriptorSetLayout {
|
||||
type Object = ash::vk::DescriptorSetLayout;
|
||||
|
||||
#[inline]
|
||||
fn internal_object(&self) -> ash::vk::DescriptorSetLayout {
|
||||
self.handle
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DescriptorSetLayout {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let fns = self.device.fns();
|
||||
fns.v1_0.destroy_descriptor_set_layout(
|
||||
self.device.internal_object(),
|
||||
self.handle,
|
||||
ptr::null(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error related to descriptor set layout.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum DescriptorSetLayoutError {
|
||||
ExtensionNotEnabled {
|
||||
extension: &'static str,
|
||||
reason: &'static str,
|
||||
},
|
||||
FeatureNotEnabled {
|
||||
feature: &'static str,
|
||||
reason: &'static str,
|
||||
},
|
||||
|
||||
/// The number of immutable samplers does not match the descriptor count.
|
||||
ImmutableSamplersCountMismatch {
|
||||
descriptor_count: u32,
|
||||
sampler_count: u32,
|
||||
},
|
||||
|
||||
/// Immutable samplers were included on a descriptor type other than `Sampler` or
|
||||
/// `CombinedImageSampler`, or, if any of the samplers had a sampler YCbCr conversion, were
|
||||
/// included on a descriptor type other than `CombinedImageSampler`.
|
||||
ImmutableSamplersWrongDescriptorType,
|
||||
|
||||
/// The maximum number of push descriptors has been exceeded.
|
||||
MaxPushDescriptorsExceeded {
|
||||
/// Maximum allowed value.
|
||||
max: u32,
|
||||
/// Value that was passed.
|
||||
obtained: u32,
|
||||
},
|
||||
|
||||
/// Out of Memory.
|
||||
OomError(OomError),
|
||||
|
||||
/// The layout was being created for push descriptors, but included a dynamic buffer binding.
|
||||
PushDescriptorDynamicBuffer,
|
||||
|
||||
/// The layout was being created for push descriptors, but included a variable count binding.
|
||||
PushDescriptorVariableCount,
|
||||
|
||||
/// Variable count descriptor must be last binding.
|
||||
VariableCountDescMustBeLast,
|
||||
|
||||
/// Variable count descriptor must not be a dynamic buffer.
|
||||
VariableCountDescMustNotBeDynamic,
|
||||
}
|
||||
|
||||
impl From<OomError> for DescriptorSetLayoutError {
|
||||
fn from(error: OomError) -> Self {
|
||||
Self::OomError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for DescriptorSetLayoutError {}
|
||||
|
||||
impl std::fmt::Display for DescriptorSetLayoutError {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
match *self {
|
||||
Self::ExtensionNotEnabled { extension, reason } => {
|
||||
write!(
|
||||
fmt,
|
||||
"the extension {} must be enabled: {}",
|
||||
extension, reason
|
||||
)
|
||||
}
|
||||
Self::FeatureNotEnabled { feature, reason } => {
|
||||
write!(fmt, "the feature {} must be enabled: {}", feature, reason)
|
||||
}
|
||||
Self::ImmutableSamplersCountMismatch { .. } => {
|
||||
write!(
|
||||
fmt,
|
||||
"the number of immutable samplers does not match the descriptor count"
|
||||
)
|
||||
}
|
||||
Self::ImmutableSamplersWrongDescriptorType => {
|
||||
write!(
|
||||
fmt,
|
||||
"immutable samplers were included on a descriptor type other than Sampler or CombinedImageSampler, or, if any of the samplers had a sampler YCbCr conversion, were included on a descriptor type other than CombinedImageSampler"
|
||||
)
|
||||
}
|
||||
Self::MaxPushDescriptorsExceeded { .. } => {
|
||||
write!(
|
||||
fmt,
|
||||
"the maximum number of push descriptors has been exceeded"
|
||||
)
|
||||
}
|
||||
Self::PushDescriptorDynamicBuffer => {
|
||||
write!(fmt, "the layout was being created for push descriptors, but included a dynamic buffer binding")
|
||||
}
|
||||
Self::PushDescriptorVariableCount => {
|
||||
write!(fmt, "the layout was being created for push descriptors, but included a variable count binding")
|
||||
}
|
||||
Self::OomError(_) => {
|
||||
write!(fmt, "out of memory")
|
||||
}
|
||||
Self::VariableCountDescMustBeLast => {
|
||||
write!(fmt, "variable count descriptor must be last binding")
|
||||
}
|
||||
Self::VariableCountDescMustNotBeDynamic => {
|
||||
write!(
|
||||
fmt,
|
||||
"variable count descriptor must not be a dynamic buffer"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::descriptor_set::layout::DescriptorDesc;
|
||||
use crate::descriptor_set::layout::DescriptorSetDesc;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayout;
|
||||
use crate::descriptor_set::layout::DescriptorType;
|
||||
use crate::descriptor_set::pool::DescriptorsCount;
|
||||
use crate::shader::ShaderStages;
|
||||
use std::iter;
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
let _layout = DescriptorSetLayout::new(device, DescriptorSetDesc::empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_create() {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
|
||||
let layout = DescriptorDesc {
|
||||
ty: DescriptorType::UniformBuffer,
|
||||
descriptor_count: 1,
|
||||
variable_count: false,
|
||||
stages: ShaderStages::all_graphics(),
|
||||
immutable_samplers: Vec::new(),
|
||||
};
|
||||
|
||||
let sl = DescriptorSetLayout::new(
|
||||
device.clone(),
|
||||
DescriptorSetDesc::new(iter::once(Some(layout))),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
sl.descriptors_count(),
|
||||
&DescriptorsCount {
|
||||
uniform_buffer: 1,
|
||||
..DescriptorsCount::zero()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -159,7 +159,7 @@ impl DescriptorSetInner {
|
||||
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
|
||||
) -> Result<Self, DescriptorSetUpdateError> {
|
||||
assert!(
|
||||
!layout.desc().is_push_descriptor(),
|
||||
!layout.push_descriptor(),
|
||||
"the provided descriptor set layout is for push descriptors, and cannot be used to build a descriptor set object"
|
||||
);
|
||||
|
||||
@ -184,8 +184,8 @@ impl DescriptorSetInner {
|
||||
check_descriptor_write(&write, &layout, variable_descriptor_count)?;
|
||||
|
||||
resources.update(&write);
|
||||
descriptor_write_info.push(write.to_vulkan_info(layout_binding.ty));
|
||||
write_descriptor_set.push(write.to_vulkan(handle, layout_binding.ty));
|
||||
descriptor_write_info.push(write.to_vulkan_info(layout_binding.descriptor_type));
|
||||
write_descriptor_set.push(write.to_vulkan(handle, layout_binding.descriptor_type));
|
||||
}
|
||||
|
||||
if !write_descriptor_set.is_empty() {
|
||||
@ -256,19 +256,16 @@ impl DescriptorSetResources {
|
||||
assert!(variable_descriptor_count <= layout.variable_descriptor_count());
|
||||
|
||||
let binding_resources = layout
|
||||
.desc()
|
||||
.bindings()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(b, d)| d.as_ref().map(|d| (b as u32, d)))
|
||||
.map(|(binding_num, binding_desc)| {
|
||||
let count = if binding_desc.variable_count {
|
||||
.map(|(&binding_num, binding)| {
|
||||
let count = if binding.variable_descriptor_count {
|
||||
variable_descriptor_count
|
||||
} else {
|
||||
binding_desc.descriptor_count
|
||||
binding.descriptor_count
|
||||
} as usize;
|
||||
|
||||
let binding_resources = match binding_desc.ty {
|
||||
let binding_resources = match binding.descriptor_type {
|
||||
DescriptorType::UniformBuffer
|
||||
| DescriptorType::StorageBuffer
|
||||
| DescriptorType::UniformBufferDynamic
|
||||
@ -284,16 +281,16 @@ impl DescriptorSetResources {
|
||||
DescriptorBindingResources::ImageView(smallvec![None; count])
|
||||
}
|
||||
DescriptorType::CombinedImageSampler => {
|
||||
if binding_desc.immutable_samplers.is_empty() {
|
||||
if binding.immutable_samplers.is_empty() {
|
||||
DescriptorBindingResources::ImageViewSampler(smallvec![None; count])
|
||||
} else {
|
||||
DescriptorBindingResources::ImageView(smallvec![None; count])
|
||||
}
|
||||
}
|
||||
DescriptorType::Sampler => {
|
||||
if binding_desc.immutable_samplers.is_empty() {
|
||||
if binding.immutable_samplers.is_empty() {
|
||||
DescriptorBindingResources::Sampler(smallvec![None; count])
|
||||
} else if layout.desc().is_push_descriptor() {
|
||||
} else if layout.push_descriptor() {
|
||||
// For push descriptors, no resource is written by default, this needs
|
||||
// to be done explicitly via a dummy write.
|
||||
DescriptorBindingResources::None(smallvec![None; count])
|
||||
@ -429,8 +426,8 @@ impl DescriptorSetWithOffsets {
|
||||
// Ensure that the number of dynamic_offsets is correct and that each
|
||||
// dynamic offset is a multiple of the minimum offset alignment specified
|
||||
// by the physical device.
|
||||
for desc in layout.desc().bindings() {
|
||||
match desc.as_ref().unwrap().ty {
|
||||
for binding in layout.bindings().values() {
|
||||
match binding.descriptor_type {
|
||||
DescriptorType::StorageBufferDynamic => {
|
||||
// Don't check alignment if there are not enough offsets anyway
|
||||
if dynamic_offsets.len() > dynamic_offset_index {
|
||||
|
@ -87,7 +87,7 @@ impl PersistentDescriptorSet {
|
||||
P: ?Sized + DescriptorPool,
|
||||
{
|
||||
assert!(
|
||||
!layout.desc().is_push_descriptor(),
|
||||
!layout.push_descriptor(),
|
||||
"the provided descriptor set layout is for push descriptors, and cannot be used to build a descriptor set object"
|
||||
);
|
||||
|
||||
|
@ -73,7 +73,7 @@ unsafe impl DescriptorPool for Arc<StdDescriptorPool> {
|
||||
variable_descriptor_count: u32,
|
||||
) -> Result<StdDescriptorPoolAlloc, OomError> {
|
||||
assert!(
|
||||
!layout.desc().is_push_descriptor(),
|
||||
!layout.push_descriptor(),
|
||||
"the provided descriptor set layout is for push descriptors, and cannot be used to build a descriptor set object",
|
||||
);
|
||||
|
||||
@ -204,14 +204,13 @@ impl Drop for StdDescriptorPoolAlloc {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::descriptor_set::layout::DescriptorDesc;
|
||||
use crate::descriptor_set::layout::DescriptorSetDesc;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayout;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayoutBinding;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayoutCreateInfo;
|
||||
use crate::descriptor_set::layout::DescriptorType;
|
||||
use crate::descriptor_set::pool::DescriptorPool;
|
||||
use crate::descriptor_set::pool::StdDescriptorPool;
|
||||
use crate::shader::ShaderStages;
|
||||
use std::iter;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[test]
|
||||
@ -219,16 +218,19 @@ mod tests {
|
||||
// Test that the `StdDescriptorPool` is kept alive by its allocations.
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
|
||||
let desc = DescriptorDesc {
|
||||
ty: DescriptorType::Sampler,
|
||||
descriptor_count: 1,
|
||||
variable_count: false,
|
||||
stages: ShaderStages::all(),
|
||||
immutable_samplers: Vec::new(),
|
||||
};
|
||||
let layout = DescriptorSetLayout::new(
|
||||
device.clone(),
|
||||
DescriptorSetDesc::new(iter::once(Some(desc))),
|
||||
DescriptorSetLayoutCreateInfo {
|
||||
bindings: [(
|
||||
0,
|
||||
DescriptorSetLayoutBinding {
|
||||
stages: ShaderStages::all(),
|
||||
..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::Sampler)
|
||||
},
|
||||
)]
|
||||
.into(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -162,7 +162,7 @@ impl UnsafeDescriptorPool {
|
||||
info.layout.device().internal_object(),
|
||||
"Tried to allocate from a pool with a set layout of a different device"
|
||||
);
|
||||
debug_assert!(!info.layout.desc().is_push_descriptor());
|
||||
debug_assert!(!info.layout.push_descriptor());
|
||||
debug_assert!(
|
||||
info.variable_descriptor_count <= info.layout.variable_descriptor_count()
|
||||
);
|
||||
@ -373,9 +373,9 @@ impl fmt::Display for DescriptorPoolAllocError {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::descriptor_set::layout::DescriptorDesc;
|
||||
use crate::descriptor_set::layout::DescriptorSetDesc;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayout;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayoutBinding;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayoutCreateInfo;
|
||||
use crate::descriptor_set::layout::DescriptorType;
|
||||
use crate::descriptor_set::pool::sys::DescriptorSetAllocateInfo;
|
||||
use crate::descriptor_set::pool::DescriptorsCount;
|
||||
@ -420,17 +420,19 @@ mod tests {
|
||||
fn basic_alloc() {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
|
||||
let layout = DescriptorDesc {
|
||||
ty: DescriptorType::UniformBuffer,
|
||||
descriptor_count: 1,
|
||||
variable_count: false,
|
||||
stages: ShaderStages::all_graphics(),
|
||||
immutable_samplers: Vec::new(),
|
||||
};
|
||||
|
||||
let set_layout = DescriptorSetLayout::new(
|
||||
device.clone(),
|
||||
DescriptorSetDesc::new(iter::once(Some(layout))),
|
||||
DescriptorSetLayoutCreateInfo {
|
||||
bindings: [(
|
||||
0,
|
||||
DescriptorSetLayoutBinding {
|
||||
stages: ShaderStages::all_graphics(),
|
||||
..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer)
|
||||
},
|
||||
)]
|
||||
.into(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@ -456,17 +458,21 @@ mod tests {
|
||||
let (device1, _) = gfx_dev_and_queue!();
|
||||
let (device2, _) = gfx_dev_and_queue!();
|
||||
|
||||
let layout = DescriptorDesc {
|
||||
ty: DescriptorType::UniformBuffer,
|
||||
descriptor_count: 1,
|
||||
variable_count: false,
|
||||
stages: ShaderStages::all_graphics(),
|
||||
immutable_samplers: Vec::new(),
|
||||
};
|
||||
|
||||
let set_layout =
|
||||
DescriptorSetLayout::new(device1, DescriptorSetDesc::new(iter::once(Some(layout))))
|
||||
.unwrap();
|
||||
let set_layout = DescriptorSetLayout::new(
|
||||
device1,
|
||||
DescriptorSetLayoutCreateInfo {
|
||||
bindings: [(
|
||||
0,
|
||||
DescriptorSetLayoutBinding {
|
||||
stages: ShaderStages::all_graphics(),
|
||||
..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer)
|
||||
},
|
||||
)]
|
||||
.into(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let desc = DescriptorsCount {
|
||||
uniform_buffer: 10,
|
||||
|
@ -49,7 +49,7 @@ impl SingleLayoutDescSetPool {
|
||||
/// - Panics if the provided `layout` has a binding with a variable descriptor count.
|
||||
pub fn new(layout: Arc<DescriptorSetLayout>) -> Self {
|
||||
assert!(
|
||||
!layout.desc().is_push_descriptor(),
|
||||
!layout.push_descriptor(),
|
||||
"the provided descriptor set layout is for push descriptors, and cannot be used to build a descriptor set object"
|
||||
);
|
||||
assert!(
|
||||
|
@ -51,7 +51,7 @@ impl UnsafeDescriptorSet {
|
||||
let (infos, mut writes): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = writes
|
||||
.into_iter()
|
||||
.map(|write| {
|
||||
let descriptor_type = layout.descriptor(write.binding()).unwrap().ty;
|
||||
let descriptor_type = layout.bindings()[&write.binding()].descriptor_type;
|
||||
|
||||
(
|
||||
write.to_vulkan_info(descriptor_type),
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
use crate::buffer::view::BufferViewAbstract;
|
||||
use crate::buffer::{BufferAccess, BufferInner};
|
||||
use crate::descriptor_set::layout::{DescriptorDesc, DescriptorType};
|
||||
use crate::descriptor_set::layout::{DescriptorSetLayoutBinding, DescriptorType};
|
||||
use crate::descriptor_set::DescriptorSetLayout;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::image::view::{ImageViewAbstract, ImageViewType};
|
||||
@ -400,8 +400,8 @@ pub(crate) fn check_descriptor_write<'a>(
|
||||
write: &WriteDescriptorSet,
|
||||
layout: &'a DescriptorSetLayout,
|
||||
variable_descriptor_count: u32,
|
||||
) -> Result<&'a DescriptorDesc, DescriptorSetUpdateError> {
|
||||
let layout_binding = match layout.desc().descriptor(write.binding()) {
|
||||
) -> Result<&'a DescriptorSetLayoutBinding, DescriptorSetUpdateError> {
|
||||
let layout_binding = match layout.bindings().get(&write.binding()) {
|
||||
Some(binding) => binding,
|
||||
None => {
|
||||
return Err(DescriptorSetUpdateError::InvalidBinding {
|
||||
@ -410,7 +410,7 @@ pub(crate) fn check_descriptor_write<'a>(
|
||||
}
|
||||
};
|
||||
|
||||
let max_descriptor_count = if layout_binding.variable_count {
|
||||
let max_descriptor_count = if layout_binding.variable_descriptor_count {
|
||||
variable_descriptor_count
|
||||
} else {
|
||||
layout_binding.descriptor_count
|
||||
@ -432,10 +432,9 @@ pub(crate) fn check_descriptor_write<'a>(
|
||||
}
|
||||
|
||||
match elements {
|
||||
WriteDescriptorSetElements::None(num_elements) => match layout_binding.ty {
|
||||
WriteDescriptorSetElements::None(num_elements) => match layout_binding.descriptor_type {
|
||||
DescriptorType::Sampler
|
||||
if layout.desc().is_push_descriptor()
|
||||
&& !layout_binding.immutable_samplers.is_empty() => {}
|
||||
if layout.push_descriptor() && !layout_binding.immutable_samplers.is_empty() => {}
|
||||
_ => {
|
||||
return Err(DescriptorSetUpdateError::IncompatibleDescriptorType {
|
||||
binding: write.binding(),
|
||||
@ -443,7 +442,7 @@ pub(crate) fn check_descriptor_write<'a>(
|
||||
}
|
||||
},
|
||||
WriteDescriptorSetElements::Buffer(elements) => {
|
||||
match layout_binding.ty {
|
||||
match layout_binding.descriptor_type {
|
||||
DescriptorType::StorageBuffer | DescriptorType::StorageBufferDynamic => {
|
||||
for (index, buffer) in elements.iter().enumerate() {
|
||||
assert_eq!(
|
||||
@ -495,7 +494,7 @@ pub(crate) fn check_descriptor_write<'a>(
|
||||
assert!(layout.device().enabled_features().robust_buffer_access);
|
||||
}
|
||||
WriteDescriptorSetElements::BufferView(elements) => {
|
||||
match layout_binding.ty {
|
||||
match layout_binding.descriptor_type {
|
||||
DescriptorType::StorageTexelBuffer => {
|
||||
for (index, buffer_view) in elements.iter().enumerate() {
|
||||
assert_eq!(
|
||||
@ -548,7 +547,7 @@ pub(crate) fn check_descriptor_write<'a>(
|
||||
}
|
||||
}
|
||||
}
|
||||
WriteDescriptorSetElements::ImageView(elements) => match layout_binding.ty {
|
||||
WriteDescriptorSetElements::ImageView(elements) => match layout_binding.descriptor_type {
|
||||
DescriptorType::CombinedImageSampler
|
||||
if !layout_binding.immutable_samplers.is_empty() =>
|
||||
{
|
||||
@ -776,7 +775,9 @@ pub(crate) fn check_descriptor_write<'a>(
|
||||
})
|
||||
}
|
||||
},
|
||||
WriteDescriptorSetElements::ImageViewSampler(elements) => match layout_binding.ty {
|
||||
WriteDescriptorSetElements::ImageViewSampler(elements) => match layout_binding
|
||||
.descriptor_type
|
||||
{
|
||||
DescriptorType::CombinedImageSampler => {
|
||||
if !layout_binding.immutable_samplers.is_empty() {
|
||||
return Err(DescriptorSetUpdateError::SamplerIsImmutable {
|
||||
@ -855,7 +856,7 @@ pub(crate) fn check_descriptor_write<'a>(
|
||||
})
|
||||
}
|
||||
},
|
||||
WriteDescriptorSetElements::Sampler(elements) => match layout_binding.ty {
|
||||
WriteDescriptorSetElements::Sampler(elements) => match layout_binding.descriptor_type {
|
||||
DescriptorType::Sampler => {
|
||||
if !layout_binding.immutable_samplers.is_empty() {
|
||||
return Err(DescriptorSetUpdateError::SamplerIsImmutable {
|
||||
|
@ -22,8 +22,11 @@
|
||||
//! any descriptor sets and/or push constants that the pipeline needs, and then issuing a `dispatch`
|
||||
//! command on the command buffer.
|
||||
|
||||
use super::layout::PipelineLayoutCreateInfo;
|
||||
use crate::check_errors;
|
||||
use crate::descriptor_set::layout::{DescriptorSetDesc, DescriptorSetLayout};
|
||||
use crate::descriptor_set::layout::{
|
||||
DescriptorSetLayout, DescriptorSetLayoutCreateInfo, DescriptorSetLayoutCreationError,
|
||||
};
|
||||
use crate::device::{Device, DeviceOwned};
|
||||
use crate::pipeline::cache::PipelineCache;
|
||||
use crate::pipeline::layout::{
|
||||
@ -74,20 +77,27 @@ impl ComputePipeline {
|
||||
) -> Result<Arc<ComputePipeline>, ComputePipelineCreationError>
|
||||
where
|
||||
Css: SpecializationConstants,
|
||||
F: FnOnce(&mut [DescriptorSetDesc]),
|
||||
F: FnOnce(&mut [DescriptorSetLayoutCreateInfo]),
|
||||
{
|
||||
let mut descriptor_set_layout_descs =
|
||||
DescriptorSetDesc::from_requirements(shader.descriptor_requirements());
|
||||
func(&mut descriptor_set_layout_descs);
|
||||
let descriptor_set_layouts = descriptor_set_layout_descs
|
||||
let mut set_layout_create_infos =
|
||||
DescriptorSetLayoutCreateInfo::from_requirements(shader.descriptor_requirements());
|
||||
func(&mut set_layout_create_infos);
|
||||
let set_layouts = set_layout_create_infos
|
||||
.iter()
|
||||
.map(|desc| Ok(DescriptorSetLayout::new(device.clone(), desc.clone())?))
|
||||
.collect::<Result<Vec<_>, PipelineLayoutCreationError>>()?;
|
||||
.map(|desc| DescriptorSetLayout::new(device.clone(), desc.clone()))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let layout = PipelineLayout::new(
|
||||
device.clone(),
|
||||
descriptor_set_layouts,
|
||||
shader.push_constant_requirements().cloned(),
|
||||
PipelineLayoutCreateInfo {
|
||||
set_layouts,
|
||||
push_constant_ranges: shader
|
||||
.push_constant_requirements()
|
||||
.cloned()
|
||||
.into_iter()
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
|
||||
unsafe {
|
||||
@ -308,6 +318,8 @@ impl Drop for ComputePipeline {
|
||||
pub enum ComputePipelineCreationError {
|
||||
/// Not enough memory.
|
||||
OomError(OomError),
|
||||
/// Error while creating a descriptor set layout object.
|
||||
DescriptorSetLayoutCreationError(DescriptorSetLayoutCreationError),
|
||||
/// Error while creating the pipeline layout object.
|
||||
PipelineLayoutCreationError(PipelineLayoutCreationError),
|
||||
/// The pipeline layout is not compatible with what the shader expects.
|
||||
@ -320,10 +332,11 @@ impl error::Error for ComputePipelineCreationError {
|
||||
#[inline]
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||
match *self {
|
||||
ComputePipelineCreationError::OomError(ref err) => Some(err),
|
||||
ComputePipelineCreationError::PipelineLayoutCreationError(ref err) => Some(err),
|
||||
ComputePipelineCreationError::IncompatiblePipelineLayout(ref err) => Some(err),
|
||||
ComputePipelineCreationError::IncompatibleSpecializationConstants => None,
|
||||
Self::OomError(ref err) => Some(err),
|
||||
Self::DescriptorSetLayoutCreationError(ref err) => Some(err),
|
||||
Self::PipelineLayoutCreationError(ref err) => Some(err),
|
||||
Self::IncompatiblePipelineLayout(ref err) => Some(err),
|
||||
Self::IncompatibleSpecializationConstants => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -336,6 +349,9 @@ impl fmt::Display for ComputePipelineCreationError {
|
||||
"{}",
|
||||
match *self {
|
||||
ComputePipelineCreationError::OomError(_) => "not enough memory available",
|
||||
ComputePipelineCreationError::DescriptorSetLayoutCreationError(_) => {
|
||||
"error while creating a descriptor set layout object"
|
||||
}
|
||||
ComputePipelineCreationError::PipelineLayoutCreationError(_) => {
|
||||
"error while creating the pipeline layout object"
|
||||
}
|
||||
@ -353,21 +369,28 @@ impl fmt::Display for ComputePipelineCreationError {
|
||||
impl From<OomError> for ComputePipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: OomError) -> ComputePipelineCreationError {
|
||||
ComputePipelineCreationError::OomError(err)
|
||||
Self::OomError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DescriptorSetLayoutCreationError> for ComputePipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: DescriptorSetLayoutCreationError) -> Self {
|
||||
Self::DescriptorSetLayoutCreationError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PipelineLayoutCreationError> for ComputePipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: PipelineLayoutCreationError) -> ComputePipelineCreationError {
|
||||
ComputePipelineCreationError::PipelineLayoutCreationError(err)
|
||||
fn from(err: PipelineLayoutCreationError) -> Self {
|
||||
Self::PipelineLayoutCreationError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PipelineLayoutSupersetError> for ComputePipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: PipelineLayoutSupersetError) -> ComputePipelineCreationError {
|
||||
ComputePipelineCreationError::IncompatiblePipelineLayout(err)
|
||||
fn from(err: PipelineLayoutSupersetError) -> Self {
|
||||
Self::IncompatiblePipelineLayout(err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,12 +398,8 @@ impl From<Error> for ComputePipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: Error) -> ComputePipelineCreationError {
|
||||
match err {
|
||||
err @ Error::OutOfHostMemory => {
|
||||
ComputePipelineCreationError::OomError(OomError::from(err))
|
||||
}
|
||||
err @ Error::OutOfDeviceMemory => {
|
||||
ComputePipelineCreationError::OomError(OomError::from(err))
|
||||
}
|
||||
err @ Error::OutOfHostMemory => Self::OomError(OomError::from(err)),
|
||||
err @ Error::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
|
||||
_ => panic!("unexpected error: {:?}", err),
|
||||
}
|
||||
}
|
||||
@ -484,12 +503,7 @@ mod tests {
|
||||
CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), false, 0).unwrap();
|
||||
|
||||
let set = PersistentDescriptorSet::new(
|
||||
pipeline
|
||||
.layout()
|
||||
.descriptor_set_layouts()
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.clone(),
|
||||
pipeline.layout().set_layouts().get(0).unwrap().clone(),
|
||||
[WriteDescriptorSet::buffer(0, data_buffer.clone())],
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -12,7 +12,7 @@
|
||||
#![allow(deprecated)]
|
||||
|
||||
use crate::check_errors;
|
||||
use crate::descriptor_set::layout::{DescriptorSetDesc, DescriptorSetLayout};
|
||||
use crate::descriptor_set::layout::{DescriptorSetLayout, DescriptorSetLayoutCreateInfo};
|
||||
use crate::device::Device;
|
||||
use crate::format::NumericType;
|
||||
use crate::pipeline::cache::PipelineCache;
|
||||
@ -32,7 +32,7 @@ use crate::pipeline::graphics::vertex_input::{
|
||||
};
|
||||
use crate::pipeline::graphics::viewport::{Scissor, Viewport, ViewportState};
|
||||
use crate::pipeline::graphics::{GraphicsPipeline, GraphicsPipelineCreationError};
|
||||
use crate::pipeline::layout::{PipelineLayout, PipelineLayoutCreationError, PipelineLayoutPcRange};
|
||||
use crate::pipeline::layout::{PipelineLayout, PipelineLayoutCreateInfo, PushConstantRange};
|
||||
use crate::pipeline::{DynamicState, PartialStateMode, StateMode};
|
||||
use crate::render_pass::Subpass;
|
||||
use crate::shader::{
|
||||
@ -144,9 +144,9 @@ where
|
||||
func: F,
|
||||
) -> Result<Arc<GraphicsPipeline>, GraphicsPipelineCreationError>
|
||||
where
|
||||
F: FnOnce(&mut [DescriptorSetDesc]),
|
||||
F: FnOnce(&mut [DescriptorSetLayoutCreateInfo]),
|
||||
{
|
||||
let (descriptor_set_layout_descs, push_constant_ranges) = {
|
||||
let (set_layout_create_infos, push_constant_ranges) = {
|
||||
let stages: SmallVec<[&EntryPoint; 5]> = [
|
||||
self.vertex_shader.as_ref().map(|s| &s.0),
|
||||
self.tessellation_shaders.as_ref().map(|s| &s.control.0),
|
||||
@ -186,12 +186,12 @@ where
|
||||
|
||||
// Build a description of a descriptor set layout from the shader requirements, then
|
||||
// feed it to the user-provided closure to allow tweaking.
|
||||
let mut descriptor_set_layout_descs = DescriptorSetDesc::from_requirements(
|
||||
let mut set_layout_create_infos = DescriptorSetLayoutCreateInfo::from_requirements(
|
||||
descriptor_requirements
|
||||
.iter()
|
||||
.map(|(&loc, reqs)| (loc, reqs)),
|
||||
);
|
||||
func(&mut descriptor_set_layout_descs);
|
||||
func(&mut set_layout_create_infos);
|
||||
|
||||
// We want to union each push constant range into a set of ranges that do not have intersecting stage flags.
|
||||
// e.g. The range [0, 16) is either made available to Vertex | Fragment or we only make [0, 16) available to
|
||||
@ -211,23 +211,29 @@ where
|
||||
}
|
||||
let push_constant_ranges: Vec<_> = range_map
|
||||
.iter()
|
||||
.map(|((offset, size), stages)| PipelineLayoutPcRange {
|
||||
.map(|((offset, size), stages)| PushConstantRange {
|
||||
stages: *stages,
|
||||
offset: *offset,
|
||||
size: *size,
|
||||
stages: *stages,
|
||||
})
|
||||
.collect();
|
||||
|
||||
(descriptor_set_layout_descs, push_constant_ranges)
|
||||
(set_layout_create_infos, push_constant_ranges)
|
||||
};
|
||||
|
||||
let descriptor_set_layouts = descriptor_set_layout_descs
|
||||
let set_layouts = set_layout_create_infos
|
||||
.into_iter()
|
||||
.map(|desc| Ok(DescriptorSetLayout::new(device.clone(), desc)?))
|
||||
.collect::<Result<Vec<_>, PipelineLayoutCreationError>>()?;
|
||||
let pipeline_layout =
|
||||
PipelineLayout::new(device.clone(), descriptor_set_layouts, push_constant_ranges)
|
||||
.unwrap();
|
||||
.map(|desc| DescriptorSetLayout::new(device.clone(), desc))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let pipeline_layout = PipelineLayout::new(
|
||||
device.clone(),
|
||||
PipelineLayoutCreateInfo {
|
||||
set_layouts,
|
||||
push_constant_ranges,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
self.with_pipeline_layout(device, pipeline_layout)
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use crate::descriptor_set::layout::DescriptorSetLayoutCreationError;
|
||||
use crate::format::Format;
|
||||
use crate::format::NumericType;
|
||||
use crate::pipeline::graphics::vertex_input::IncompatibleVertexDefinitionError;
|
||||
@ -134,6 +135,9 @@ pub enum GraphicsPipelineCreationError {
|
||||
/// Not enough memory.
|
||||
OomError(OomError),
|
||||
|
||||
/// Error while creating a descriptor set layout object.
|
||||
DescriptorSetLayoutCreationError(DescriptorSetLayoutCreationError),
|
||||
|
||||
/// Error while creating the pipeline layout object.
|
||||
PipelineLayoutCreationError(PipelineLayoutCreationError),
|
||||
|
||||
@ -278,6 +282,10 @@ impl fmt::Display for GraphicsPipelineCreationError {
|
||||
fmt,
|
||||
"not enough memory available",
|
||||
),
|
||||
Self::DescriptorSetLayoutCreationError(_) => write!(
|
||||
fmt,
|
||||
"error while creating a descriptor set layout object",
|
||||
),
|
||||
Self::PipelineLayoutCreationError(_) => write!(
|
||||
fmt,
|
||||
"error while creating the pipeline layout object",
|
||||
@ -341,30 +349,37 @@ impl From<OomError> for GraphicsPipelineCreationError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DescriptorSetLayoutCreationError> for GraphicsPipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: DescriptorSetLayoutCreationError) -> Self {
|
||||
Self::DescriptorSetLayoutCreationError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PipelineLayoutCreationError> for GraphicsPipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: PipelineLayoutCreationError) -> GraphicsPipelineCreationError {
|
||||
fn from(err: PipelineLayoutCreationError) -> Self {
|
||||
Self::PipelineLayoutCreationError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PipelineLayoutSupersetError> for GraphicsPipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: PipelineLayoutSupersetError) -> GraphicsPipelineCreationError {
|
||||
fn from(err: PipelineLayoutSupersetError) -> Self {
|
||||
Self::IncompatiblePipelineLayout(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IncompatibleVertexDefinitionError> for GraphicsPipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: IncompatibleVertexDefinitionError) -> GraphicsPipelineCreationError {
|
||||
fn from(err: IncompatibleVertexDefinitionError) -> Self {
|
||||
Self::IncompatibleVertexDefinition(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for GraphicsPipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: Error) -> GraphicsPipelineCreationError {
|
||||
fn from(err: Error) -> Self {
|
||||
match err {
|
||||
err @ Error::OutOfHostMemory => Self::OomError(OomError::from(err)),
|
||||
err @ Error::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,7 @@
|
||||
//! # let image_data: Vec<u8> = return;
|
||||
//! # let queue: std::sync::Arc<vulkano::device::Queue> = return;
|
||||
//! use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
|
||||
//! use vulkano::descriptor_set::layout::{DescriptorDesc, DescriptorSetLayout, DescriptorSetDesc, DescriptorType};
|
||||
//! use vulkano::descriptor_set::layout::{DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo, DescriptorType};
|
||||
//! use vulkano::format::Format;
|
||||
//! use vulkano::image::{ImmutableImage, ImageCreateFlags, ImageDimensions, ImageUsage, MipmapsCount};
|
||||
//! use vulkano::image::view::ImageView;
|
||||
@ -46,13 +46,18 @@
|
||||
//!
|
||||
//! let descriptor_set_layout = DescriptorSetLayout::new(
|
||||
//! device.clone(),
|
||||
//! DescriptorSetDesc::new([Some(DescriptorDesc {
|
||||
//! ty: DescriptorType::CombinedImageSampler,
|
||||
//! descriptor_count: 1,
|
||||
//! variable_count: false,
|
||||
//! stages: ShaderStage::Fragment.into(),
|
||||
//! immutable_samplers: vec![sampler],
|
||||
//! })]),
|
||||
//! DescriptorSetLayoutCreateInfo {
|
||||
//! bindings: [(
|
||||
//! 0,
|
||||
//! DescriptorSetLayoutBinding {
|
||||
//! stages: ShaderStage::Fragment.into(),
|
||||
//! immutable_samplers: vec![sampler],
|
||||
//! ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::CombinedImageSampler)
|
||||
//! },
|
||||
//! )]
|
||||
//! .into(),
|
||||
//! ..Default::default()
|
||||
//! },
|
||||
//! ).unwrap();
|
||||
//!
|
||||
//! let (image, future) = ImmutableImage::from_iter(
|
||||
|
@ -23,7 +23,7 @@ use crate::device::Device;
|
||||
use crate::format::{Format, NumericType};
|
||||
use crate::image::view::ImageViewType;
|
||||
use crate::pipeline::graphics::input_assembly::PrimitiveTopology;
|
||||
use crate::pipeline::layout::PipelineLayoutPcRange;
|
||||
use crate::pipeline::layout::PushConstantRange;
|
||||
use crate::shader::spirv::{Capability, Spirv, SpirvError};
|
||||
use crate::sync::PipelineStages;
|
||||
use crate::DeviceSize;
|
||||
@ -369,7 +369,7 @@ impl Display for ShaderSupportError {
|
||||
pub struct EntryPointInfo {
|
||||
pub execution: ShaderExecution,
|
||||
pub descriptor_requirements: FnvHashMap<(u32, u32), DescriptorRequirements>,
|
||||
pub push_constant_requirements: Option<PipelineLayoutPcRange>,
|
||||
pub push_constant_requirements: Option<PushConstantRange>,
|
||||
pub specialization_constant_requirements: FnvHashMap<u32, SpecializationConstantRequirements>,
|
||||
pub input_interface: ShaderInterface,
|
||||
pub output_interface: ShaderInterface,
|
||||
@ -417,7 +417,7 @@ impl<'a> EntryPoint<'a> {
|
||||
|
||||
/// Returns the push constant requirements.
|
||||
#[inline]
|
||||
pub fn push_constant_requirements(&self) -> Option<&PipelineLayoutPcRange> {
|
||||
pub fn push_constant_requirements(&self) -> Option<&PushConstantRange> {
|
||||
self.info.push_constant_requirements.as_ref()
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ use crate::image::view::ImageViewType;
|
||||
use crate::shader::ShaderScalarType;
|
||||
use crate::DeviceSize;
|
||||
use crate::{
|
||||
pipeline::layout::PipelineLayoutPcRange,
|
||||
pipeline::layout::PushConstantRange,
|
||||
shader::{
|
||||
spirv::{
|
||||
Capability, Decoration, Dim, ExecutionMode, ExecutionModel, Id, Instruction, Spirv,
|
||||
@ -909,8 +909,8 @@ fn descriptor_requirements_of(spirv: &Spirv, variable_id: Id) -> DescriptorVaria
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts the `PipelineLayoutPcRange` from `spirv`.
|
||||
fn push_constant_requirements(spirv: &Spirv, stage: ShaderStage) -> Option<PipelineLayoutPcRange> {
|
||||
/// Extracts the `PushConstantRange` from `spirv`.
|
||||
fn push_constant_requirements(spirv: &Spirv, stage: ShaderStage) -> Option<PushConstantRange> {
|
||||
spirv
|
||||
.iter_global()
|
||||
.find_map(|instruction| match instruction {
|
||||
@ -927,10 +927,10 @@ fn push_constant_requirements(spirv: &Spirv, stage: ShaderStage) -> Option<Pipel
|
||||
let start = offset_of_struct(spirv, ty);
|
||||
let end =
|
||||
size_of_type(spirv, ty).expect("Found runtime-sized push constants") as u32;
|
||||
Some(PipelineLayoutPcRange {
|
||||
Some(PushConstantRange {
|
||||
stages: stage.into(),
|
||||
offset: start,
|
||||
size: end - start,
|
||||
stages: stage.into(),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
|
Loading…
Reference in New Issue
Block a user