From f475584f71bf45e073b27825af595eef539a2a1e Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 5 Sep 2025 18:14:00 +0200 Subject: [PATCH] vulkan: support blend buffers having different primaries than framebuffer --- src/gfx_apis/vulkan/descriptor.rs | 27 -------------- src/gfx_apis/vulkan/renderer.rs | 55 +++++++++++++++++++++++++--- src/gfx_apis/vulkan/shaders.rs | 8 ++++ src/gfx_apis/vulkan/shaders/out.frag | 20 +++++++--- 4 files changed, 73 insertions(+), 37 deletions(-) diff --git a/src/gfx_apis/vulkan/descriptor.rs b/src/gfx_apis/vulkan/descriptor.rs index 7d020944..87e093ff 100644 --- a/src/gfx_apis/vulkan/descriptor.rs +++ b/src/gfx_apis/vulkan/descriptor.rs @@ -120,33 +120,6 @@ impl VulkanDevice { })) } - pub(super) fn create_out_descriptor_set_layout( - self: &Rc, - db: &descriptor_buffer::Device, - ) -> Result, 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 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, - })) - } - fn get_descriptor_set_size( &self, db: &descriptor_buffer::Device, diff --git a/src/gfx_apis/vulkan/renderer.rs b/src/gfx_apis/vulkan/renderer.rs index 742722af..1da9e013 100644 --- a/src/gfx_apis/vulkan/renderer.rs +++ b/src/gfx_apis/vulkan/renderer.rs @@ -28,8 +28,8 @@ use { shaders::{ 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, TexColorManagementData, - TexPushConstants, TexVertex, VulkanShader, + OUT_FRAG, OUT_VERT, OutColorManagementData, OutPushConstants, TEX_FRAG, TEX_VERT, + TexColorManagementData, TexPushConstants, TexVertex, VulkanShader, }, }, io_uring::IoUring, @@ -179,6 +179,7 @@ pub(super) struct Memory { uniform_buffer_writer: GenericBufferWriter, uniform_buffer_descriptor_cache: Option>, blend_buffer_descriptor_buffer_offset: DeviceAddress, + blend_buffer_color_management_data_address: Option, } type Point = [[f32; 2]; 4]; @@ -298,7 +299,7 @@ impl VulkanDevice { let out_descriptor_set_layout = self .descriptor_buffer .as_ref() - .map(|db| self.create_out_descriptor_set_layout(db)) + .map(|_| self.create_tex_resource_descriptor_set_layout()) .transpose()?; let gfx_command_buffers = self.create_command_pool(self.graphics_queue_idx)?; let transfer_command_buffers = self @@ -502,6 +503,7 @@ impl VulkanRenderer { format: vk::Format, bb_cd: &ColorDescription, fb_cd: &ColorDescription, + has_color_management_data: bool, ) -> Result, VulkanError> { let key = OutPipelineKey { format, @@ -525,7 +527,7 @@ impl VulkanRenderer { eotf: key.eotf.to_vulkan(), inv_eotf: fb_cd.eotf.to_vulkan(), descriptor_set_layouts, - has_color_management_data: false, + has_color_management_data, })?; pipelines.set(key, out.clone()); Ok(out) @@ -566,6 +568,20 @@ impl VulkanRenderer { memory.blend_buffer_descriptor_buffer_offset = resource_writer.next_offset(); let mut writer = resource_writer.add_set(layout); writer.write(layout.offsets[0], &bb.sampled_image_descriptor); + if let Some(addr) = memory.blend_buffer_color_management_data_address { + let uniform_buffer = DescriptorAddressInfoEXT::default() + .address(addr) + .range(size_of::() as _); + let info = DescriptorGetInfoEXT::default() + .ty(DescriptorType::UNIFORM_BUFFER) + .data(DescriptorDataEXT { + p_uniform_buffer: &uniform_buffer, + }); + unsafe { + db.get_descriptor(&info, uniform_buffer_descriptor_cache); + } + writer.write(layout.offsets[1], uniform_buffer_descriptor_cache); + } } let tex_descriptor_set_layout = &self.tex_descriptor_set_layouts[1]; for pass in RenderPass::variants() { @@ -816,6 +832,26 @@ impl VulkanRenderer { Ok(()) } + fn create_blend_cm_data( + &self, + bb: Option<&VulkanImage>, + bb_cd: &ColorDescription, + fb_cd: &ColorDescription, + ) { + zone!("create_blend_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_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, + ); + } + fn create_data_buffer(&self) -> Result<(), VulkanError> { if self.device.descriptor_buffer.is_none() { return Ok(()); @@ -881,6 +917,9 @@ impl VulkanRenderer { } } } + if let Some(addr) = &mut memory.blend_buffer_color_management_data_address { + *addr += buffer.buffer.address; + } memory.used_buffers.push(buffer); Ok(()) } @@ -1297,7 +1336,12 @@ impl VulkanRenderer { zone!("blend_buffer_copy"); let memory = &*self.memory.borrow(); let db = self.device.descriptor_buffer.as_ref().unwrap(); - let pipeline = self.get_or_create_out_pipeline(fb.format.vk_format, bb_cd, fb_cd)?; + let pipeline = self.get_or_create_out_pipeline( + fb.format.vk_format, + bb_cd, + fb_cd, + memory.blend_buffer_color_management_data_address.is_some(), + )?; let push = OutPushConstants { vertices: memory.out_address, }; @@ -1879,6 +1923,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_data_buffer()?; self.create_uniform_buffer()?; self.collect_memory(); diff --git a/src/gfx_apis/vulkan/shaders.rs b/src/gfx_apis/vulkan/shaders.rs index be199c8a..74ef9031 100644 --- a/src/gfx_apis/vulkan/shaders.rs +++ b/src/gfx_apis/vulkan/shaders.rs @@ -69,6 +69,14 @@ pub struct TexColorManagementData { unsafe impl Packed for TexColorManagementData {} +#[derive(Copy, Clone, Debug)] +#[repr(C, align(16))] +pub struct OutColorManagementData { + pub matrix: [[f32; 4]; 4], +} + +unsafe impl Packed for OutColorManagementData {} + #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct LegacyTexPushConstants { diff --git a/src/gfx_apis/vulkan/shaders/out.frag b/src/gfx_apis/vulkan/shaders/out.frag index 19377bb9..d5df53e0 100644 --- a/src/gfx_apis/vulkan/shaders/out.frag +++ b/src/gfx_apis/vulkan/shaders/out.frag @@ -1,20 +1,30 @@ #version 450 + #extension GL_EXT_samplerless_texture_functions : require +#extension GL_EXT_scalar_block_layout : require #include "frag_spec_const.glsl" #include "eotfs.glsl" #include "out.common.glsl" layout(set = 0, binding = 0) uniform texture2D in_color; +layout(set = 0, binding = 1, row_major, std430) uniform ColorManagementData { + mat4x4 matrix; +} cm_data; layout(location = 0) out vec4 out_color; void main() { vec4 c = texelFetch(in_color, ivec2(gl_FragCoord.xy), 0); - if (eotf != inv_eotf) { - c.rgb /= mix(c.a, 1.0, c.a == 0.0); - c.rgb = apply_eotf(c.rgb); - c.rgb = apply_inv_eotf(c.rgb); - c.rgb *= c.a; + if (eotf != inv_eotf || has_matrix) { + vec3 rgb = c.rgb; + rgb /= mix(c.a, 1.0, c.a == 0.0); + rgb = apply_eotf(rgb); + if (has_matrix) { + rgb = (cm_data.matrix * vec4(rgb, 1.0)).rgb; + } + rgb = apply_inv_eotf(rgb); + rgb *= c.a; + c.rgb = rgb; } out_color = c; }