vulkan: apply color space transforms to colors
This commit is contained in:
parent
b5044d7fe7
commit
c4d0fdd4bb
4 changed files with 73 additions and 13 deletions
|
|
@ -52,7 +52,6 @@ pub struct ColorDescription {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LinearColorDescription {
|
impl LinearColorDescription {
|
||||||
#[expect(dead_code)]
|
|
||||||
pub fn color_transform(&self, target: &Self) -> ColorMatrix {
|
pub fn color_transform(&self, target: &Self) -> ColorMatrix {
|
||||||
let mut mat = target.local_from_xyz;
|
let mut mat = target.local_from_xyz;
|
||||||
if self.luminance != target.luminance {
|
if self.luminance != target.luminance {
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,6 @@ pub struct FillRect {
|
||||||
pub rect: FramebufferRect,
|
pub rect: FramebufferRect,
|
||||||
pub color: Color,
|
pub color: Color,
|
||||||
pub alpha: Option<f32>,
|
pub alpha: Option<f32>,
|
||||||
#[expect(dead_code)]
|
|
||||||
pub cd: Rc<LinearColorDescription>,
|
pub cd: Rc<LinearColorDescription>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -556,7 +556,7 @@ impl GfxFramebuffer for VulkanImage {
|
||||||
cd: &Rc<ColorDescription>,
|
cd: &Rc<ColorDescription>,
|
||||||
ops: &[GfxApiOpt],
|
ops: &[GfxApiOpt],
|
||||||
clear: Option<&Color>,
|
clear: Option<&Color>,
|
||||||
_clear_cd: &Rc<LinearColorDescription>,
|
clear_cd: &Rc<LinearColorDescription>,
|
||||||
region: &Region,
|
region: &Region,
|
||||||
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
|
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
|
||||||
blend_cd: &Rc<ColorDescription>,
|
blend_cd: &Rc<ColorDescription>,
|
||||||
|
|
@ -581,6 +581,7 @@ impl GfxFramebuffer for VulkanImage {
|
||||||
cd,
|
cd,
|
||||||
ops,
|
ops,
|
||||||
clear,
|
clear,
|
||||||
|
clear_cd,
|
||||||
region,
|
region,
|
||||||
blend_buffer,
|
blend_buffer,
|
||||||
blend_cd,
|
blend_cd,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncEngine, SpawnedFuture},
|
async_engine::{AsyncEngine, SpawnedFuture},
|
||||||
cmm::{cmm_description::ColorDescription, cmm_transfer_function::TransferFunction},
|
cmm::{
|
||||||
|
cmm_description::{ColorDescription, LinearColorDescription, LinearColorDescriptionId},
|
||||||
|
cmm_transfer_function::TransferFunction,
|
||||||
|
cmm_transform::ColorMatrix,
|
||||||
|
},
|
||||||
cpu_worker::PendingJob,
|
cpu_worker::PendingJob,
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
AcquireSync, BufferResv, BufferResvUser, GfxApiOpt, GfxBlendBuffer, GfxFormat,
|
AcquireSync, BufferResv, BufferResvUser, GfxApiOpt, GfxBlendBuffer, GfxFormat,
|
||||||
|
|
@ -57,6 +61,7 @@ use {
|
||||||
std::{
|
std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
collections::hash_map::Entry,
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
mem,
|
mem,
|
||||||
ops::Range,
|
ops::Range,
|
||||||
|
|
@ -169,6 +174,7 @@ pub(super) struct Memory {
|
||||||
tex_targets: Vec<[Point; 2]>,
|
tex_targets: Vec<[Point; 2]>,
|
||||||
data_buffer: Vec<u8>,
|
data_buffer: Vec<u8>,
|
||||||
out_address: DeviceAddress,
|
out_address: DeviceAddress,
|
||||||
|
color_transforms: ColorTransforms,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Point = [[f32; 2]; 4];
|
type Point = [[f32; 2]; 4];
|
||||||
|
|
@ -601,6 +607,7 @@ impl VulkanRenderer {
|
||||||
memory.tex_targets.clear();
|
memory.tex_targets.clear();
|
||||||
memory.fill_targets.clear();
|
memory.fill_targets.clear();
|
||||||
memory.data_buffer.clear();
|
memory.data_buffer.clear();
|
||||||
|
memory.color_transforms.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];
|
||||||
|
|
@ -667,10 +674,6 @@ impl VulkanRenderer {
|
||||||
if !bounds.intersects(&target) {
|
if !bounds.intersects(&target) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let tf = match pass {
|
|
||||||
RenderPass::BlendBuffer => blend_cd.transfer_function,
|
|
||||||
RenderPass::FrameBuffer => fb_cd.transfer_function,
|
|
||||||
};
|
|
||||||
let ops = &mut memory.ops_tmp[pass];
|
let ops = &mut memory.ops_tmp[pass];
|
||||||
let lo = memory.fill_targets.len();
|
let lo = memory.fill_targets.len();
|
||||||
for region in &memory.paint_regions[pass] {
|
for region in &memory.paint_regions[pass] {
|
||||||
|
|
@ -684,7 +687,15 @@ impl VulkanRenderer {
|
||||||
if lo == hi {
|
if lo == hi {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let color = fr.color.to_array2(tf, fr.alpha);
|
let target_cd = match pass {
|
||||||
|
RenderPass::BlendBuffer => blend_cd,
|
||||||
|
RenderPass::FrameBuffer => fb_cd,
|
||||||
|
};
|
||||||
|
let tf = target_cd.transfer_function;
|
||||||
|
let color = memory
|
||||||
|
.color_transforms
|
||||||
|
.apply_to_color(&fr.cd, target_cd, fr.color);
|
||||||
|
let color = color.to_array2(tf, fr.alpha);
|
||||||
let source_type = match color[3] < 1.0 {
|
let source_type = match color[3] < 1.0 {
|
||||||
false => TexSourceType::Opaque,
|
false => TexSourceType::Opaque,
|
||||||
true => TexSourceType::HasAlpha,
|
true => TexSourceType::HasAlpha,
|
||||||
|
|
@ -945,6 +956,7 @@ impl VulkanRenderer {
|
||||||
buf: CommandBuffer,
|
buf: CommandBuffer,
|
||||||
target: &VulkanImage,
|
target: &VulkanImage,
|
||||||
clear: Option<&Color>,
|
clear: Option<&Color>,
|
||||||
|
clear_cd: &LinearColorDescription,
|
||||||
pass: RenderPass,
|
pass: RenderPass,
|
||||||
target_cd: &ColorDescription,
|
target_cd: &ColorDescription,
|
||||||
) {
|
) {
|
||||||
|
|
@ -955,9 +967,12 @@ impl VulkanRenderer {
|
||||||
let clear_rects = &memory.clear_rects[pass];
|
let clear_rects = &memory.clear_rects[pass];
|
||||||
if let Some(clear) = clear {
|
if let Some(clear) = clear {
|
||||||
if clear_rects.is_not_empty() {
|
if clear_rects.is_not_empty() {
|
||||||
|
let color = memory
|
||||||
|
.color_transforms
|
||||||
|
.apply_to_color(clear_cd, target_cd, *clear);
|
||||||
let clear_value = ClearValue {
|
let clear_value = ClearValue {
|
||||||
color: ClearColorValue {
|
color: ClearColorValue {
|
||||||
float32: clear.to_array(target_cd.transfer_function),
|
float32: color.to_array(target_cd.transfer_function),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let use_load_clear = clear_rects.len() == 1 && {
|
let use_load_clear = clear_rects.len() == 1 && {
|
||||||
|
|
@ -1599,6 +1614,7 @@ impl VulkanRenderer {
|
||||||
fb_cd: &Rc<ColorDescription>,
|
fb_cd: &Rc<ColorDescription>,
|
||||||
opts: &[GfxApiOpt],
|
opts: &[GfxApiOpt],
|
||||||
clear: Option<&Color>,
|
clear: Option<&Color>,
|
||||||
|
clear_cd: &Rc<LinearColorDescription>,
|
||||||
region: &Region,
|
region: &Region,
|
||||||
blend_buffer: Option<Rc<VulkanImage>>,
|
blend_buffer: Option<Rc<VulkanImage>>,
|
||||||
blend_cd: &Rc<ColorDescription>,
|
blend_cd: &Rc<ColorDescription>,
|
||||||
|
|
@ -1611,6 +1627,7 @@ impl VulkanRenderer {
|
||||||
fb_cd,
|
fb_cd,
|
||||||
opts,
|
opts,
|
||||||
clear,
|
clear,
|
||||||
|
clear_cd,
|
||||||
region,
|
region,
|
||||||
blend_buffer,
|
blend_buffer,
|
||||||
blend_cd,
|
blend_cd,
|
||||||
|
|
@ -1779,6 +1796,7 @@ impl VulkanRenderer {
|
||||||
fb_cd: &Rc<ColorDescription>,
|
fb_cd: &Rc<ColorDescription>,
|
||||||
opts: &[GfxApiOpt],
|
opts: &[GfxApiOpt],
|
||||||
clear: Option<&Color>,
|
clear: Option<&Color>,
|
||||||
|
clear_cd: &Rc<LinearColorDescription>,
|
||||||
region: &Region,
|
region: &Region,
|
||||||
mut blend_buffer: Option<Rc<VulkanImage>>,
|
mut blend_buffer: Option<Rc<VulkanImage>>,
|
||||||
bb_cd: &Rc<ColorDescription>,
|
bb_cd: &Rc<ColorDescription>,
|
||||||
|
|
@ -1799,15 +1817,16 @@ impl VulkanRenderer {
|
||||||
zone!("blend buffer pass");
|
zone!("blend buffer pass");
|
||||||
let rp = RenderPass::BlendBuffer;
|
let rp = RenderPass::BlendBuffer;
|
||||||
self.blend_buffer_initial_barrier(buf.buffer, bb);
|
self.blend_buffer_initial_barrier(buf.buffer, bb);
|
||||||
self.begin_rendering(buf.buffer, bb, clear, rp, bb_cd);
|
self.begin_rendering(buf.buffer, bb, clear, clear_cd, rp, bb_cd);
|
||||||
self.record_draws(buf.buffer, bb, rp, bb_cd)?;
|
self.record_draws(buf.buffer, bb, rp, bb_cd)?;
|
||||||
self.end_rendering(buf.buffer);
|
self.end_rendering(buf.buffer);
|
||||||
self.blend_buffer_final_barrier(buf.buffer, bb);
|
self.blend_buffer_final_barrier(buf.buffer, bb);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
zone!("frame buffer pass");
|
zone!("frame buffer pass");
|
||||||
self.begin_rendering(buf.buffer, fb, clear, RenderPass::FrameBuffer, fb_cd);
|
let rp = RenderPass::FrameBuffer;
|
||||||
self.record_draws(buf.buffer, fb, RenderPass::FrameBuffer, fb_cd)?;
|
self.begin_rendering(buf.buffer, fb, clear, clear_cd, rp, fb_cd);
|
||||||
|
self.record_draws(buf.buffer, fb, rp, fb_cd)?;
|
||||||
if let Some(bb) = bb {
|
if let Some(bb) = bb {
|
||||||
self.blend_buffer_copy(buf.buffer, fb, fb_cd, bb, bb_cd)?;
|
self.blend_buffer_copy(buf.buffer, fb, fb_cd, bb, bb_cd)?;
|
||||||
}
|
}
|
||||||
|
|
@ -2028,3 +2047,45 @@ where
|
||||||
let y2 = y2.min(fb.height as i32);
|
let y2 = y2.min(fb.height as i32);
|
||||||
Some([x1, y1, x2, y2])
|
Some([x1, y1, x2, y2])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct ColorTransforms {
|
||||||
|
map: AHashMap<[LinearColorDescriptionId; 2], ColorTransform>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ColorTransform {
|
||||||
|
matrix: ColorMatrix,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColorTransforms {
|
||||||
|
fn get_or_create(
|
||||||
|
&mut self,
|
||||||
|
src: &LinearColorDescription,
|
||||||
|
dst: &ColorDescription,
|
||||||
|
) -> Option<&mut ColorTransform> {
|
||||||
|
if src.id == dst.linear.id {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let ct = match self.map.entry([src.id, dst.linear.id]) {
|
||||||
|
Entry::Occupied(o) => o.into_mut(),
|
||||||
|
Entry::Vacant(e) => {
|
||||||
|
let matrix = src.color_transform(&dst.linear);
|
||||||
|
let ct = ColorTransform { matrix };
|
||||||
|
e.insert(ct)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(ct)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_to_color(
|
||||||
|
&mut self,
|
||||||
|
src: &LinearColorDescription,
|
||||||
|
dst: &ColorDescription,
|
||||||
|
mut color: Color,
|
||||||
|
) -> Color {
|
||||||
|
if let Some(ct) = self.get_or_create(src, dst) {
|
||||||
|
color = ct.matrix * color;
|
||||||
|
};
|
||||||
|
color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue