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 {
|
use {
|
||||||
|
color::{ColorTransforms, EotfArgsCache},
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncEngine, SpawnedFuture},
|
async_engine::{AsyncEngine, SpawnedFuture},
|
||||||
cmm::{
|
cmm::{
|
||||||
cmm_description::{ColorDescription, LinearColorDescription, LinearColorDescriptionId},
|
cmm_description::{ColorDescription, LinearColorDescription},
|
||||||
cmm_eotf::{Eotf, EotfPow, bt1886_eotf_args, bt1886_inv_eotf_args},
|
|
||||||
cmm_render_intent::RenderIntent,
|
cmm_render_intent::RenderIntent,
|
||||||
cmm_transform::ColorMatrix,
|
|
||||||
},
|
},
|
||||||
cpu_worker::PendingJob,
|
cpu_worker::PendingJob,
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
|
|
@ -41,8 +42,8 @@ use {
|
||||||
rect::{Rect, Region},
|
rect::{Rect, Region},
|
||||||
theme::Color,
|
theme::Color,
|
||||||
utils::{
|
utils::{
|
||||||
copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell, ordered_float::F32,
|
copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell, oserror::OsErrorExt2,
|
||||||
oserror::OsErrorExt2, stack::Stack,
|
stack::Stack,
|
||||||
},
|
},
|
||||||
video::dmabuf::{DMA_BUF_SYNC_READ, DMA_BUF_SYNC_WRITE, dma_buf_export_sync_file},
|
video::dmabuf::{DMA_BUF_SYNC_READ, DMA_BUF_SYNC_WRITE, dma_buf_export_sync_file},
|
||||||
vulkan_core::{
|
vulkan_core::{
|
||||||
|
|
@ -74,7 +75,6 @@ use {
|
||||||
any::Any,
|
any::Any,
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
cell::{Cell, LazyCell, RefCell},
|
cell::{Cell, LazyCell, RefCell},
|
||||||
collections::hash_map::Entry,
|
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
mem,
|
mem,
|
||||||
ops::Range,
|
ops::Range,
|
||||||
|
|
@ -914,8 +914,8 @@ impl VulkanRenderer {
|
||||||
memory.fill_targets.clear();
|
memory.fill_targets.clear();
|
||||||
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.clear();
|
||||||
memory.eotf_args_cache.map.clear();
|
memory.eotf_args_cache.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];
|
||||||
|
|
@ -2828,159 +2828,3 @@ where
|
||||||
}
|
}
|
||||||
Some([x1, y1, x2, y2])
|
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