1
0
Fork 0
forked from wry/wry

vulkan: separate images and samplers

This commit is contained in:
Julian Orth 2025-03-03 19:39:47 +01:00
parent 2a5fa4cd1e
commit fdafdf9912
9 changed files with 137 additions and 83 deletions

View file

@ -10,9 +10,8 @@ use {
utils::on_drop::OnDrop,
},
ash::vk::{
DescriptorDataEXT, DescriptorGetInfoEXT, DescriptorImageInfo, DescriptorType, Extent3D,
ImageAspectFlags, ImageCreateInfo, ImageLayout, ImageSubresourceRange, ImageTiling,
ImageType, ImageViewCreateInfo, ImageViewType, SampleCountFlags, SharingMode,
Extent3D, ImageAspectFlags, ImageCreateInfo, ImageLayout, ImageSubresourceRange,
ImageTiling, ImageType, ImageViewCreateInfo, ImageViewType, SampleCountFlags, SharingMode,
},
gpu_alloc::UsageFlags,
std::{any::Any, cell::Cell, collections::hash_map::Entry, rc::Rc},
@ -24,9 +23,9 @@ impl VulkanRenderer {
width: i32,
height: i32,
) -> Result<Rc<VulkanImage>, VulkanError> {
let Some(db) = &self.device.descriptor_buffer else {
if self.device.descriptor_buffer.is_none() {
return Err(VulkanError::NoDescriptorBuffer);
};
}
if width <= 0 || height <= 0 {
return Err(VulkanError::NonPositiveImageSize);
}
@ -90,21 +89,6 @@ impl VulkanRenderer {
};
let view = view.map_err(VulkanError::CreateImageView)?;
destroy_image.forget();
let sampled_image_descriptor = {
let mut buf = vec![0; self.device.sampled_image_descriptor_size].into_boxed_slice();
let image_info = DescriptorImageInfo::default()
.image_view(view)
.image_layout(ImageLayout::SHADER_READ_ONLY_OPTIMAL);
let info = DescriptorGetInfoEXT::default()
.ty(DescriptorType::SAMPLED_IMAGE)
.data(DescriptorDataEXT {
p_sampled_image: &image_info,
});
unsafe {
db.get_descriptor(&info, &mut buf);
}
buf
};
let img = Rc::new(VulkanImage {
renderer: self.clone(),
format: BLEND_FORMAT,
@ -121,8 +105,7 @@ impl VulkanRenderer {
}),
ty: VulkanImageMemory::Blend(allocation),
bridge: None,
shader_read_only_optimal_descriptor: Box::new([]),
sampled_image_descriptor,
sampled_image_descriptor: self.sampled_image_descriptor(view),
descriptor_buffer_version: Default::default(),
descriptor_buffer_offset: Default::default(),
execution_version: Default::default(),

View file

@ -52,12 +52,13 @@ impl VulkanBufferCache {
pub fn for_descriptor_buffer(
device: &Rc<VulkanDevice>,
allocator: &Rc<VulkanAllocator>,
has_sampler: bool,
for_sampler: bool,
) -> Rc<Self> {
let mut usage = BufferUsageFlags::RESOURCE_DESCRIPTOR_BUFFER_EXT
| BufferUsageFlags::SHADER_DEVICE_ADDRESS;
if has_sampler {
let mut usage = BufferUsageFlags::SHADER_DEVICE_ADDRESS;
if for_sampler {
usage |= BufferUsageFlags::SAMPLER_DESCRIPTOR_BUFFER_EXT;
} else {
usage |= BufferUsageFlags::RESOURCE_DESCRIPTOR_BUFFER_EXT;
}
Self::new(device, allocator, usage)
}

View file

@ -30,7 +30,7 @@ impl Drop for VulkanDescriptorSetLayout {
}
impl VulkanDevice {
pub(super) fn create_tex_descriptor_set_layout(
pub(super) fn create_tex_legacy_descriptor_set_layout(
self: &Rc<Self>,
sampler: &Rc<VulkanSampler>,
) -> Result<Rc<VulkanDescriptorSetLayout>, VulkanError> {
@ -40,24 +40,40 @@ impl VulkanDevice {
.immutable_samplers(&immutable_sampler)
.descriptor_count(1)
.descriptor_type(DescriptorType::COMBINED_IMAGE_SAMPLER);
let mut flags = DescriptorSetLayoutCreateFlags::empty();
if self.descriptor_buffer.is_some() {
flags |= DescriptorSetLayoutCreateFlags::DESCRIPTOR_BUFFER_EXT;
} else {
flags |= DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR_KHR;
}
let create_info = DescriptorSetLayoutCreateInfo::default()
.bindings(slice::from_ref(&binding))
.flags(flags);
.flags(DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR_KHR);
let layout = unsafe { self.device.create_descriptor_set_layout(&create_info, None) };
let layout = layout.map_err(VulkanError::CreateDescriptorSetLayout)?;
let mut size = 0;
Ok(Rc::new(VulkanDescriptorSetLayout {
device: self.clone(),
layout,
size: 0,
offsets: Default::default(),
_sampler: Some(sampler.clone()),
}))
}
pub(super) fn create_tex_sampler_descriptor_set_layout(
self: &Rc<Self>,
sampler: &Rc<VulkanSampler>,
) -> Result<Rc<VulkanDescriptorSetLayout>, VulkanError> {
let immutable_sampler = [sampler.sampler];
let binding = DescriptorSetLayoutBinding::default()
.stage_flags(ShaderStageFlags::FRAGMENT)
.immutable_samplers(&immutable_sampler)
.descriptor_count(1)
.descriptor_type(DescriptorType::SAMPLER);
let create_info = DescriptorSetLayoutCreateInfo::default()
.bindings(slice::from_ref(&binding))
.flags(DescriptorSetLayoutCreateFlags::DESCRIPTOR_BUFFER_EXT);
let layout = unsafe { self.device.create_descriptor_set_layout(&create_info, None) };
let layout = layout.map_err(VulkanError::CreateDescriptorSetLayout)?;
let db = self.descriptor_buffer.as_ref().unwrap();
let size = self.get_descriptor_set_size(db, layout);
let mut offsets = ArrayVec::new();
if let Some(db) = &self.descriptor_buffer {
size = self.get_descriptor_set_size(db, layout);
unsafe {
offsets.push(db.get_descriptor_set_layout_binding_offset(layout, 0));
}
unsafe {
offsets.push(db.get_descriptor_set_layout_binding_offset(layout, 0));
}
Ok(Rc::new(VulkanDescriptorSetLayout {
device: self.clone(),
@ -68,6 +84,33 @@ impl VulkanDevice {
}))
}
pub(super) fn create_tex_resource_descriptor_set_layout(
self: &Rc<Self>,
) -> Result<Rc<VulkanDescriptorSetLayout>, VulkanError> {
let binding = DescriptorSetLayoutBinding::default()
.stage_flags(ShaderStageFlags::FRAGMENT)
.descriptor_count(1)
.descriptor_type(DescriptorType::SAMPLED_IMAGE);
let create_info = DescriptorSetLayoutCreateInfo::default()
.bindings(slice::from_ref(&binding))
.flags(DescriptorSetLayoutCreateFlags::DESCRIPTOR_BUFFER_EXT);
let layout = unsafe { self.device.create_descriptor_set_layout(&create_info, None) };
let layout = layout.map_err(VulkanError::CreateDescriptorSetLayout)?;
let db = self.descriptor_buffer.as_ref().unwrap();
let size = self.get_descriptor_set_size(db, layout);
let mut offsets = ArrayVec::new();
unsafe {
offsets.push(db.get_descriptor_set_layout_binding_offset(layout, 0));
}
Ok(Rc::new(VulkanDescriptorSetLayout {
device: self.clone(),
layout,
size,
offsets,
_sampler: None,
}))
}
pub(super) fn create_out_descriptor_set_layout(
self: &Rc<Self>,
db: &descriptor_buffer::Device,

View file

@ -71,7 +71,7 @@ pub struct VulkanDevice {
pub(super) distinct_transfer_queue_family_idx: Option<u32>,
pub(super) transfer_granularity_mask: (u32, u32),
pub(super) descriptor_buffer_offset_mask: DeviceSize,
pub(super) combined_image_sampler_descriptor_size: usize,
pub(super) sampler_descriptor_size: usize,
pub(super) sampled_image_descriptor_size: usize,
}
@ -366,7 +366,7 @@ impl VulkanInstance {
let descriptor_buffer = supports_descriptor_buffer
.then(|| descriptor_buffer::Device::new(&self.instance, &device));
let mut descriptor_buffer_offset_mask = 0;
let mut combined_image_sampler_descriptor_size = 0;
let mut sampler_descriptor_size = 0;
let mut sampled_image_descriptor_size = 0;
if supports_descriptor_buffer {
let mut descriptor_buffer_props =
@ -382,8 +382,7 @@ impl VulkanInstance {
.checked_next_power_of_two()
.unwrap()
- 1;
combined_image_sampler_descriptor_size =
descriptor_buffer_props.combined_image_sampler_descriptor_size;
sampler_descriptor_size = descriptor_buffer_props.sampler_descriptor_size;
sampled_image_descriptor_size = descriptor_buffer_props.sampled_image_descriptor_size;
}
let memory_properties =
@ -422,7 +421,7 @@ impl VulkanInstance {
distinct_transfer_queue_family_idx,
transfer_granularity_mask,
descriptor_buffer_offset_mask,
combined_image_sampler_descriptor_size,
sampler_descriptor_size,
sampled_image_descriptor_size,
blend_limits,
}))

View file

@ -26,7 +26,8 @@ use {
ImagePlaneMemoryRequirementsInfo, ImageSubresourceRange, ImageTiling, ImageType,
ImageUsageFlags, ImageView, ImageViewCreateInfo, ImageViewType, ImportMemoryFdInfoKHR,
MemoryAllocateInfo, MemoryDedicatedAllocateInfo, MemoryFdPropertiesKHR,
MemoryPropertyFlags, MemoryRequirements2, SampleCountFlags, SharingMode, SubresourceLayout,
MemoryPropertyFlags, MemoryRequirements2, SampleCountFlags, Sampler, SharingMode,
SubresourceLayout,
},
gpu_alloc::UsageFlags,
std::{
@ -63,7 +64,6 @@ pub struct VulkanImage {
pub(super) queue_state: Cell<QueueState>,
pub(super) ty: VulkanImageMemory,
pub(super) bridge: Option<VulkanFramebufferBridge>,
pub(super) shader_read_only_optimal_descriptor: Box<[u8]>,
pub(super) sampled_image_descriptor: Box<[u8]>,
pub(super) descriptor_buffer_version: Cell<u64>,
pub(super) descriptor_buffer_offset: Cell<DeviceSize>,
@ -235,21 +235,37 @@ impl VulkanDevice {
}
}
impl VulkanDevice {
pub(super) fn create_sampler_descriptor(&self, sampler: Sampler) -> Box<[u8]> {
let Some(db) = &self.descriptor_buffer else {
return Box::new([]);
};
let mut buf = vec![0; self.sampler_descriptor_size].into_boxed_slice();
let info = DescriptorGetInfoEXT::default()
.ty(DescriptorType::SAMPLER)
.data(DescriptorDataEXT {
p_sampler: &sampler,
});
unsafe {
db.get_descriptor(&info, &mut buf);
}
buf
}
}
impl VulkanRenderer {
pub(super) fn sampler_read_only_descriptor(&self, view: ImageView) -> Box<[u8]> {
pub(super) fn sampled_image_descriptor(&self, view: ImageView) -> Box<[u8]> {
let Some(db) = &self.device.descriptor_buffer else {
return Box::new([]);
};
let mut buf =
vec![0; self.device.combined_image_sampler_descriptor_size].into_boxed_slice();
let mut buf = vec![0; self.device.sampled_image_descriptor_size].into_boxed_slice();
let image_info = DescriptorImageInfo::default()
.sampler(self.sampler.sampler)
.image_view(view)
.image_layout(ImageLayout::SHADER_READ_ONLY_OPTIMAL);
let info = DescriptorGetInfoEXT::default()
.ty(DescriptorType::COMBINED_IMAGE_SAMPLER)
.ty(DescriptorType::SAMPLED_IMAGE)
.data(DescriptorDataEXT {
p_combined_image_sampler: &image_info,
p_sampled_image: &image_info,
});
unsafe {
db.get_descriptor(&info, &mut buf);
@ -450,10 +466,7 @@ impl VulkanDmaBufImageTemplate {
family: QueueFamily::Gfx,
}),
bridge,
shader_read_only_optimal_descriptor: self
.renderer
.sampler_read_only_descriptor(texture_view),
sampled_image_descriptor: Box::new([]),
sampled_image_descriptor: self.renderer.sampled_image_descriptor(texture_view),
descriptor_buffer_version: Cell::new(0),
descriptor_buffer_offset: Cell::new(0),
execution_version: Cell::new(0),

View file

@ -29,7 +29,7 @@ pub(super) struct VulkanPipeline {
pub(super) _frag: Rc<VulkanShader>,
pub(super) pipeline_layout: PipelineLayout,
pub(super) pipeline: Pipeline,
pub(super) _frag_descriptor_set_layout: Option<Rc<VulkanDescriptorSetLayout>>,
pub(super) _descriptor_set_layouts: ArrayVec<Rc<VulkanDescriptorSetLayout>, 2>,
}
pub(super) struct PipelineCreateInfo {
@ -41,7 +41,7 @@ pub(super) struct PipelineCreateInfo {
pub(super) has_alpha_mult: bool,
pub(super) eotf: u32,
pub(super) oetf: u32,
pub(super) frag_descriptor_set_layout: Option<Rc<VulkanDescriptorSetLayout>>,
pub(super) descriptor_set_layouts: ArrayVec<Rc<VulkanDescriptorSetLayout>, 2>,
}
impl VulkanDevice {
@ -67,9 +67,8 @@ impl VulkanDevice {
.size(push_size as u32),
);
}
let mut descriptor_set_layouts = ArrayVec::<_, 1>::new();
descriptor_set_layouts
.extend(info.frag_descriptor_set_layout.as_ref().map(|l| l.layout));
let mut descriptor_set_layouts = ArrayVec::<_, 2>::new();
descriptor_set_layouts.extend(info.descriptor_set_layouts.iter().map(|l| l.layout));
let create_info = PipelineLayoutCreateInfo::default()
.push_constant_ranges(&push_constant_ranges)
.set_layouts(&descriptor_set_layouts);
@ -175,7 +174,7 @@ impl VulkanDevice {
_frag: info.frag,
pipeline_layout,
pipeline,
_frag_descriptor_set_layout: info.frag_descriptor_set_layout,
_descriptor_set_layouts: info.descriptor_set_layouts,
}))
}
}

View file

@ -90,12 +90,13 @@ pub struct VulkanRenderer {
pub(super) tex_frag_shader: Rc<VulkanShader>,
pub(super) out_vert_shader: Rc<VulkanShader>,
pub(super) out_frag_shader: Rc<VulkanShader>,
pub(super) tex_descriptor_set_layout: Rc<VulkanDescriptorSetLayout>,
pub(super) tex_descriptor_set_layouts: ArrayVec<Rc<VulkanDescriptorSetLayout>, 2>,
pub(super) out_descriptor_set_layout: Option<Rc<VulkanDescriptorSetLayout>>,
pub(super) defunct: Cell<bool>,
pub(super) pending_cpu_jobs: CopyHashMap<u64, PendingJob>,
pub(super) shm_allocator: Rc<VulkanThreadedAllocator>,
pub(super) sampler: Rc<VulkanSampler>,
pub(super) _sampler: Rc<VulkanSampler>,
pub(super) sampler_descriptor: Box<[u8]>,
pub(super) sampler_descriptor_buffer_cache: Rc<VulkanBufferCache>,
pub(super) resource_descriptor_buffer_cache: Rc<VulkanBufferCache>,
pub(super) blend_buffers: RefCell<AHashMap<(u32, u32), Weak<VulkanImage>>>,
@ -234,23 +235,28 @@ impl VulkanDevice {
eng: &Rc<AsyncEngine>,
ring: &Rc<IoUring>,
) -> Result<Rc<VulkanRenderer>, VulkanError> {
let sampler = self.create_sampler()?;
let fill_vert_shader;
let fill_frag_shader;
let tex_vert_shader;
let tex_frag_shader;
let mut tex_descriptor_set_layouts = ArrayVec::new();
if self.descriptor_buffer.is_some() {
tex_vert_shader = self.create_shader(TEX_VERT)?;
tex_frag_shader = self.create_shader(TEX_FRAG)?;
fill_vert_shader = self.create_shader(FILL_VERT)?;
fill_frag_shader = self.create_shader(FILL_FRAG)?;
tex_descriptor_set_layouts
.push(self.create_tex_sampler_descriptor_set_layout(&sampler)?);
tex_descriptor_set_layouts.push(self.create_tex_resource_descriptor_set_layout()?);
} else {
tex_vert_shader = self.create_shader(LEGACY_TEX_VERT)?;
tex_frag_shader = self.create_shader(LEGACY_TEX_FRAG)?;
fill_vert_shader = self.create_shader(LEGACY_FILL_VERT)?;
fill_frag_shader = self.create_shader(LEGACY_FILL_FRAG)?;
tex_descriptor_set_layouts
.push(self.create_tex_legacy_descriptor_set_layout(&sampler)?);
}
let sampler = self.create_sampler()?;
let tex_descriptor_set_layout = self.create_tex_descriptor_set_layout(&sampler)?;
let out_descriptor_set_layout = self
.descriptor_buffer
.as_ref()
@ -327,12 +333,13 @@ impl VulkanDevice {
tex_frag_shader,
out_vert_shader,
out_frag_shader,
tex_descriptor_set_layout,
tex_descriptor_set_layouts,
out_descriptor_set_layout,
defunct: Cell::new(false),
pending_cpu_jobs: Default::default(),
shm_allocator,
sampler,
sampler_descriptor: self.create_sampler_descriptor(sampler.sampler),
_sampler: sampler,
sampler_descriptor_buffer_cache,
resource_descriptor_buffer_cache,
blend_buffers: Default::default(),
@ -372,7 +379,7 @@ impl VulkanRenderer {
has_alpha_mult: false,
eotf,
oetf,
frag_descriptor_set_layout: None,
descriptor_set_layouts: Default::default(),
};
self.device.create_pipeline2(info, push_size)
};
@ -393,7 +400,7 @@ impl VulkanRenderer {
has_alpha_mult,
eotf,
oetf,
frag_descriptor_set_layout: Some(self.tex_descriptor_set_layout.clone()),
descriptor_set_layouts: self.tex_descriptor_set_layouts.clone(),
};
self.device.create_pipeline2(info, push_size)
};
@ -438,6 +445,13 @@ impl VulkanRenderer {
let memory = &mut *self.memory.borrow_mut();
let sampler_writer = &mut memory.sampler_descriptor_buffer_writer;
sampler_writer.clear();
{
let mut writer = sampler_writer.add_set(&self.tex_descriptor_set_layouts[0]);
writer.write(
self.tex_descriptor_set_layouts[0].offsets[0],
&self.sampler_descriptor,
);
}
let resource_writer = &mut memory.resource_descriptor_buffer_writer;
resource_writer.clear();
if let Some(bb) = bb {
@ -447,6 +461,7 @@ impl VulkanRenderer {
let mut writer = resource_writer.add_set(layout);
writer.write(layout.offsets[0], &bb.sampled_image_descriptor);
}
let tex_descriptor_set_layout = &self.tex_descriptor_set_layouts[1];
for pass in RenderPass::variants() {
for cmd in &memory.ops[pass] {
let VulkanOp::Tex(c) = cmd else {
@ -456,12 +471,12 @@ impl VulkanRenderer {
if tex.descriptor_buffer_version.replace(version) == version {
continue;
}
let offset = sampler_writer.next_offset();
let offset = resource_writer.next_offset();
tex.descriptor_buffer_offset.set(offset);
let mut writer = sampler_writer.add_set(&self.tex_descriptor_set_layout);
let mut writer = resource_writer.add_set(tex_descriptor_set_layout);
writer.write(
self.tex_descriptor_set_layout.offsets[0],
&tex.shader_read_only_optimal_descriptor,
tex_descriptor_set_layout.offsets[0],
&tex.sampled_image_descriptor,
);
}
}
@ -1018,8 +1033,8 @@ impl VulkanRenderer {
PipelineBindPoint::GRAPHICS,
pipeline.pipeline_layout,
0,
&[0],
&[tex.descriptor_buffer_offset.get()],
&[0, 1],
&[0, tex.descriptor_buffer_offset.get()],
);
dev.cmd_push_constants(
buf,
@ -1102,7 +1117,8 @@ impl VulkanRenderer {
let pipeline = match self.out_pipelines.borrow_mut().entry(fb.format.vk_format) {
Entry::Occupied(pipeline) => pipeline.get().clone(),
Entry::Vacant(e) => {
let layout = self.out_descriptor_set_layout.as_ref().unwrap();
let mut descriptor_set_layouts = ArrayVec::new();
descriptor_set_layouts.push(self.out_descriptor_set_layout.clone().unwrap());
let out = self
.device
.create_pipeline::<OutPushConstants>(PipelineCreateInfo {
@ -1114,7 +1130,7 @@ impl VulkanRenderer {
has_alpha_mult: false,
eotf: TF_LINEAR,
oetf: TF_SRGB,
frag_descriptor_set_layout: Some(layout.clone()),
descriptor_set_layouts,
})?;
e.insert(out.clone());
out

View file

@ -4,12 +4,13 @@
#include "transfer_functions.glsl"
#include "tex.common.glsl"
layout(set = 0, binding = 0) uniform sampler2D tex;
layout(set = 0, binding = 0) uniform sampler sam;
layout(set = 1, binding = 0) uniform texture2D tex;
layout(location = 0) in vec2 tex_pos;
layout(location = 0) out vec4 out_color;
void main() {
vec4 c = textureLod(tex, tex_pos, 0);
vec4 c = textureLod(sampler2D(tex, sam), tex_pos, 0);
if (eotf != oetf) {
if (src_has_alpha) {
c.rgb /= mix(c.a, 1.0, c.a == 0.0);

View file

@ -459,8 +459,7 @@ impl VulkanRenderer {
}),
ty: VulkanImageMemory::Internal(shm),
bridge: None,
shader_read_only_optimal_descriptor: self.sampler_read_only_descriptor(view),
sampled_image_descriptor: Box::new([]),
sampled_image_descriptor: self.sampled_image_descriptor(view),
descriptor_buffer_version: Cell::new(0),
descriptor_buffer_offset: Cell::new(0),
execution_version: Cell::new(0),