vulkan: split renderer color caches
This commit is contained in:
parent
1a43bd55e1
commit
3c7ba1a7b7
2 changed files with 192 additions and 164 deletions
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
184
src/gfx_apis/vulkan/renderer/color.rs
Normal file
184
src/gfx_apis/vulkan/renderer/color.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue