From 8e65de91f9f7140814cf3edd9d72e4a714c11c97 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 1 Mar 2025 19:19:27 +0100 Subject: [PATCH] vulkan: apply color space transforms to textures --- src/cmm/cmm_transform.rs | 1 - src/gfx_apis/vulkan/blend_buffer.rs | 2 - src/gfx_apis/vulkan/buffer_cache.rs | 52 +++++- src/gfx_apis/vulkan/descriptor.rs | 21 ++- src/gfx_apis/vulkan/device.rs | 22 ++- src/gfx_apis/vulkan/image.rs | 8 +- src/gfx_apis/vulkan/pipeline.rs | 6 +- src/gfx_apis/vulkan/renderer.rs | 156 ++++++++++++++---- src/gfx_apis/vulkan/shaders.rs | 8 + .../vulkan/shaders/frag_spec_const.glsl | 1 + src/gfx_apis/vulkan/shaders/tex.frag | 20 ++- src/gfx_apis/vulkan/shm_image.rs | 2 - 12 files changed, 233 insertions(+), 66 deletions(-) diff --git a/src/cmm/cmm_transform.rs b/src/cmm/cmm_transform.rs index c175caef..898f060a 100644 --- a/src/cmm/cmm_transform.rs +++ b/src/cmm/cmm_transform.rs @@ -157,7 +157,6 @@ impl ColorMatrix { Self(m, PhantomData) } - #[expect(dead_code)] pub const fn to_f32(&self) -> [[f32; 4]; 4] { let m = &self.0; macro_rules! map { diff --git a/src/gfx_apis/vulkan/blend_buffer.rs b/src/gfx_apis/vulkan/blend_buffer.rs index cc1213e8..5845453c 100644 --- a/src/gfx_apis/vulkan/blend_buffer.rs +++ b/src/gfx_apis/vulkan/blend_buffer.rs @@ -106,8 +106,6 @@ impl VulkanRenderer { ty: VulkanImageMemory::Blend(allocation), bridge: None, sampled_image_descriptor: self.sampled_image_descriptor(view), - descriptor_buffer_version: Default::default(), - descriptor_buffer_offset: Default::default(), execution_version: Default::default(), }); cached.insert_entry(Rc::downgrade(&img)); diff --git a/src/gfx_apis/vulkan/buffer_cache.rs b/src/gfx_apis/vulkan/buffer_cache.rs index dec2b0e8..58d43a01 100644 --- a/src/gfx_apis/vulkan/buffer_cache.rs +++ b/src/gfx_apis/vulkan/buffer_cache.rs @@ -12,7 +12,8 @@ use { DeviceSize, }, gpu_alloc::UsageFlags, - std::{cell::RefCell, mem::ManuallyDrop, rc::Rc}, + std::{cell::RefCell, mem::ManuallyDrop, ops::Deref, rc::Rc}, + uapi::Packed, }; pub struct VulkanBufferCache { @@ -20,6 +21,7 @@ pub struct VulkanBufferCache { allocator: Rc, buffers: RefCell>, usage: BufferUsageFlags, + min_alignment: DeviceSize, } pub struct VulkanBuffer { @@ -40,12 +42,14 @@ impl VulkanBufferCache { device: &Rc, allocator: &Rc, usage: BufferUsageFlags, + min_alignment: DeviceSize, ) -> Rc { Rc::new(Self { device: device.clone(), allocator: allocator.clone(), buffers: Default::default(), usage, + min_alignment, }) } @@ -55,25 +59,27 @@ impl VulkanBufferCache { for_sampler: bool, ) -> Rc { let mut usage = BufferUsageFlags::SHADER_DEVICE_ADDRESS; + let mut min_alignment = 1; if for_sampler { usage |= BufferUsageFlags::SAMPLER_DESCRIPTOR_BUFFER_EXT; } else { usage |= BufferUsageFlags::RESOURCE_DESCRIPTOR_BUFFER_EXT; + if device.is_anv { + // https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33903 + min_alignment = 4096; + } } - Self::new(device, allocator, usage) + Self::new(device, allocator, usage, min_alignment) } pub fn usage(&self) -> BufferUsageFlags { self.usage } - pub fn allocate( - self: &Rc, - capacity: DeviceSize, - align: DeviceSize, - ) -> Result { + pub fn allocate(self: &Rc, capacity: DeviceSize) -> Result { const MIN_ALLOCATION: DeviceSize = 1024; - let capacity = (capacity.max(MIN_ALLOCATION) + align - 1) & !(align - 1); + let align_mask = self.min_alignment - 1; + let capacity = (capacity.max(MIN_ALLOCATION) + align_mask) & !align_mask; let mut smallest = None; let mut smallest_size = DeviceSize::MAX; let mut fitting = None; @@ -116,7 +122,7 @@ impl VulkanBufferCache { let destroy_buffer = OnDrop(|| unsafe { self.device.device.destroy_buffer(buffer, None) }); let mut memory_requirements = unsafe { self.device.device.get_buffer_memory_requirements(buffer) }; - memory_requirements.alignment = memory_requirements.alignment.max(align); + memory_requirements.alignment = memory_requirements.alignment.max(self.min_alignment); let allocation = { let flags = UsageFlags::UPLOAD | UsageFlags::FAST_DEVICE_ACCESS @@ -162,3 +168,31 @@ impl Drop for VulkanBufferUnused { } } } + +#[derive(Default)] +pub struct GenericBufferWriter { + buf: Vec, +} + +impl GenericBufferWriter { + pub fn clear(&mut self) { + self.buf.clear(); + } + + pub fn write(&mut self, offset_mask: DeviceSize, data: &(impl Packed + ?Sized)) -> DeviceSize { + let mut offset = self.buf.len() as DeviceSize; + let mask = offset_mask | (align_of_val(data) as DeviceSize - 1); + offset = (offset + mask) & !mask; + self.buf.resize(offset as usize, 0); + self.buf.extend_from_slice(uapi::as_bytes(data)); + offset + } +} + +impl Deref for GenericBufferWriter { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &self.buf + } +} diff --git a/src/gfx_apis/vulkan/descriptor.rs b/src/gfx_apis/vulkan/descriptor.rs index 9f78e8d3..7d020944 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>, } @@ -87,12 +87,20 @@ impl VulkanDevice { pub(super) fn create_tex_resource_descriptor_set_layout( self: &Rc, ) -> Result, VulkanError> { - let binding = DescriptorSetLayoutBinding::default() - .stage_flags(ShaderStageFlags::FRAGMENT) - .descriptor_count(1) - .descriptor_type(DescriptorType::SAMPLED_IMAGE); + let bindings = [ + DescriptorSetLayoutBinding::default() + .binding(0) + .stage_flags(ShaderStageFlags::FRAGMENT) + .descriptor_count(1) + .descriptor_type(DescriptorType::SAMPLED_IMAGE), + DescriptorSetLayoutBinding::default() + .binding(1) + .stage_flags(ShaderStageFlags::FRAGMENT) + .descriptor_count(1) + .descriptor_type(DescriptorType::UNIFORM_BUFFER), + ]; let create_info = DescriptorSetLayoutCreateInfo::default() - .bindings(slice::from_ref(&binding)) + .bindings(&bindings) .flags(DescriptorSetLayoutCreateFlags::DESCRIPTOR_BUFFER_EXT); let layout = unsafe { self.device.create_descriptor_set_layout(&create_info, None) }; let layout = layout.map_err(VulkanError::CreateDescriptorSetLayout)?; @@ -101,6 +109,7 @@ impl VulkanDevice { let mut offsets = ArrayVec::new(); unsafe { offsets.push(db.get_descriptor_set_layout_binding_offset(layout, 0)); + offsets.push(db.get_descriptor_set_layout_binding_offset(layout, 1)); } Ok(Rc::new(VulkanDescriptorSetLayout { device: self.clone(), diff --git a/src/gfx_apis/vulkan/device.rs b/src/gfx_apis/vulkan/device.rs index be2471d6..976af41b 100644 --- a/src/gfx_apis/vulkan/device.rs +++ b/src/gfx_apis/vulkan/device.rs @@ -37,8 +37,9 @@ use { PhysicalDeviceDrmPropertiesEXT, PhysicalDeviceDynamicRenderingFeatures, PhysicalDeviceExternalSemaphoreInfo, PhysicalDeviceProperties, PhysicalDeviceProperties2, PhysicalDeviceSynchronization2Features, - PhysicalDeviceTimelineSemaphoreFeatures, PhysicalDeviceVulkan12Properties, Queue, - QueueFlags, + PhysicalDeviceTimelineSemaphoreFeatures, + PhysicalDeviceUniformBufferStandardLayoutFeatures, PhysicalDeviceVulkan12Properties, + Queue, QueueFlags, }, }, isnt::std_1::collections::IsntHashMap2Ext, @@ -75,6 +76,8 @@ pub struct VulkanDevice { pub(super) sampler_descriptor_size: usize, pub(super) sampled_image_descriptor_size: usize, pub(super) is_anv: bool, + pub(super) uniform_buffer_offset_mask: DeviceSize, + pub(super) uniform_buffer_descriptor_size: usize, } impl Drop for VulkanDevice { @@ -308,6 +311,9 @@ impl VulkanInstance { PhysicalDeviceDescriptorBufferFeaturesEXT::default().descriptor_buffer(true); let mut buffer_device_address_features = PhysicalDeviceBufferDeviceAddressFeatures::default().buffer_device_address(true); + let mut uniform_buffer_standard_layout_features = + PhysicalDeviceUniformBufferStandardLayoutFeatures::default() + .uniform_buffer_standard_layout(true); let mut queue_create_infos = ArrayVec::<_, 2>::new(); queue_create_infos.push( DeviceQueueCreateInfo::default() @@ -325,6 +331,7 @@ impl VulkanInstance { .push_next(&mut semaphore_features) .push_next(&mut synchronization2_features) .push_next(&mut dynamic_rendering_features) + .push_next(&mut uniform_buffer_standard_layout_features) .queue_create_infos(&queue_create_infos) .enabled_extension_names(&enabled_extensions); if supports_descriptor_buffer { @@ -382,6 +389,14 @@ impl VulkanInstance { let mut descriptor_buffer_offset_mask = 0; let mut sampler_descriptor_size = 0; let mut sampled_image_descriptor_size = 0; + let mut uniform_buffer_descriptor_size = 0; + let uniform_buffer_offset_mask = physical_device_properties2 + .properties + .limits + .min_uniform_buffer_offset_alignment + .checked_next_power_of_two() + .unwrap() + - 1; if supports_descriptor_buffer { descriptor_buffer_offset_mask = descriptor_buffer_props .descriptor_buffer_offset_alignment @@ -390,6 +405,7 @@ impl VulkanInstance { - 1; sampler_descriptor_size = descriptor_buffer_props.sampler_descriptor_size; sampled_image_descriptor_size = descriptor_buffer_props.sampled_image_descriptor_size; + uniform_buffer_descriptor_size = descriptor_buffer_props.uniform_buffer_descriptor_size; } let memory_properties = unsafe { self.instance.get_physical_device_memory_properties(phy_dev) }; @@ -432,6 +448,8 @@ impl VulkanInstance { blend_limits, is_anv: physical_device_vulkan12_properties.driver_id == DriverId::INTEL_OPEN_SOURCE_MESA, + uniform_buffer_offset_mask, + uniform_buffer_descriptor_size, })) } } diff --git a/src/gfx_apis/vulkan/image.rs b/src/gfx_apis/vulkan/image.rs index c0cab9f3..ab49b254 100644 --- a/src/gfx_apis/vulkan/image.rs +++ b/src/gfx_apis/vulkan/image.rs @@ -21,8 +21,8 @@ use { ash::vk::{ BindImageMemoryInfo, BindImagePlaneMemoryInfo, ComponentMapping, ComponentSwizzle, DescriptorDataEXT, DescriptorGetInfoEXT, DescriptorImageInfo, DescriptorType, DeviceMemory, - DeviceSize, Extent3D, ExternalMemoryHandleTypeFlags, ExternalMemoryImageCreateInfo, - FormatFeatureFlags, Image, ImageAspectFlags, ImageCreateFlags, ImageCreateInfo, + Extent3D, ExternalMemoryHandleTypeFlags, ExternalMemoryImageCreateInfo, FormatFeatureFlags, + Image, ImageAspectFlags, ImageCreateFlags, ImageCreateInfo, ImageDrmFormatModifierExplicitCreateInfoEXT, ImageLayout, ImageMemoryRequirementsInfo2, ImagePlaneMemoryRequirementsInfo, ImageSubresourceRange, ImageTiling, ImageType, ImageUsageFlags, ImageView, ImageViewCreateInfo, ImageViewType, ImportMemoryFdInfoKHR, @@ -66,8 +66,6 @@ pub struct VulkanImage { pub(super) ty: VulkanImageMemory, pub(super) bridge: Option, pub(super) sampled_image_descriptor: Box<[u8]>, - pub(super) descriptor_buffer_version: Cell, - pub(super) descriptor_buffer_offset: Cell, pub(super) execution_version: Cell, } @@ -468,8 +466,6 @@ impl VulkanDmaBufImageTemplate { }), bridge, 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), })) } diff --git a/src/gfx_apis/vulkan/pipeline.rs b/src/gfx_apis/vulkan/pipeline.rs index 30804a47..d0fc3073 100644 --- a/src/gfx_apis/vulkan/pipeline.rs +++ b/src/gfx_apis/vulkan/pipeline.rs @@ -42,6 +42,7 @@ pub(super) struct PipelineCreateInfo { pub(super) eotf: u32, pub(super) oetf: u32, pub(super) descriptor_set_layouts: ArrayVec, 2>, + pub(super) has_color_management_data: bool, } impl VulkanDevice { @@ -77,8 +78,8 @@ impl VulkanDevice { }; let destroy_layout = OnDrop(|| unsafe { self.device.destroy_pipeline_layout(pipeline_layout, None) }); - let mut frag_spec_data = ArrayVec::<_, { 4 * 4 }>::new(); - let mut frag_spec_entries = ArrayVec::<_, 4>::new(); + let mut frag_spec_data = ArrayVec::<_, { 5 * 4 }>::new(); + let mut frag_spec_entries = ArrayVec::<_, 5>::new(); let mut frag_spec_entry = |data: &[u8]| { let entry = SpecializationMapEntry::default() .constant_id(frag_spec_entries.len() as _) @@ -91,6 +92,7 @@ impl VulkanDevice { frag_spec_entry(&(info.has_alpha_mult as u32).to_ne_bytes()); frag_spec_entry(&info.eotf.to_ne_bytes()); frag_spec_entry(&info.oetf.to_ne_bytes()); + frag_spec_entry(&(info.has_color_management_data as u32).to_ne_bytes()); let frag_spec = SpecializationInfo::default() .map_entries(&frag_spec_entries) .data(&frag_spec_data); diff --git a/src/gfx_apis/vulkan/renderer.rs b/src/gfx_apis/vulkan/renderer.rs index 2886cb7f..bdc873be 100644 --- a/src/gfx_apis/vulkan/renderer.rs +++ b/src/gfx_apis/vulkan/renderer.rs @@ -14,7 +14,7 @@ use { gfx_apis::vulkan::{ VulkanError, allocator::{VulkanAllocator, VulkanThreadedAllocator}, - buffer_cache::{VulkanBuffer, VulkanBufferCache}, + buffer_cache::{GenericBufferWriter, VulkanBuffer, VulkanBufferCache}, command::{VulkanCommandBuffer, VulkanCommandPool}, descriptor::VulkanDescriptorSetLayout, descriptor_buffer::VulkanDescriptorBufferWriter, @@ -27,8 +27,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, TexPushConstants, - TexVertex, VulkanShader, + OUT_FRAG, OUT_VERT, OutPushConstants, TEX_FRAG, TEX_VERT, TexColorManagementData, + TexPushConstants, TexVertex, VulkanShader, }, transfer_functions::{TF_LINEAR, TransferFunctionExt}, }, @@ -46,9 +46,10 @@ use { self, AccessFlags2, AttachmentLoadOp, AttachmentStoreOp, BufferUsageFlags, ClearAttachment, ClearColorValue, ClearRect, ClearValue, CommandBuffer, CommandBufferBeginInfo, CommandBufferSubmitInfo, CommandBufferUsageFlags, - CopyImageInfo2, DependencyInfoKHR, DescriptorBufferBindingInfoEXT, DescriptorImageInfo, - DescriptorType, DeviceAddress, DeviceSize, Extent2D, Extent3D, ImageAspectFlags, - ImageCopy2, ImageLayout, ImageMemoryBarrier2, ImageSubresourceLayers, + CopyImageInfo2, DependencyInfoKHR, DescriptorAddressInfoEXT, + DescriptorBufferBindingInfoEXT, DescriptorDataEXT, DescriptorGetInfoEXT, + DescriptorImageInfo, DescriptorType, DeviceAddress, DeviceSize, Extent2D, Extent3D, + ImageAspectFlags, ImageCopy2, ImageLayout, ImageMemoryBarrier2, ImageSubresourceLayers, ImageSubresourceRange, Offset2D, Offset3D, PipelineBindPoint, PipelineStageFlags2, QUEUE_FAMILY_FOREIGN_EXT, Rect2D, RenderingAttachmentInfo, RenderingInfo, SemaphoreSubmitInfo, SemaphoreSubmitInfoKHR, ShaderStageFlags, SubmitInfo2, Viewport, @@ -108,6 +109,7 @@ pub struct VulkanRenderer { pub(super) resource_descriptor_buffer_cache: Rc, pub(super) blend_buffers: RefCell>>, pub(super) shader_buffer_cache: Rc, + pub(super) uniform_buffer_cache: Rc, } pub(super) struct CachedCommandBuffers { @@ -159,7 +161,7 @@ pub(super) struct Memory { wait_semaphore_infos: Vec>, release_fence: Option>, release_sync_file: Option, - used_buffers: ArrayVec, + used_buffers: ArrayVec, paint_bounds: StaticMap>, paint_regions: StaticMap>, clear_rects: StaticMap>, @@ -175,6 +177,9 @@ pub(super) struct Memory { data_buffer: Vec, out_address: DeviceAddress, color_transforms: ColorTransforms, + uniform_buffer_writer: GenericBufferWriter, + uniform_buffer_descriptor_cache: Option>, + blend_buffer_descriptor_buffer_offset: DeviceAddress, } type Point = [[f32; 2]; 4]; @@ -196,6 +201,8 @@ struct VulkanTexOp { range_address: DeviceAddress, instances: u32, tex_cd: Rc, + color_management_data_address: Option, + resource_descriptor_buffer_offset: DeviceAddress, } struct VulkanFillOp { @@ -230,7 +237,7 @@ pub(super) struct PendingFrame { wait_semaphores: Cell>>, waiter: Cell>>, _release_fence: Option>, - _used_buffers: ArrayVec, + _used_buffers: ArrayVec, } type FillPipelines = Rc>>; @@ -240,6 +247,7 @@ struct TexPipelineKey { tex_copy_type: TexCopyType, tex_source_type: TexSourceType, eotf: TransferFunction, + has_color_management_data: bool, } pub(super) struct TexPipelines { @@ -338,7 +346,13 @@ impl VulkanDevice { let shader_buffer_cache = { // TODO: https://github.com/KhronosGroup/Vulkan-Samples/issues/1286 let usage = BufferUsageFlags::SHADER_DEVICE_ADDRESS | BufferUsageFlags::STORAGE_BUFFER; - VulkanBufferCache::new(self, &allocator, usage) + let align = 8; + VulkanBufferCache::new(self, &allocator, usage, align) + }; + let uniform_buffer_cache = { + let usage = BufferUsageFlags::SHADER_DEVICE_ADDRESS | BufferUsageFlags::UNIFORM_BUFFER; + let align = align_of::() as DeviceSize; + VulkanBufferCache::new(self, &allocator, usage, align) }; let render = Rc::new(VulkanRenderer { formats: Rc::new(formats), @@ -374,6 +388,7 @@ impl VulkanDevice { resource_descriptor_buffer_cache, blend_buffers: Default::default(), shader_buffer_cache, + uniform_buffer_cache, }); Ok(render) } @@ -404,6 +419,7 @@ impl VulkanRenderer { eotf: TF_LINEAR, oetf: TF_LINEAR, descriptor_set_layouts: Default::default(), + has_color_management_data: false, }; self.device.create_pipeline2(info, push_size) }; @@ -441,11 +457,13 @@ impl VulkanRenderer { tex_cd: &ColorDescription, tex_copy_type: TexCopyType, tex_source_type: TexSourceType, + has_color_management_data: bool, ) -> Result, VulkanError> { let key = TexPipelineKey { tex_copy_type, tex_source_type, eotf: tex_cd.transfer_function, + has_color_management_data, }; if let Some(pl) = pipelines.pipelines.get(&key) { return Ok(pl); @@ -473,6 +491,7 @@ impl VulkanRenderer { eotf: key.eotf.to_vulkan(), oetf: pipelines.oetf.to_vulkan(), descriptor_set_layouts: self.tex_descriptor_set_layouts.clone(), + has_color_management_data, }; let pl = self.device.create_pipeline2(info, push_size)?; pipelines.pipelines.set(key, pl.clone()); @@ -507,6 +526,7 @@ impl VulkanRenderer { eotf: key.eotf.to_vulkan(), oetf: fb_cd.transfer_function.to_vulkan(), descriptor_set_layouts, + has_color_management_data: false, })?; pipelines.set(key, out.clone()); Ok(out) @@ -525,7 +545,6 @@ impl VulkanRenderer { return Ok(()); }; zone!("create_descriptor_buffers"); - let version = self.allocate_point(); let memory = &mut *self.memory.borrow_mut(); let sampler_writer = &mut memory.sampler_descriptor_buffer_writer; sampler_writer.clear(); @@ -538,30 +557,47 @@ 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() + }); if let Some(bb) = bb { let layout = self.out_descriptor_set_layout.as_ref().unwrap(); - let offset = resource_writer.next_offset(); - bb.descriptor_buffer_offset.set(offset); + 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); } let tex_descriptor_set_layout = &self.tex_descriptor_set_layouts[1]; for pass in RenderPass::variants() { - for cmd in &memory.ops[pass] { + for cmd in &mut memory.ops[pass] { let VulkanOp::Tex(c) = cmd else { continue; }; let tex = &c.tex; - if tex.descriptor_buffer_version.replace(version) == version { - continue; - } - let offset = resource_writer.next_offset(); - tex.descriptor_buffer_offset.set(offset); + c.resource_descriptor_buffer_offset = resource_writer.next_offset(); let mut writer = resource_writer.add_set(tex_descriptor_set_layout); writer.write( tex_descriptor_set_layout.offsets[0], &tex.sampled_image_descriptor, ); + if let Some(addr) = c.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( + tex_descriptor_set_layout.offsets[1], + uniform_buffer_descriptor_cache, + ); + } } } let mut infos = ArrayVec::<_, 2>::new(); @@ -569,12 +605,7 @@ impl VulkanRenderer { (&sampler_writer, &self.sampler_descriptor_buffer_cache), (&resource_writer, &self.resource_descriptor_buffer_cache), ] { - let mut min_alignment = 1; - if self.device.is_anv { - // https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33903 - min_alignment = 4096; - } - let buffer = cache.allocate(writer.len() as DeviceSize, min_alignment)?; + let buffer = cache.allocate(writer.len() as DeviceSize)?; buffer.buffer.allocation.upload(|ptr, _| unsafe { ptr::copy_nonoverlapping(writer.as_ptr(), ptr, writer.len()) })?; @@ -607,6 +638,7 @@ impl VulkanRenderer { memory.tex_targets.clear(); memory.fill_targets.clear(); memory.data_buffer.clear(); + memory.uniform_buffer_writer.clear(); memory.color_transforms.map.clear(); let sync = |memory: &mut Memory| { for pass in RenderPass::variants() { @@ -751,6 +783,16 @@ impl VulkanRenderer { true => TexSourceType::HasAlpha, false => TexSourceType::Opaque, }; + let target_cd = match pass { + RenderPass::BlendBuffer => blend_cd, + RenderPass::FrameBuffer => fb_cd, + }; + let color_management_data_address = memory.color_transforms.get_offset( + &ct.cd.linear, + target_cd, + self.device.uniform_buffer_offset_mask, + &mut memory.uniform_buffer_writer, + ); ops.push(VulkanOp::Tex(VulkanTexOp { tex: tex.clone(), range: lo..hi, @@ -763,6 +805,8 @@ impl VulkanRenderer { range_address: 0, instances: 0, tex_cd: ct.cd.clone(), + color_management_data_address, + resource_descriptor_buffer_offset: 0, })); } } @@ -792,7 +836,7 @@ impl VulkanRenderer { if buf.is_empty() { return Ok(()); } - let buffer = self.shader_buffer_cache.allocate(buf.len() as _, 8)?; + let buffer = self.shader_buffer_cache.allocate(buf.len() as _)?; buffer.buffer.allocation.upload(|ptr, _| unsafe { ptr::copy_nonoverlapping(buf.as_ptr(), ptr, buf.len()); })?; @@ -813,6 +857,33 @@ impl VulkanRenderer { Ok(()) } + fn create_uniform_buffer(&self) -> Result<(), VulkanError> { + if self.device.descriptor_buffer.is_none() { + return Ok(()); + } + zone!("create_uniform_buffer"); + let memory = &mut *self.memory.borrow_mut(); + let buf = &memory.uniform_buffer_writer; + if buf.is_empty() { + return Ok(()); + } + let buffer = self.uniform_buffer_cache.allocate(buf.len() as _)?; + buffer.buffer.allocation.upload(|ptr, _| unsafe { + ptr::copy_nonoverlapping(buf.as_ptr(), ptr, buf.len()); + })?; + for ops in memory.ops.values_mut() { + for op in ops { + if let VulkanOp::Tex(c) = op { + if let Some(addr) = &mut c.color_management_data_address { + *addr += buffer.buffer.address; + } + } + } + } + memory.used_buffers.push(buffer); + Ok(()) + } + fn collect_memory(&self) { zone!("collect_memory"); let memory = &mut *self.memory.borrow_mut(); @@ -1126,6 +1197,7 @@ impl VulkanRenderer { &c.tex_cd, c.copy_type, c.source_type, + c.color_management_data_address.is_some(), )?; bind(&pipeline); let image_info = DescriptorImageInfo::default() @@ -1143,7 +1215,7 @@ impl VulkanRenderer { pipeline.pipeline_layout, 0, &[0, 1], - &[0, tex.descriptor_buffer_offset.get()], + &[0, c.resource_descriptor_buffer_offset], ); dev.cmd_push_constants( buf, @@ -1219,7 +1291,6 @@ impl VulkanRenderer { buf: CommandBuffer, fb: &VulkanImage, fb_cd: &ColorDescription, - bb: &VulkanImage, bb_cd: &ColorDescription, ) -> Result<(), VulkanError> { zone!("blend_buffer_copy"); @@ -1239,7 +1310,7 @@ impl VulkanRenderer { pipeline.pipeline_layout, 0, &[1], - &[bb.descriptor_buffer_offset.get()], + &[memory.blend_buffer_descriptor_buffer_offset], ); dev.cmd_push_constants( buf, @@ -1808,6 +1879,7 @@ impl VulkanRenderer { let buf = self.gfx_command_buffers.allocate()?; self.convert_ops(opts, bb_cd, fb_cd); self.create_data_buffer()?; + self.create_uniform_buffer()?; self.collect_memory(); self.begin_command_buffer(buf.buffer)?; self.create_descriptor_buffers(buf.buffer, bb)?; @@ -1827,8 +1899,8 @@ impl VulkanRenderer { let rp = RenderPass::FrameBuffer; self.begin_rendering(buf.buffer, fb, clear, clear_cd, rp, fb_cd); self.record_draws(buf.buffer, fb, rp, fb_cd)?; - if let Some(bb) = bb { - self.blend_buffer_copy(buf.buffer, fb, fb_cd, bb, bb_cd)?; + if bb.is_some() { + self.blend_buffer_copy(buf.buffer, fb, fb_cd, bb_cd)?; } self.end_rendering(buf.buffer); } @@ -2055,6 +2127,7 @@ struct ColorTransforms { struct ColorTransform { matrix: ColorMatrix, + offset: Option, } impl ColorTransforms { @@ -2070,7 +2143,10 @@ impl ColorTransforms { Entry::Occupied(o) => o.into_mut(), Entry::Vacant(e) => { let matrix = src.color_transform(&dst.linear); - let ct = ColorTransform { matrix }; + let ct = ColorTransform { + matrix, + offset: None, + }; e.insert(ct) } }; @@ -2088,4 +2164,22 @@ impl ColorTransforms { }; color } + + fn get_offset( + &mut self, + src: &LinearColorDescription, + dst: &ColorDescription, + uniform_buffer_offset_mask: DeviceSize, + writer: &mut GenericBufferWriter, + ) -> Option { + let ct = self.get_or_create(src, dst)?; + if ct.offset.is_none() { + let data = TexColorManagementData { + matrix: ct.matrix.to_f32(), + }; + let offset = writer.write(uniform_buffer_offset_mask, &data); + ct.offset = Some(offset); + } + ct.offset + } } diff --git a/src/gfx_apis/vulkan/shaders.rs b/src/gfx_apis/vulkan/shaders.rs index 5fa21821..be199c8a 100644 --- a/src/gfx_apis/vulkan/shaders.rs +++ b/src/gfx_apis/vulkan/shaders.rs @@ -61,6 +61,14 @@ pub struct TexPushConstants { unsafe impl Packed for TexPushConstants {} +#[derive(Copy, Clone, Debug)] +#[repr(C, align(16))] +pub struct TexColorManagementData { + pub matrix: [[f32; 4]; 4], +} + +unsafe impl Packed for TexColorManagementData {} + #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct LegacyTexPushConstants { diff --git a/src/gfx_apis/vulkan/shaders/frag_spec_const.glsl b/src/gfx_apis/vulkan/shaders/frag_spec_const.glsl index ada35281..9bbc6c7b 100644 --- a/src/gfx_apis/vulkan/shaders/frag_spec_const.glsl +++ b/src/gfx_apis/vulkan/shaders/frag_spec_const.glsl @@ -5,5 +5,6 @@ layout(constant_id = 0) const bool src_has_alpha = false; layout(constant_id = 1) const bool has_alpha_multiplier = false; layout(constant_id = 2) const uint eotf = 0; layout(constant_id = 3) const uint oetf = 0; +layout(constant_id = 4) const bool has_matrix = false; #endif diff --git a/src/gfx_apis/vulkan/shaders/tex.frag b/src/gfx_apis/vulkan/shaders/tex.frag index f9b18731..d7a6a978 100644 --- a/src/gfx_apis/vulkan/shaders/tex.frag +++ b/src/gfx_apis/vulkan/shaders/tex.frag @@ -1,25 +1,35 @@ #version 450 +#extension GL_EXT_scalar_block_layout : require + #include "frag_spec_const.glsl" #include "transfer_functions.glsl" #include "tex.common.glsl" layout(set = 0, binding = 0) uniform sampler sam; layout(set = 1, binding = 0) uniform texture2D tex; +layout(set = 1, binding = 1, row_major, std430) uniform ColorManagementData { + mat4x4 matrix; +} cm_data; layout(location = 0) in vec2 tex_pos; layout(location = 0) out vec4 out_color; void main() { vec4 c = textureLod(sampler2D(tex, sam), tex_pos, 0); - if (eotf != oetf) { + if (eotf != oetf || has_matrix) { + vec3 rgb = c.rgb; if (src_has_alpha) { - c.rgb /= mix(c.a, 1.0, c.a == 0.0); + rgb /= mix(c.a, 1.0, c.a == 0.0); } - c.rgb = apply_eotf(c.rgb); - c.rgb = apply_oetf(c.rgb); + rgb = apply_eotf(rgb); + if (has_matrix) { + rgb = (cm_data.matrix * vec4(rgb, 1.0)).rgb; + } + rgb = apply_oetf(rgb); if (src_has_alpha) { - c.rgb *= c.a; + rgb *= c.a; } + c.rgb = rgb; } if (has_alpha_multiplier) { if (src_has_alpha) { diff --git a/src/gfx_apis/vulkan/shm_image.rs b/src/gfx_apis/vulkan/shm_image.rs index 240d1e11..b7cd130a 100644 --- a/src/gfx_apis/vulkan/shm_image.rs +++ b/src/gfx_apis/vulkan/shm_image.rs @@ -460,8 +460,6 @@ impl VulkanRenderer { ty: VulkanImageMemory::Internal(shm), bridge: None, 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), }); let shm = match &img.ty {