1use super::*;
2
3const DESCRIPTOR_MAX_SIZE: usize = 16;
4
5pub(crate) fn validate_descriptor_sizes(
6 p: &vk::PhysicalDeviceDescriptorBufferPropertiesEXT,
7) -> Result<()> {
8 ensure!(DESCRIPTOR_MAX_SIZE >= p.buffer_capture_replay_descriptor_data_size);
9 ensure!(DESCRIPTOR_MAX_SIZE >= p.image_capture_replay_descriptor_data_size);
10 ensure!(DESCRIPTOR_MAX_SIZE >= p.image_view_capture_replay_descriptor_data_size);
11 ensure!(DESCRIPTOR_MAX_SIZE >= p.sampler_capture_replay_descriptor_data_size);
12 ensure!(DESCRIPTOR_MAX_SIZE >= p.acceleration_structure_capture_replay_descriptor_data_size);
13 ensure!(DESCRIPTOR_MAX_SIZE >= p.sampler_descriptor_size);
14 ensure!(DESCRIPTOR_MAX_SIZE >= p.combined_image_sampler_descriptor_size);
15 ensure!(DESCRIPTOR_MAX_SIZE >= p.sampled_image_descriptor_size);
16 ensure!(DESCRIPTOR_MAX_SIZE >= p.storage_image_descriptor_size);
17 ensure!(DESCRIPTOR_MAX_SIZE >= p.uniform_texel_buffer_descriptor_size);
18 ensure!(DESCRIPTOR_MAX_SIZE >= p.robust_uniform_texel_buffer_descriptor_size);
19 ensure!(DESCRIPTOR_MAX_SIZE >= p.storage_texel_buffer_descriptor_size);
20 ensure!(DESCRIPTOR_MAX_SIZE >= p.robust_storage_texel_buffer_descriptor_size);
21 ensure!(DESCRIPTOR_MAX_SIZE >= p.uniform_buffer_descriptor_size);
22 ensure!(DESCRIPTOR_MAX_SIZE >= p.robust_uniform_buffer_descriptor_size);
23 ensure!(DESCRIPTOR_MAX_SIZE >= p.storage_buffer_descriptor_size);
24 ensure!(DESCRIPTOR_MAX_SIZE >= p.robust_storage_buffer_descriptor_size);
25 ensure!(DESCRIPTOR_MAX_SIZE >= p.input_attachment_descriptor_size);
26 ensure!(DESCRIPTOR_MAX_SIZE >= p.acceleration_structure_descriptor_size);
27 Ok(())
28}
29
30#[derive(Clone, Copy, Debug)]
31pub enum DescriptorCreateInfo {
32 UniformBuffer {
33 address: vk::DeviceAddress,
34 range: vk::DeviceSize,
35 },
36 StorageBuffer {
37 address: vk::DeviceAddress,
38 range: vk::DeviceSize,
39 },
40 SampledImage {
41 image_view: vk::ImageView,
42 image_layout: vk::ImageLayout,
43 },
44 StorageImage {
45 image_view: vk::ImageView,
46 image_layout: vk::ImageLayout,
47 },
48 InputAttachment {
49 image_view: vk::ImageView,
50 image_layout: vk::ImageLayout,
51 },
52 Sampler(vk::Sampler),
53 AccelerationStructure(vk::DeviceAddress),
54}
55
56impl DescriptorCreateInfo {
57 fn size(&self, props: &vk::PhysicalDeviceDescriptorBufferPropertiesEXT) -> usize {
58 match self {
59 DescriptorCreateInfo::UniformBuffer { .. } => props.uniform_buffer_descriptor_size,
60 DescriptorCreateInfo::StorageBuffer { .. } => props.storage_buffer_descriptor_size,
61 DescriptorCreateInfo::SampledImage { .. } => props.sampled_image_descriptor_size,
62 DescriptorCreateInfo::StorageImage { .. } => props.storage_image_descriptor_size,
63 DescriptorCreateInfo::InputAttachment { .. } => props.input_attachment_descriptor_size,
64 DescriptorCreateInfo::Sampler(_) => props.sampler_descriptor_size,
65 DescriptorCreateInfo::AccelerationStructure(_) => {
66 props.acceleration_structure_descriptor_size
67 }
68 }
69 }
70
71 fn ty(&self) -> vk::DescriptorType {
72 match self {
73 DescriptorCreateInfo::UniformBuffer { .. } => vk::DescriptorType::UniformBuffer,
74 DescriptorCreateInfo::StorageBuffer { .. } => vk::DescriptorType::StorageBuffer,
75 DescriptorCreateInfo::SampledImage { .. } => vk::DescriptorType::SampledImage,
76 DescriptorCreateInfo::StorageImage { .. } => vk::DescriptorType::StorageImage,
77 DescriptorCreateInfo::InputAttachment { .. } => vk::DescriptorType::InputAttachment,
78 DescriptorCreateInfo::Sampler(_) => vk::DescriptorType::Sampler,
79 DescriptorCreateInfo::AccelerationStructure(_) => {
80 vk::DescriptorType::AccelerationStructureKHR
81 }
82 }
83 }
84}
85
86type DescriptorData = [u8; DESCRIPTOR_MAX_SIZE];
87
88#[derive(Clone, Copy)]
89pub struct Descriptor {
90 ty: vk::DescriptorType,
91 size: usize,
92 data: DescriptorData,
93}
94
95impl Descriptor {
96 #[must_use]
97 pub unsafe fn create(
98 physical_device: &PhysicalDevice,
99 device: &Device,
100 create_info: DescriptorCreateInfo,
101 ) -> Self {
102 let props = physical_device.descriptor_buffer_properties_ext;
104 let size = create_info.size(&props);
105 let ty = create_info.ty();
106
107 let data = match create_info {
109 DescriptorCreateInfo::UniformBuffer { address, range } => Self::get_descriptor_data(
110 device,
111 ty,
112 size,
113 vk::DescriptorDataEXT {
114 p_uniform_buffer: &vk::DescriptorAddressInfoEXT {
115 s_type: vk::StructureType::DescriptorAddressInfoEXT,
116 p_next: null_mut(),
117 address,
118 range,
119 format: vk::Format::Undefined,
120 },
121 },
122 ),
123 DescriptorCreateInfo::StorageBuffer { address, range } => Self::get_descriptor_data(
124 device,
125 ty,
126 size,
127 vk::DescriptorDataEXT {
128 p_storage_buffer: &vk::DescriptorAddressInfoEXT {
129 s_type: vk::StructureType::DescriptorAddressInfoEXT,
130 p_next: null_mut(),
131 address,
132 range,
133 format: vk::Format::Undefined,
134 },
135 },
136 ),
137 DescriptorCreateInfo::SampledImage {
138 image_view,
139 image_layout,
140 } => Self::get_descriptor_data(
141 device,
142 ty,
143 size,
144 vk::DescriptorDataEXT {
145 p_sampled_image: &vk::DescriptorImageInfo {
146 sampler: vk::Sampler::null(),
147 image_view,
148 image_layout,
149 },
150 },
151 ),
152 DescriptorCreateInfo::StorageImage {
153 image_view,
154 image_layout,
155 } => Self::get_descriptor_data(
156 device,
157 ty,
158 size,
159 vk::DescriptorDataEXT {
160 p_storage_image: &vk::DescriptorImageInfo {
161 sampler: vk::Sampler::null(),
162 image_view,
163 image_layout,
164 },
165 },
166 ),
167 DescriptorCreateInfo::InputAttachment {
168 image_view,
169 image_layout,
170 } => Self::get_descriptor_data(
171 device,
172 ty,
173 size,
174 vk::DescriptorDataEXT {
175 p_input_attachment_image: &vk::DescriptorImageInfo {
176 sampler: vk::Sampler::null(),
177 image_view,
178 image_layout,
179 },
180 },
181 ),
182 DescriptorCreateInfo::Sampler(sampler) => Self::get_descriptor_data(
183 device,
184 ty,
185 size,
186 vk::DescriptorDataEXT {
187 p_sampler: &raw const sampler,
188 },
189 ),
190 DescriptorCreateInfo::AccelerationStructure(acceleration_structure) => {
191 Self::get_descriptor_data(
192 device,
193 ty,
194 size,
195 vk::DescriptorDataEXT {
196 acceleration_structure,
197 },
198 )
199 }
200 };
201
202 Self { ty, size, data }
203 }
204
205 unsafe fn get_descriptor_data(
206 device: &Device,
207 ty: vk::DescriptorType,
208 size: usize,
209 data: vk::DescriptorDataEXT,
210 ) -> DescriptorData {
211 let mut descriptor = MaybeUninit::<DescriptorData>::zeroed();
212 device.get_descriptor_ext(
213 &vk::DescriptorGetInfoEXT {
214 s_type: vk::StructureType::DescriptorGetInfoEXT,
215 p_next: null(),
216 ty,
217 data,
218 },
219 size,
220 descriptor.as_mut_ptr().cast(),
221 );
222 descriptor.assume_init()
223 }
224}
225
226impl std::fmt::Debug for Descriptor {
227 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
228 let slice = &self.data[0..self.size];
229 f.debug_struct("Descriptor")
230 .field("ty", &self.ty)
231 .field("size", &self.size)
232 .field("data", &slice)
233 .finish()
234 }
235}
236
237#[derive(Debug)]
238pub struct DescriptorBinding<'a> {
239 pub ty: vk::DescriptorType,
240 pub stages: vk::ShaderStageFlags,
241 pub descriptors: &'a [Descriptor],
242}
243
244pub struct DescriptorStorage {
245 buffer: vk::Buffer,
246 allocations: BufferAllocations,
247 pub(super) allocation: BufferAllocation,
248 set_layout: vk::DescriptorSetLayout,
249 pub(super) set_count: u32,
250 pub(super) buffer_indices: Vec<u32>,
251 pub(super) offsets: Vec<vk::DeviceSize>,
252 pub(super) push_constant_range: Option<vk::PushConstantRange>,
253 pub(super) pipeline_layout: vk::PipelineLayout,
254 pub(super) usage: vk::BufferUsageFlags,
255}
256
257impl DescriptorStorage {
258 pub unsafe fn create(
259 physical_device: &PhysicalDevice,
260 device: &Device,
261 bindings: &[DescriptorBinding],
262 push_constant_range: Option<vk::PushConstantRange>,
263 ) -> Result<Self> {
264 ensure!(!bindings.is_empty(), "Expected 1 or more bindings");
266 for (binding_index, binding) in bindings.iter().enumerate() {
267 ensure!(
268 !binding.descriptors.is_empty(),
269 "Binding {binding_index} expected 1 or more descriptors",
270 );
271 for descriptor in binding.descriptors {
272 ensure!(
273 binding.ty == descriptor.ty,
274 "Binding {} expected descriptor type to be equal to {:?}, got {:?} instead",
275 binding_index,
276 binding.ty,
277 descriptor.ty
278 );
279 }
280 }
281
282 let set_layout_bindings = bindings
284 .iter()
285 .enumerate()
286 .map(|(binding_index, binding)| vk::DescriptorSetLayoutBinding {
287 binding: binding_index as _,
288 descriptor_type: binding.ty,
289 descriptor_count: binding.descriptors.len() as _,
290 stage_flags: binding.stages,
291 p_immutable_samplers: null(),
292 })
293 .collect::<Vec<_>>();
294 let set_layout =
295 device.create_descriptor_set_layout(&vk::DescriptorSetLayoutCreateInfo {
296 s_type: vk::StructureType::DescriptorSetLayoutCreateInfo,
297 p_next: null(),
298 flags: vk::DescriptorSetLayoutCreateFlagBits::DescriptorBufferEXT.into(),
299 binding_count: set_layout_bindings.len() as _,
300 p_bindings: set_layout_bindings.as_ptr(),
301 })?;
302 let set_count = 1;
303 let buffer_indices = vec![0];
304 let offsets = vec![0];
305 let size = device.get_descriptor_set_layout_size_ext(set_layout);
306
307 let usage = vk::BufferUsageFlagBits::ResourceDescriptorBufferEXT
309 | vk::BufferUsageFlagBits::SamplerDescriptorBufferEXT;
310
311 let (buffer, buffer_create_info) = BufferCreator::new(size, usage)
313 .create(device)
314 .context("Creating buffer object")?;
315
316 let allocations = BufferAllocations::allocate(
318 physical_device,
319 device,
320 &[buffer],
321 &[buffer_create_info],
322 vk::MemoryPropertyFlagBits::HostVisible | vk::MemoryPropertyFlagBits::HostCoherent,
323 )?;
324 let allocation = allocations.allocations()[0];
325
326 for (binding_index, binding) in bindings.iter().enumerate() {
328 let binding_index = binding_index as u32;
329 let descriptor_offset =
330 device.get_descriptor_set_layout_binding_offset_ext(set_layout, binding_index);
331 let descriptor_offset = descriptor_offset as usize;
332 for (array_index, descriptor) in binding.descriptors.iter().enumerate() {
333 let dst_offset = descriptor_offset + array_index * descriptor.size;
334 std::ptr::copy_nonoverlapping(
335 descriptor.data.as_ptr(),
336 allocation.as_mut_ptr::<u8>().add(dst_offset),
337 descriptor.size,
338 );
339 }
340 }
341
342 let pipeline_layout = {
344 let mut create_info = vk::PipelineLayoutCreateInfo {
345 s_type: vk::StructureType::PipelineLayoutCreateInfo,
346 p_next: null(),
347 flags: vk::PipelineLayoutCreateFlags::empty(),
348 set_layout_count: 1,
349 p_set_layouts: &raw const set_layout,
350 push_constant_range_count: 0,
351 p_push_constant_ranges: null(),
352 };
353 let mut pcr: vk::PushConstantRange = zeroed();
354 if let Some(push_constant_range) = &push_constant_range {
355 pcr.stage_flags = push_constant_range.stage_flags;
356 pcr.size = push_constant_range.size;
357 pcr.offset = push_constant_range.offset;
358 create_info.push_constant_range_count = 1;
359 create_info.p_push_constant_ranges = &raw const pcr;
360 }
361 device.create_pipeline_layout(&raw const create_info)?
362 };
363
364 Ok(Self {
365 buffer,
366 allocations,
367 allocation,
368 set_layout,
369 set_count,
370 buffer_indices,
371 offsets,
372 push_constant_range,
373 pipeline_layout,
374 usage,
375 })
376 }
377
378 pub unsafe fn destroy(self, device: &Device) {
379 device.destroy_pipeline_layout(self.pipeline_layout);
380 device.destroy_descriptor_set_layout(self.set_layout);
381 device.destroy_buffer(self.buffer);
382 self.allocations.free(device);
383 }
384
385 pub unsafe fn bind(&self, device: &Device, cmd: vk::CommandBuffer) {
386 device.cmd_bind_descriptor_buffers_ext(
387 cmd,
388 1,
389 &vk::DescriptorBufferBindingInfoEXT {
390 s_type: vk::StructureType::DescriptorBufferBindingInfoEXT,
391 p_next: null_mut(),
392 address: self.allocation.device_address(),
393 usage: self.usage,
394 },
395 );
396 }
397
398 pub unsafe fn set_offsets(
399 &self,
400 device: &Device,
401 cmd: vk::CommandBuffer,
402 pipeline_bind_point: vk::PipelineBindPoint,
403 ) {
404 device.cmd_set_descriptor_buffer_offsets_ext(
405 cmd,
406 pipeline_bind_point,
407 self.pipeline_layout,
408 0,
409 self.set_count,
410 self.buffer_indices.as_ptr(),
411 self.offsets.as_ptr(),
412 );
413 }
414
415 pub unsafe fn push_constants<T>(
416 &self,
417 device: &Device,
418 cmd: vk::CommandBuffer,
419 data: &T,
420 ) -> Result<()> {
421 let Some(pcr) = self.push_constant_range else {
422 bail!("Missing push constant range");
423 };
424 ensure!(pcr.size as usize == size_of::<T>());
425 device.cmd_push_constants(
426 cmd,
427 self.pipeline_layout,
428 pcr.stage_flags,
429 pcr.offset,
430 pcr.size,
431 std::ptr::from_ref::<T>(data).cast(),
432 );
433 Ok(())
434 }
435
436 #[must_use]
437 pub fn pipeline_layout(&self) -> vk::PipelineLayout {
438 self.pipeline_layout
439 }
440
441 #[must_use]
442 pub fn set_layouts(&self) -> &[vk::DescriptorSetLayout] {
443 std::slice::from_ref(&self.set_layout)
444 }
445
446 #[must_use]
447 pub fn push_constant_ranges(&self) -> &[vk::PushConstantRange] {
448 if let Some(pcr) = &self.push_constant_range {
449 std::slice::from_ref(pcr)
450 } else {
451 &[]
452 }
453 }
454}