1
0
Fork 0
forked from wry/wry

vulkan: allow EOTFs to be parametrized

This commit is contained in:
Julian Orth 2025-09-08 18:26:19 +02:00
parent 6d28bfd4e2
commit a2d726e508
4 changed files with 174 additions and 25 deletions

View file

@ -15,7 +15,7 @@ pub(super) struct VulkanDescriptorSetLayout {
pub(super) device: Rc<VulkanDevice>, pub(super) device: Rc<VulkanDevice>,
pub(super) layout: DescriptorSetLayout, pub(super) layout: DescriptorSetLayout,
pub(super) size: DeviceSize, pub(super) size: DeviceSize,
pub(super) offsets: ArrayVec<DeviceSize, 2>, pub(super) offsets: ArrayVec<DeviceSize, 4>,
pub(super) _sampler: Option<Rc<VulkanSampler>>, pub(super) _sampler: Option<Rc<VulkanSampler>>,
} }
@ -98,6 +98,16 @@ impl VulkanDevice {
.stage_flags(ShaderStageFlags::FRAGMENT) .stage_flags(ShaderStageFlags::FRAGMENT)
.descriptor_count(1) .descriptor_count(1)
.descriptor_type(DescriptorType::UNIFORM_BUFFER), .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() let create_info = DescriptorSetLayoutCreateInfo::default()
.bindings(&bindings) .bindings(&bindings)
@ -110,6 +120,8 @@ impl VulkanDevice {
unsafe { unsafe {
offsets.push(db.get_descriptor_set_layout_binding_offset(layout, 0)); 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, 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 { Ok(Rc::new(VulkanDescriptorSetLayout {
device: self.clone(), device: self.clone(),

View file

@ -25,10 +25,10 @@ use {
sampler::VulkanSampler, sampler::VulkanSampler,
semaphore::VulkanSemaphore, semaphore::VulkanSemaphore,
shaders::{ shaders::{
ColorManagementData, FILL_FRAG, FILL_VERT, FillPushConstants, LEGACY_FILL_FRAG, ColorManagementData, EotfArgs, FILL_FRAG, FILL_VERT, FillPushConstants,
LEGACY_FILL_VERT, LEGACY_TEX_FRAG, LEGACY_TEX_VERT, LegacyFillPushConstants, InvEotfArgs, LEGACY_FILL_FRAG, LEGACY_FILL_VERT, LEGACY_TEX_FRAG, LEGACY_TEX_VERT,
LegacyTexPushConstants, OUT_FRAG, OUT_VERT, OutPushConstants, TEX_FRAG, TEX_VERT, LegacyFillPushConstants, LegacyTexPushConstants, OUT_FRAG, OUT_VERT,
TexPushConstants, TexVertex, VulkanShader, OutPushConstants, TEX_FRAG, TEX_VERT, TexPushConstants, TexVertex, VulkanShader,
}, },
}, },
io_uring::IoUring, io_uring::IoUring,
@ -176,10 +176,16 @@ pub(super) struct Memory {
data_buffer: Vec<u8>, data_buffer: Vec<u8>,
out_address: DeviceAddress, out_address: DeviceAddress,
color_transforms: ColorTransforms, color_transforms: ColorTransforms,
eotf_args_cache: EotfArgsCache,
uniform_buffer_writer: GenericBufferWriter, uniform_buffer_writer: GenericBufferWriter,
uniform_buffer_descriptor_cache: Option<Box<[u8]>>, uniform_buffer_descriptor_cache: Option<Box<[u8]>>,
blend_buffer_inv_eotf_args_descriptor: Option<Box<[u8]>>,
fb_inv_eotf_args_descriptor: Option<Box<[u8]>>,
blend_buffer_descriptor_buffer_offset: DeviceAddress, blend_buffer_descriptor_buffer_offset: DeviceAddress,
blend_buffer_color_management_data_address: Option<DeviceSize>, blend_buffer_color_management_data_address: Option<DeviceSize>,
blend_buffer_eotf_args_address: Option<DeviceSize>,
blend_buffer_inv_eotf_args_address: Option<DeviceSize>,
fb_inv_eotf_args_address: Option<DeviceSize>,
} }
type Point = [[f32; 2]; 4]; type Point = [[f32; 2]; 4];
@ -202,6 +208,7 @@ struct VulkanTexOp {
instances: u32, instances: u32,
tex_cd: Rc<ColorDescription>, tex_cd: Rc<ColorDescription>,
color_management_data_address: Option<DeviceAddress>, color_management_data_address: Option<DeviceAddress>,
eotf_args_address: Option<DeviceAddress>,
resource_descriptor_buffer_offset: DeviceAddress, resource_descriptor_buffer_offset: DeviceAddress,
} }
@ -352,7 +359,9 @@ impl VulkanDevice {
}; };
let uniform_buffer_cache = { let uniform_buffer_cache = {
let usage = BufferUsageFlags::SHADER_DEVICE_ADDRESS | BufferUsageFlags::UNIFORM_BUFFER; let usage = BufferUsageFlags::SHADER_DEVICE_ADDRESS | BufferUsageFlags::UNIFORM_BUFFER;
let align = align_of::<ColorManagementData>() as DeviceSize; let align = align_of::<ColorManagementData>()
.max(align_of::<EotfArgs>())
.max(align_of::<InvEotfArgs>()) as DeviceSize;
VulkanBufferCache::new(self, &allocator, usage, align) VulkanBufferCache::new(self, &allocator, usage, align)
}; };
let render = Rc::new(VulkanRenderer { let render = Rc::new(VulkanRenderer {
@ -562,11 +571,14 @@ impl VulkanRenderer {
} }
let resource_writer = &mut memory.resource_descriptor_buffer_writer; let resource_writer = &mut memory.resource_descriptor_buffer_writer;
resource_writer.clear(); resource_writer.clear();
let uniform_buffer_descriptor_cache = memory macro_rules! ub_descriptor_cache {
.uniform_buffer_descriptor_cache ($field:ident) => {
.get_or_insert_with(|| { memory.$field.get_or_insert_with(|| {
vec![0u8; self.device.uniform_buffer_descriptor_size].into_boxed_slice() 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 { macro_rules! get_ub_descriptor {
($addr:expr, $ty:ty, $descriptor:expr $(,)?) => {{ ($addr:expr, $ty:ty, $descriptor:expr $(,)?) => {{
let uniform_buffer = DescriptorAddressInfoEXT::default() let uniform_buffer = DescriptorAddressInfoEXT::default()
@ -586,6 +598,22 @@ impl VulkanRenderer {
get_ub_descriptor!($addr, $ty, uniform_buffer_descriptor_cache) 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 { if let Some(bb) = bb {
let layout = self.out_descriptor_set_layout.as_ref().unwrap(); let layout = self.out_descriptor_set_layout.as_ref().unwrap();
memory.blend_buffer_descriptor_buffer_offset = resource_writer.next_offset(); memory.blend_buffer_descriptor_buffer_offset = resource_writer.next_offset();
@ -597,9 +625,19 @@ impl VulkanRenderer {
get_ub_descriptor!(addr, ColorManagementData), 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]; let tex_descriptor_set_layout = &self.tex_descriptor_set_layouts[1];
for pass in RenderPass::variants() { 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] { for cmd in &mut memory.ops[pass] {
let VulkanOp::Tex(c) = cmd else { let VulkanOp::Tex(c) = cmd else {
continue; continue;
@ -617,6 +655,15 @@ impl VulkanRenderer {
get_ub_descriptor!(addr, ColorManagementData), 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(); let mut infos = ArrayVec::<_, 2>::new();
@ -659,6 +706,7 @@ impl VulkanRenderer {
memory.data_buffer.clear(); memory.data_buffer.clear();
memory.uniform_buffer_writer.clear(); memory.uniform_buffer_writer.clear();
memory.color_transforms.map.clear(); memory.color_transforms.map.clear();
memory.eotf_args_cache.map.clear();
let sync = |memory: &mut Memory| { let sync = |memory: &mut Memory| {
for pass in RenderPass::variants() { for pass in RenderPass::variants() {
let ops = &mut memory.ops_tmp[pass]; let ops = &mut memory.ops_tmp[pass];
@ -813,6 +861,12 @@ impl VulkanRenderer {
self.device.uniform_buffer_offset_mask, self.device.uniform_buffer_offset_mask,
&mut memory.uniform_buffer_writer, &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 { ops.push(VulkanOp::Tex(VulkanTexOp {
tex: tex.clone(), tex: tex.clone(),
range: lo..hi, range: lo..hi,
@ -826,6 +880,7 @@ impl VulkanRenderer {
instances: 0, instances: 0,
tex_cd: ct.cd.clone(), tex_cd: ct.cd.clone(),
color_management_data_address, color_management_data_address,
eotf_args_address,
resource_descriptor_buffer_offset: 0, resource_descriptor_buffer_offset: 0,
})); }));
} }
@ -836,21 +891,41 @@ impl VulkanRenderer {
Ok(()) Ok(())
} }
fn create_blend_cm_data( fn create_fixed_cm_data(
&self, &self,
bb: Option<&VulkanImage>, bb: Option<&VulkanImage>,
bb_cd: &ColorDescription, bb_cd: &ColorDescription,
fb_cd: &ColorDescription, fb_cd: &ColorDescription,
) { ) {
zone!("create_blend_cm_data"); zone!("create_fixed_cm_data");
let memory = &mut *self.memory.borrow_mut(); let memory = &mut *self.memory.borrow_mut();
memory.blend_buffer_color_management_data_address = None; memory.blend_buffer_color_management_data_address = None;
if bb.is_none() { memory.blend_buffer_eotf_args_address = None;
return; 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( memory.fb_inv_eotf_args_address = memory.eotf_args_cache.get_offset(
&bb_cd.linear,
fb_cd, fb_cd,
true,
self.device.uniform_buffer_offset_mask, self.device.uniform_buffer_offset_mask,
&mut memory.uniform_buffer_writer, &mut memory.uniform_buffer_writer,
); );
@ -912,18 +987,25 @@ impl VulkanRenderer {
buffer.buffer.allocation.upload(|ptr, _| unsafe { buffer.buffer.allocation.upload(|ptr, _| unsafe {
ptr::copy_nonoverlapping(buf.as_ptr(), ptr, buf.len()); 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 ops in memory.ops.values_mut() {
for op in ops { for op in ops {
if let VulkanOp::Tex(c) = op if let VulkanOp::Tex(c) = op {
&& let Some(addr) = &mut c.color_management_data_address adj!(&mut c.color_management_data_address);
{ adj!(&mut c.eotf_args_address);
*addr += buffer.buffer.address;
} }
} }
} }
if let Some(addr) = &mut memory.blend_buffer_color_management_data_address { adj!(&mut memory.blend_buffer_color_management_data_address);
*addr += buffer.buffer.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); memory.used_buffers.push(buffer);
Ok(()) Ok(())
} }
@ -1942,7 +2024,7 @@ impl VulkanRenderer {
let bb = blend_buffer.as_deref(); let bb = blend_buffer.as_deref();
let buf = self.gfx_command_buffers.allocate()?; let buf = self.gfx_command_buffers.allocate()?;
self.convert_ops(opts, bb_cd, fb_cd)?; 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_data_buffer()?;
self.create_uniform_buffer()?; self.create_uniform_buffer()?;
self.collect_memory(); self.collect_memory();
@ -2242,3 +2324,24 @@ impl ColorTransforms {
ct.offset 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<DeviceSize> {
None
}
}

View file

@ -69,6 +69,28 @@ pub struct ColorManagementData {
unsafe impl Packed for 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)] #[derive(Copy, Clone, Debug)]
#[repr(C)] #[repr(C)]
pub struct LegacyTexPushConstants { pub struct LegacyTexPushConstants {

View file

@ -5,5 +5,17 @@ layout(set = TEX_SET, binding = 0) uniform texture2D tex;
layout(set = TEX_SET, binding = 1, row_major, std430) uniform ColorManagementData { layout(set = TEX_SET, binding = 1, row_major, std430) uniform ColorManagementData {
mat4x4 matrix; mat4x4 matrix;
} cm_data; } 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 #endif