1
0
Fork 0
forked from wry/wry

vulkan: apply color space transforms to textures

This commit is contained in:
Julian Orth 2025-03-01 19:19:27 +01:00
parent c4d0fdd4bb
commit 8e65de91f9
12 changed files with 233 additions and 66 deletions

View file

@ -157,7 +157,6 @@ impl<T, U> ColorMatrix<T, U> {
Self(m, PhantomData)
}
#[expect(dead_code)]
pub const fn to_f32(&self) -> [[f32; 4]; 4] {
let m = &self.0;
macro_rules! map {

View file

@ -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));

View file

@ -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<VulkanAllocator>,
buffers: RefCell<Vec<VulkanBufferUnused>>,
usage: BufferUsageFlags,
min_alignment: DeviceSize,
}
pub struct VulkanBuffer {
@ -40,12 +42,14 @@ impl VulkanBufferCache {
device: &Rc<VulkanDevice>,
allocator: &Rc<VulkanAllocator>,
usage: BufferUsageFlags,
min_alignment: DeviceSize,
) -> Rc<Self> {
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<Self> {
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<Self>,
capacity: DeviceSize,
align: DeviceSize,
) -> Result<VulkanBuffer, VulkanError> {
pub fn allocate(self: &Rc<Self>, capacity: DeviceSize) -> Result<VulkanBuffer, VulkanError> {
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<u8>,
}
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
}
}

View file

@ -15,7 +15,7 @@ pub(super) struct VulkanDescriptorSetLayout {
pub(super) device: Rc<VulkanDevice>,
pub(super) layout: DescriptorSetLayout,
pub(super) size: DeviceSize,
pub(super) offsets: ArrayVec<DeviceSize, 1>,
pub(super) offsets: ArrayVec<DeviceSize, 2>,
pub(super) _sampler: Option<Rc<VulkanSampler>>,
}
@ -87,12 +87,20 @@ 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 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(),

View file

@ -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,
}))
}
}

View file

@ -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<VulkanFramebufferBridge>,
pub(super) sampled_image_descriptor: Box<[u8]>,
pub(super) descriptor_buffer_version: Cell<u64>,
pub(super) descriptor_buffer_offset: Cell<DeviceSize>,
pub(super) execution_version: Cell<u64>,
}
@ -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),
}))
}

View file

@ -42,6 +42,7 @@ pub(super) struct PipelineCreateInfo {
pub(super) eotf: u32,
pub(super) oetf: u32,
pub(super) descriptor_set_layouts: ArrayVec<Rc<VulkanDescriptorSetLayout>, 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);

View file

@ -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<VulkanBufferCache>,
pub(super) blend_buffers: RefCell<AHashMap<(u32, u32), Weak<VulkanImage>>>,
pub(super) shader_buffer_cache: Rc<VulkanBufferCache>,
pub(super) uniform_buffer_cache: Rc<VulkanBufferCache>,
}
pub(super) struct CachedCommandBuffers {
@ -159,7 +161,7 @@ pub(super) struct Memory {
wait_semaphore_infos: Vec<SemaphoreSubmitInfo<'static>>,
release_fence: Option<Rc<VulkanFence>>,
release_sync_file: Option<SyncFile>,
used_buffers: ArrayVec<VulkanBuffer, 3>,
used_buffers: ArrayVec<VulkanBuffer, 4>,
paint_bounds: StaticMap<RenderPass, Option<PaintRegion>>,
paint_regions: StaticMap<RenderPass, Vec<PaintRegion>>,
clear_rects: StaticMap<RenderPass, Vec<ClearRect>>,
@ -175,6 +177,9 @@ pub(super) struct Memory {
data_buffer: Vec<u8>,
out_address: DeviceAddress,
color_transforms: ColorTransforms,
uniform_buffer_writer: GenericBufferWriter,
uniform_buffer_descriptor_cache: Option<Box<[u8]>>,
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<ColorDescription>,
color_management_data_address: Option<DeviceAddress>,
resource_descriptor_buffer_offset: DeviceAddress,
}
struct VulkanFillOp {
@ -230,7 +237,7 @@ pub(super) struct PendingFrame {
wait_semaphores: Cell<Vec<Rc<VulkanSemaphore>>>,
waiter: Cell<Option<SpawnedFuture<()>>>,
_release_fence: Option<Rc<VulkanFence>>,
_used_buffers: ArrayVec<VulkanBuffer, 3>,
_used_buffers: ArrayVec<VulkanBuffer, 4>,
}
type FillPipelines = Rc<StaticMap<TexSourceType, Rc<VulkanPipeline>>>;
@ -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::<TexColorManagementData>() 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<Rc<VulkanPipeline>, 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::<TexColorManagementData>() 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<DeviceSize>,
}
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<DeviceSize> {
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
}
}

View file

@ -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 {

View file

@ -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

View file

@ -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) {

View file

@ -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 {