1
0
Fork 0
forked from wry/wry

vulkan: split renderer color caches

This commit is contained in:
kossLAN 2026-05-29 21:01:31 -04:00
parent 1a43bd55e1
commit 3c7ba1a7b7
No known key found for this signature in database
2 changed files with 192 additions and 164 deletions

View file

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

View file

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