From 3c7ba1a7b72d0bbfb934997bc2ebfc2f7aea58d2 Mon Sep 17 00:00:00 2001 From: kossLAN Date: Fri, 29 May 2026 21:01:31 -0400 Subject: [PATCH] vulkan: split renderer color caches --- src/gfx_apis/vulkan/renderer.rs | 172 ++---------------------- src/gfx_apis/vulkan/renderer/color.rs | 184 ++++++++++++++++++++++++++ 2 files changed, 192 insertions(+), 164 deletions(-) create mode 100644 src/gfx_apis/vulkan/renderer/color.rs diff --git a/src/gfx_apis/vulkan/renderer.rs b/src/gfx_apis/vulkan/renderer.rs index 4983a178..a736a79b 100644 --- a/src/gfx_apis/vulkan/renderer.rs +++ b/src/gfx_apis/vulkan/renderer.rs @@ -1,11 +1,12 @@ +mod color; + use { + color::{ColorTransforms, EotfArgsCache}, crate::{ async_engine::{AsyncEngine, SpawnedFuture}, cmm::{ - cmm_description::{ColorDescription, LinearColorDescription, LinearColorDescriptionId}, - cmm_eotf::{Eotf, EotfPow, bt1886_eotf_args, bt1886_inv_eotf_args}, + cmm_description::{ColorDescription, LinearColorDescription}, cmm_render_intent::RenderIntent, - cmm_transform::ColorMatrix, }, cpu_worker::PendingJob, gfx_api::{ @@ -41,8 +42,8 @@ use { rect::{Rect, Region}, theme::Color, utils::{ - copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell, ordered_float::F32, - oserror::OsErrorExt2, stack::Stack, + copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell, oserror::OsErrorExt2, + stack::Stack, }, video::dmabuf::{DMA_BUF_SYNC_READ, DMA_BUF_SYNC_WRITE, dma_buf_export_sync_file}, vulkan_core::{ @@ -74,7 +75,6 @@ use { any::Any, borrow::Cow, cell::{Cell, LazyCell, RefCell}, - collections::hash_map::Entry, fmt::{Debug, Formatter}, mem, ops::Range, @@ -914,8 +914,8 @@ impl VulkanRenderer { memory.fill_targets.clear(); memory.data_buffer.clear(); memory.uniform_buffer_writer.clear(); - memory.color_transforms.map.clear(); - memory.eotf_args_cache.map.clear(); + memory.color_transforms.clear(); + memory.eotf_args_cache.clear(); let sync = |memory: &mut Memory| { for pass in RenderPass::variants() { let ops = &mut memory.ops_tmp[pass]; @@ -2828,159 +2828,3 @@ where } Some([x1, y1, x2, y2]) } - -#[derive(Default)] -struct ColorTransforms { - map: AHashMap<([LinearColorDescriptionId; 2], RenderIntent), ColorTransform>, -} - -struct ColorTransform { - matrix: ColorMatrix, - offset: Option, -} - -impl ColorTransforms { - fn get_or_create( - &mut self, - src: &LinearColorDescription, - dst: &ColorDescription, - intent: RenderIntent, - ) -> Option<&mut ColorTransform> { - if src.embeds_into(&dst.linear) { - return None; - } - let ct = match self.map.entry(([src.id, dst.linear.id], intent)) { - Entry::Occupied(o) => o.into_mut(), - Entry::Vacant(e) => { - let matrix = src.color_transform(&dst.linear, intent); - let ct = ColorTransform { - matrix, - offset: None, - }; - e.insert(ct) - } - }; - Some(ct) - } - - fn apply_to_color( - &mut self, - src: &LinearColorDescription, - dst: &ColorDescription, - intent: RenderIntent, - mut color: Color, - ) -> Color { - if let Some(ct) = self.get_or_create(src, dst, intent) { - color = apply_color_matrix(ct.matrix, color); - }; - color - } - - fn get_offset( - &mut self, - src: &LinearColorDescription, - dst: &ColorDescription, - intent: RenderIntent, - uniform_buffer_offset_mask: DeviceSize, - writer: &mut GenericBufferWriter, - ) -> Option { - let ct = self.get_or_create(src, dst, intent)?; - if ct.offset.is_none() { - let data = ColorManagementData { - matrix: ct.matrix.to_f32(), - }; - let offset = writer.write(uniform_buffer_offset_mask, &data); - ct.offset = Some(offset); - } - ct.offset - } -} - -fn apply_color_matrix(matrix: ColorMatrix, color: Color) -> Color { - let mut rgba = color.to_array(Eotf::Linear); - let a = rgba[3]; - if a < 1.0 && a > 0.0 { - for c in &mut rgba[..3] { - *c /= a; - } - } - let [r, g, b] = matrix * [rgba[0] as f64, rgba[1] as f64, rgba[2] as f64]; - Color::new( - Eotf::Linear, - AlphaMode::Straight, - r as f32, - g as f32, - b as f32, - a, - ) -} - -#[derive(Default)] -struct EotfArgsCache { - map: AHashMap<(EotfCacheKey, bool), EotfArg>, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -enum EotfCacheKey { - Pow(EotfPow), - Bt1886(F32), -} - -struct EotfArg { - offset: DeviceSize, -} - -impl EotfArgsCache { - fn get_offset( - &mut self, - desc: &ColorDescription, - inv: bool, - uniform_buffer_offset_mask: DeviceSize, - writer: &mut GenericBufferWriter, - ) -> Option { - let key = match desc.eotf { - Eotf::Bt1886(c) => EotfCacheKey::Bt1886(c), - Eotf::Pow(pow) => EotfCacheKey::Pow(pow), - _ => return None, - }; - let ct = match self.map.entry((key, inv)) { - Entry::Occupied(o) => o.into_mut(), - Entry::Vacant(e) => { - #[expect(unused_assignments)] - let [mut arg1, mut arg2, mut arg3, mut arg4] = [0.0; 4]; - if inv { - match key { - EotfCacheKey::Pow(pow) => arg1 = pow.inv_eotf_f32(), - EotfCacheKey::Bt1886(c) => { - [arg1, arg2, arg3, arg4] = bt1886_inv_eotf_args(c); - } - } - let data = InvEotfArgs { - arg1, - arg2, - arg3, - arg4, - }; - let offset = writer.write(uniform_buffer_offset_mask, &data); - e.insert(EotfArg { offset }) - } else { - match key { - EotfCacheKey::Pow(pow) => arg1 = pow.eotf_f32(), - EotfCacheKey::Bt1886(c) => { - [arg1, arg2, arg3, arg4] = bt1886_eotf_args(c); - } - } - let data = EotfArgs { - arg1, - arg2, - arg3, - arg4, - }; - let offset = writer.write(uniform_buffer_offset_mask, &data); - e.insert(EotfArg { offset }) - } - } - }; - Some(ct.offset) - } -} diff --git a/src/gfx_apis/vulkan/renderer/color.rs b/src/gfx_apis/vulkan/renderer/color.rs new file mode 100644 index 00000000..fef90f2a --- /dev/null +++ b/src/gfx_apis/vulkan/renderer/color.rs @@ -0,0 +1,184 @@ +use { + crate::{ + cmm::{ + cmm_description::{ColorDescription, LinearColorDescription, LinearColorDescriptionId}, + cmm_eotf::{Eotf, EotfPow, bt1886_eotf_args, bt1886_inv_eotf_args}, + cmm_render_intent::RenderIntent, + cmm_transform::ColorMatrix, + }, + gfx_api::AlphaMode, + gfx_apis::vulkan::{ + buffer_cache::GenericBufferWriter, + shaders::{ColorManagementData, EotfArgs, InvEotfArgs}, + }, + theme::Color, + utils::ordered_float::F32, + }, + ahash::AHashMap, + ash::vk::DeviceSize, + std::collections::hash_map::Entry, +}; + +#[derive(Default)] +pub(super) struct ColorTransforms { + map: AHashMap<([LinearColorDescriptionId; 2], RenderIntent), ColorTransform>, +} + +struct ColorTransform { + matrix: ColorMatrix, + offset: Option, +} + +impl ColorTransforms { + pub(super) fn clear(&mut self) { + self.map.clear(); + } + + fn get_or_create( + &mut self, + src: &LinearColorDescription, + dst: &ColorDescription, + intent: RenderIntent, + ) -> Option<&mut ColorTransform> { + if src.embeds_into(&dst.linear) { + return None; + } + let ct = match self.map.entry(([src.id, dst.linear.id], intent)) { + Entry::Occupied(o) => o.into_mut(), + Entry::Vacant(e) => { + let matrix = src.color_transform(&dst.linear, intent); + let ct = ColorTransform { + matrix, + offset: None, + }; + e.insert(ct) + } + }; + Some(ct) + } + + pub(super) fn apply_to_color( + &mut self, + src: &LinearColorDescription, + dst: &ColorDescription, + intent: RenderIntent, + mut color: Color, + ) -> Color { + if let Some(ct) = self.get_or_create(src, dst, intent) { + color = apply_color_matrix(ct.matrix, color); + }; + color + } + + pub(super) fn get_offset( + &mut self, + src: &LinearColorDescription, + dst: &ColorDescription, + intent: RenderIntent, + uniform_buffer_offset_mask: DeviceSize, + writer: &mut GenericBufferWriter, + ) -> Option { + let ct = self.get_or_create(src, dst, intent)?; + if ct.offset.is_none() { + let data = ColorManagementData { + matrix: ct.matrix.to_f32(), + }; + let offset = writer.write(uniform_buffer_offset_mask, &data); + ct.offset = Some(offset); + } + ct.offset + } +} + +fn apply_color_matrix(matrix: ColorMatrix, color: Color) -> Color { + let mut rgba = color.to_array(Eotf::Linear); + let a = rgba[3]; + if a < 1.0 && a > 0.0 { + for c in &mut rgba[..3] { + *c /= a; + } + } + let [r, g, b] = matrix * [rgba[0] as f64, rgba[1] as f64, rgba[2] as f64]; + Color::new( + Eotf::Linear, + AlphaMode::Straight, + r as f32, + g as f32, + b as f32, + a, + ) +} + +#[derive(Default)] +pub(super) struct EotfArgsCache { + map: AHashMap<(EotfCacheKey, bool), EotfArg>, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +enum EotfCacheKey { + Pow(EotfPow), + Bt1886(F32), +} + +struct EotfArg { + offset: DeviceSize, +} + +impl EotfArgsCache { + pub(super) fn clear(&mut self) { + self.map.clear(); + } + + pub(super) fn get_offset( + &mut self, + desc: &ColorDescription, + inv: bool, + uniform_buffer_offset_mask: DeviceSize, + writer: &mut GenericBufferWriter, + ) -> Option { + let key = match desc.eotf { + Eotf::Bt1886(c) => EotfCacheKey::Bt1886(c), + Eotf::Pow(pow) => EotfCacheKey::Pow(pow), + _ => return None, + }; + let ct = match self.map.entry((key, inv)) { + Entry::Occupied(o) => o.into_mut(), + Entry::Vacant(e) => { + #[expect(unused_assignments)] + let [mut arg1, mut arg2, mut arg3, mut arg4] = [0.0; 4]; + if inv { + match key { + EotfCacheKey::Pow(pow) => arg1 = pow.inv_eotf_f32(), + EotfCacheKey::Bt1886(c) => { + [arg1, arg2, arg3, arg4] = bt1886_inv_eotf_args(c); + } + } + let data = InvEotfArgs { + arg1, + arg2, + arg3, + arg4, + }; + let offset = writer.write(uniform_buffer_offset_mask, &data); + e.insert(EotfArg { offset }) + } else { + match key { + EotfCacheKey::Pow(pow) => arg1 = pow.eotf_f32(), + EotfCacheKey::Bt1886(c) => { + [arg1, arg2, arg3, arg4] = bt1886_eotf_args(c); + } + } + let data = EotfArgs { + arg1, + arg2, + arg3, + arg4, + }; + let offset = writer.write(uniform_buffer_offset_mask, &data); + e.insert(EotfArg { offset }) + } + } + }; + Some(ct.offset) + } +}