Skip to main content

ursus_core/vulkan/resources/
bindless.rs

1use crate::render::gfx::descriptor::{DescriptorAllocator, DescriptorSetDesc};
2use crate::render::gfx::types::Format;
3use crate::render::gfx::types::{DescriptorSetId, ShaderStage};
4use crate::vulkan::core::{sampler, DeviceContext, SubmitContext};
5use crate::vulkan::resources::texture::TextureSource;
6use crate::vulkan::GpuTexture;
7use ash::vk;
8
9pub const MAX_TEXTURES: u32 = 4096;
10
11pub struct BindlessSet {
12    pub set_id: DescriptorSetId,
13    pub sampler: vk::Sampler,
14    next_slot: u32,
15    owned_textures: Vec<GpuTexture>,
16    device: ash::Device,
17}
18
19impl BindlessSet {
20    pub fn new(
21        device: &ash::Device,
22        physical_device: vk::PhysicalDevice,
23        instance: &ash::Instance,
24        descriptors: &mut DescriptorAllocator,
25        command_pool: vk::CommandPool,
26        queue: vk::Queue,
27    ) -> anyhow::Result<Self> {
28        let max_aniso =
29            unsafe { instance.get_physical_device_properties(physical_device).limits.max_sampler_anisotropy.min(16.0) };
30        let sampler = sampler::create_linear_repeat_aniso_sampler(device, max_aniso)?;
31
32        let desc = DescriptorSetDesc::new()
33            .with_immutable_sampler(0, ShaderStage::Fragment, sampler)
34            .with_bindless_sampled_images(1, ShaderStage::Fragment, MAX_TEXTURES);
35
36        let set_id = descriptors.create_set(desc)?;
37
38        let mut this = Self { set_id, sampler, next_slot: 0, owned_textures: Vec::new(), device: device.clone() };
39
40        let white = GpuTexture::upload(
41            DeviceContext { device, physical_device, instance },
42            SubmitContext { command_pool, queue },
43            TextureSource {
44                pixels: &[255u8, 255, 255, 255],
45                width: 1,
46                height: 1,
47                format: Format::Rgba8Srgb,
48                name: "white_fallback",
49            },
50        )?;
51        let slot = this.alloc_slot(descriptors, white.view);
52        assert_eq!(slot, 0, "white fallback должен быть слотом 0");
53        this.owned_textures.push(white);
54
55        Ok(this)
56    }
57
58    pub fn alloc_slot(&mut self, descriptors: &DescriptorAllocator, view: vk::ImageView) -> u32 {
59        let slot = self.next_slot;
60        assert!(slot < MAX_TEXTURES, "bindless texture array is full");
61        descriptors.write_sampled_image_array(self.set_id, 1, slot, view);
62        self.next_slot += 1;
63        slot
64    }
65
66    pub fn update_slot(&self, descriptors: &DescriptorAllocator, slot: u32, view: vk::ImageView) {
67        assert!(slot < self.next_slot);
68        descriptors.write_sampled_image_array(self.set_id, 1, slot, view);
69    }
70
71    pub fn next_slot(&self) -> u32 {
72        self.next_slot
73    }
74}
75
76impl Drop for BindlessSet {
77    fn drop(&mut self) {
78        unsafe { self.device.destroy_sampler(self.sampler, None) };
79    }
80}