From a2d726e50895244d656b67a96f71879ed5c2cfb3 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Mon, 8 Sep 2025 18:26:19 +0200 Subject: [PATCH] vulkan: allow EOTFs to be parametrized --- src/gfx_apis/vulkan/descriptor.rs | 14 ++- src/gfx_apis/vulkan/renderer.rs | 151 +++++++++++++++++++---- src/gfx_apis/vulkan/shaders.rs | 22 ++++ src/gfx_apis/vulkan/shaders/tex_set.glsl | 12 ++ 4 files changed, 174 insertions(+), 25 deletions(-) diff --git a/src/gfx_apis/vulkan/descriptor.rs b/src/gfx_apis/vulkan/descriptor.rs index 87e093ff..66f519d2 100644 --- a/src/gfx_apis/vulkan/descriptor.rs +++ b/src/gfx_apis/vulkan/descriptor.rs @@ -15,7 +15,7 @@ pub(super) struct VulkanDescriptorSetLayout { pub(super) device: Rc, pub(super) layout: DescriptorSetLayout, pub(super) size: DeviceSize, - pub(super) offsets: ArrayVec, + pub(super) offsets: ArrayVec, pub(super) _sampler: Option>, } @@ -98,6 +98,16 @@ impl VulkanDevice { .stage_flags(ShaderStageFlags::FRAGMENT) .descriptor_count(1) .descriptor_type(DescriptorType::UNIFORM_BUFFER), + DescriptorSetLayoutBinding::default() + .binding(2) + .stage_flags(ShaderStageFlags::FRAGMENT) + .descriptor_count(1) + .descriptor_type(DescriptorType::UNIFORM_BUFFER), + DescriptorSetLayoutBinding::default() + .binding(3) + .stage_flags(ShaderStageFlags::FRAGMENT) + .descriptor_count(1) + .descriptor_type(DescriptorType::UNIFORM_BUFFER), ]; let create_info = DescriptorSetLayoutCreateInfo::default() .bindings(&bindings) @@ -110,6 +120,8 @@ impl VulkanDevice { unsafe { offsets.push(db.get_descriptor_set_layout_binding_offset(layout, 0)); offsets.push(db.get_descriptor_set_layout_binding_offset(layout, 1)); + offsets.push(db.get_descriptor_set_layout_binding_offset(layout, 2)); + offsets.push(db.get_descriptor_set_layout_binding_offset(layout, 3)); } Ok(Rc::new(VulkanDescriptorSetLayout { device: self.clone(), diff --git a/src/gfx_apis/vulkan/renderer.rs b/src/gfx_apis/vulkan/renderer.rs index b8455ef2..4531165b 100644 --- a/src/gfx_apis/vulkan/renderer.rs +++ b/src/gfx_apis/vulkan/renderer.rs @@ -25,10 +25,10 @@ use { sampler::VulkanSampler, semaphore::VulkanSemaphore, shaders::{ - ColorManagementData, FILL_FRAG, FILL_VERT, FillPushConstants, LEGACY_FILL_FRAG, - LEGACY_FILL_VERT, LEGACY_TEX_FRAG, LEGACY_TEX_VERT, LegacyFillPushConstants, - LegacyTexPushConstants, OUT_FRAG, OUT_VERT, OutPushConstants, TEX_FRAG, TEX_VERT, - TexPushConstants, TexVertex, VulkanShader, + ColorManagementData, EotfArgs, FILL_FRAG, FILL_VERT, FillPushConstants, + InvEotfArgs, LEGACY_FILL_FRAG, LEGACY_FILL_VERT, LEGACY_TEX_FRAG, LEGACY_TEX_VERT, + LegacyFillPushConstants, LegacyTexPushConstants, OUT_FRAG, OUT_VERT, + OutPushConstants, TEX_FRAG, TEX_VERT, TexPushConstants, TexVertex, VulkanShader, }, }, io_uring::IoUring, @@ -176,10 +176,16 @@ pub(super) struct Memory { data_buffer: Vec, out_address: DeviceAddress, color_transforms: ColorTransforms, + eotf_args_cache: EotfArgsCache, uniform_buffer_writer: GenericBufferWriter, uniform_buffer_descriptor_cache: Option>, + blend_buffer_inv_eotf_args_descriptor: Option>, + fb_inv_eotf_args_descriptor: Option>, blend_buffer_descriptor_buffer_offset: DeviceAddress, blend_buffer_color_management_data_address: Option, + blend_buffer_eotf_args_address: Option, + blend_buffer_inv_eotf_args_address: Option, + fb_inv_eotf_args_address: Option, } type Point = [[f32; 2]; 4]; @@ -202,6 +208,7 @@ struct VulkanTexOp { instances: u32, tex_cd: Rc, color_management_data_address: Option, + eotf_args_address: Option, resource_descriptor_buffer_offset: DeviceAddress, } @@ -352,7 +359,9 @@ impl VulkanDevice { }; let uniform_buffer_cache = { let usage = BufferUsageFlags::SHADER_DEVICE_ADDRESS | BufferUsageFlags::UNIFORM_BUFFER; - let align = align_of::() as DeviceSize; + let align = align_of::() + .max(align_of::()) + .max(align_of::()) as DeviceSize; VulkanBufferCache::new(self, &allocator, usage, align) }; let render = Rc::new(VulkanRenderer { @@ -562,11 +571,14 @@ impl VulkanRenderer { } let resource_writer = &mut memory.resource_descriptor_buffer_writer; resource_writer.clear(); - let uniform_buffer_descriptor_cache = memory - .uniform_buffer_descriptor_cache - .get_or_insert_with(|| { - vec![0u8; self.device.uniform_buffer_descriptor_size].into_boxed_slice() - }); + macro_rules! ub_descriptor_cache { + ($field:ident) => { + memory.$field.get_or_insert_with(|| { + vec![0u8; self.device.uniform_buffer_descriptor_size].into_boxed_slice() + }) + }; + } + let uniform_buffer_descriptor_cache = ub_descriptor_cache!(uniform_buffer_descriptor_cache); macro_rules! get_ub_descriptor { ($addr:expr, $ty:ty, $descriptor:expr $(,)?) => {{ let uniform_buffer = DescriptorAddressInfoEXT::default() @@ -586,6 +598,22 @@ impl VulkanRenderer { get_ub_descriptor!($addr, $ty, uniform_buffer_descriptor_cache) }; } + let mut blend_buffer_inv_eotf_args_descriptor = None; + if let Some(addr) = memory.blend_buffer_inv_eotf_args_address { + blend_buffer_inv_eotf_args_descriptor = Some(get_ub_descriptor!( + addr, + InvEotfArgs, + ub_descriptor_cache!(blend_buffer_inv_eotf_args_descriptor), + )); + } + let mut fb_inv_eotf_args_descriptor = None; + if let Some(addr) = memory.fb_inv_eotf_args_address { + fb_inv_eotf_args_descriptor = Some(get_ub_descriptor!( + addr, + InvEotfArgs, + ub_descriptor_cache!(fb_inv_eotf_args_descriptor), + )); + } if let Some(bb) = bb { let layout = self.out_descriptor_set_layout.as_ref().unwrap(); memory.blend_buffer_descriptor_buffer_offset = resource_writer.next_offset(); @@ -597,9 +625,19 @@ impl VulkanRenderer { get_ub_descriptor!(addr, ColorManagementData), ); } + if let Some(addr) = memory.blend_buffer_eotf_args_address { + writer.write(layout.offsets[2], get_ub_descriptor!(addr, EotfArgs)); + } + if let Some(desc) = fb_inv_eotf_args_descriptor { + writer.write(layout.offsets[3], desc); + } } let tex_descriptor_set_layout = &self.tex_descriptor_set_layouts[1]; for pass in RenderPass::variants() { + let inv_eotf_desc = match pass { + RenderPass::BlendBuffer => blend_buffer_inv_eotf_args_descriptor, + RenderPass::FrameBuffer => fb_inv_eotf_args_descriptor, + }; for cmd in &mut memory.ops[pass] { let VulkanOp::Tex(c) = cmd else { continue; @@ -617,6 +655,15 @@ impl VulkanRenderer { get_ub_descriptor!(addr, ColorManagementData), ); } + if let Some(addr) = c.eotf_args_address { + writer.write( + tex_descriptor_set_layout.offsets[2], + get_ub_descriptor!(addr, EotfArgs), + ); + } + if let Some(desc) = inv_eotf_desc { + writer.write(tex_descriptor_set_layout.offsets[3], desc); + } } } let mut infos = ArrayVec::<_, 2>::new(); @@ -659,6 +706,7 @@ impl VulkanRenderer { memory.data_buffer.clear(); memory.uniform_buffer_writer.clear(); memory.color_transforms.map.clear(); + memory.eotf_args_cache.map.clear(); let sync = |memory: &mut Memory| { for pass in RenderPass::variants() { let ops = &mut memory.ops_tmp[pass]; @@ -813,6 +861,12 @@ impl VulkanRenderer { self.device.uniform_buffer_offset_mask, &mut memory.uniform_buffer_writer, ); + let eotf_args_address = memory.eotf_args_cache.get_offset( + &ct.cd, + false, + self.device.uniform_buffer_offset_mask, + &mut memory.uniform_buffer_writer, + ); ops.push(VulkanOp::Tex(VulkanTexOp { tex: tex.clone(), range: lo..hi, @@ -826,6 +880,7 @@ impl VulkanRenderer { instances: 0, tex_cd: ct.cd.clone(), color_management_data_address, + eotf_args_address, resource_descriptor_buffer_offset: 0, })); } @@ -836,21 +891,41 @@ impl VulkanRenderer { Ok(()) } - fn create_blend_cm_data( + fn create_fixed_cm_data( &self, bb: Option<&VulkanImage>, bb_cd: &ColorDescription, fb_cd: &ColorDescription, ) { - zone!("create_blend_cm_data"); + zone!("create_fixed_cm_data"); let memory = &mut *self.memory.borrow_mut(); memory.blend_buffer_color_management_data_address = None; - if bb.is_none() { - return; + memory.blend_buffer_eotf_args_address = None; + memory.blend_buffer_inv_eotf_args_address = None; + memory.fb_inv_eotf_args_address = None; + if bb.is_some() { + memory.blend_buffer_color_management_data_address = memory.color_transforms.get_offset( + &bb_cd.linear, + fb_cd, + self.device.uniform_buffer_offset_mask, + &mut memory.uniform_buffer_writer, + ); + memory.blend_buffer_eotf_args_address = memory.eotf_args_cache.get_offset( + bb_cd, + false, + self.device.uniform_buffer_offset_mask, + &mut memory.uniform_buffer_writer, + ); + memory.blend_buffer_inv_eotf_args_address = memory.eotf_args_cache.get_offset( + bb_cd, + true, + self.device.uniform_buffer_offset_mask, + &mut memory.uniform_buffer_writer, + ); } - memory.blend_buffer_color_management_data_address = memory.color_transforms.get_offset( - &bb_cd.linear, + memory.fb_inv_eotf_args_address = memory.eotf_args_cache.get_offset( fb_cd, + true, self.device.uniform_buffer_offset_mask, &mut memory.uniform_buffer_writer, ); @@ -912,18 +987,25 @@ impl VulkanRenderer { buffer.buffer.allocation.upload(|ptr, _| unsafe { ptr::copy_nonoverlapping(buf.as_ptr(), ptr, buf.len()); })?; + macro_rules! adj { + ($expr:expr) => { + if let Some(addr) = $expr { + *addr += buffer.buffer.address; + } + }; + } for ops in memory.ops.values_mut() { for op in ops { - if let VulkanOp::Tex(c) = op - && let Some(addr) = &mut c.color_management_data_address - { - *addr += buffer.buffer.address; + if let VulkanOp::Tex(c) = op { + adj!(&mut c.color_management_data_address); + adj!(&mut c.eotf_args_address); } } } - if let Some(addr) = &mut memory.blend_buffer_color_management_data_address { - *addr += buffer.buffer.address; - } + adj!(&mut memory.blend_buffer_color_management_data_address); + adj!(&mut memory.blend_buffer_eotf_args_address); + adj!(&mut memory.blend_buffer_inv_eotf_args_address); + adj!(&mut memory.fb_inv_eotf_args_address); memory.used_buffers.push(buffer); Ok(()) } @@ -1942,7 +2024,7 @@ impl VulkanRenderer { let bb = blend_buffer.as_deref(); let buf = self.gfx_command_buffers.allocate()?; self.convert_ops(opts, bb_cd, fb_cd)?; - self.create_blend_cm_data(bb, bb_cd, fb_cd); + self.create_fixed_cm_data(bb, bb_cd, fb_cd); self.create_data_buffer()?; self.create_uniform_buffer()?; self.collect_memory(); @@ -2242,3 +2324,24 @@ impl ColorTransforms { ct.offset } } + +#[derive(Default)] +struct EotfArgsCache { + map: AHashMap<(), EotfArg>, +} + +struct EotfArg { + _offset: DeviceSize, +} + +impl EotfArgsCache { + fn get_offset( + &mut self, + _desc: &ColorDescription, + _inv: bool, + _uniform_buffer_offset_mask: DeviceSize, + _writer: &mut GenericBufferWriter, + ) -> Option { + None + } +} diff --git a/src/gfx_apis/vulkan/shaders.rs b/src/gfx_apis/vulkan/shaders.rs index de75388d..0e441582 100644 --- a/src/gfx_apis/vulkan/shaders.rs +++ b/src/gfx_apis/vulkan/shaders.rs @@ -69,6 +69,28 @@ pub struct ColorManagementData { unsafe impl Packed for ColorManagementData {} +#[derive(Copy, Clone, Debug)] +#[repr(C, align(16))] +pub struct EotfArgs { + pub arg1: f32, + pub arg2: f32, + pub arg3: f32, + pub arg4: f32, +} + +unsafe impl Packed for EotfArgs {} + +#[derive(Copy, Clone, Debug)] +#[repr(C, align(16))] +pub struct InvEotfArgs { + pub arg1: f32, + pub arg2: f32, + pub arg3: f32, + pub arg4: f32, +} + +unsafe impl Packed for InvEotfArgs {} + #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct LegacyTexPushConstants { diff --git a/src/gfx_apis/vulkan/shaders/tex_set.glsl b/src/gfx_apis/vulkan/shaders/tex_set.glsl index eedfe0ff..7a9f51aa 100644 --- a/src/gfx_apis/vulkan/shaders/tex_set.glsl +++ b/src/gfx_apis/vulkan/shaders/tex_set.glsl @@ -5,5 +5,17 @@ layout(set = TEX_SET, binding = 0) uniform texture2D tex; layout(set = TEX_SET, binding = 1, row_major, std430) uniform ColorManagementData { mat4x4 matrix; } cm_data; +layout(set = TEX_SET, binding = 2, row_major, std430) uniform EotfArgs { + float arg1; + float arg2; + float arg3; + float arg4; +} cm_eotf_args; +layout(set = TEX_SET, binding = 3, row_major, std430) uniform InvEotfArgs { + float arg1; + float arg2; + float arg3; + float arg4; +} cm_inv_eotf_args; #endif