From 56a6012a7c1d7f22f262abca337e6d181e681a4b Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 21 Feb 2026 14:10:59 +0100 Subject: [PATCH] vulkan: implement all alpha modes --- src/gfx_apis/vulkan.rs | 5 +++++ src/gfx_apis/vulkan/alpha_modes.rs | 15 +++++++++++++++ src/gfx_apis/vulkan/pipeline.rs | 15 ++++++++++----- src/gfx_apis/vulkan/renderer.rs | 16 ++++++++++++++-- src/gfx_apis/vulkan/shaders/alpha_modes.glsl | 8 ++++++++ .../vulkan/shaders/frag_spec_const.glsl | 1 + src/gfx_apis/vulkan/shaders/tex.frag | 8 ++++++-- .../vulkan/shaders_bin/legacy_fill.frag.spv | Bin 964 -> 1016 bytes .../vulkan/shaders_bin/legacy_tex.frag.spv | Bin 1800 -> 1852 bytes src/gfx_apis/vulkan/shaders_bin/out.frag.spv | Bin 13824 -> 13876 bytes src/gfx_apis/vulkan/shaders_bin/tex.frag.spv | Bin 14596 -> 15032 bytes src/gfx_apis/vulkan/shaders_hash.txt | 5 +++-- 12 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 src/gfx_apis/vulkan/alpha_modes.rs create mode 100644 src/gfx_apis/vulkan/shaders/alpha_modes.glsl diff --git a/src/gfx_apis/vulkan.rs b/src/gfx_apis/vulkan.rs index ad0a5943..36662e47 100644 --- a/src/gfx_apis/vulkan.rs +++ b/src/gfx_apis/vulkan.rs @@ -1,4 +1,5 @@ mod allocator; +mod alpha_modes; mod blend_buffer; mod bo_allocator; mod buffer_cache; @@ -387,6 +388,10 @@ impl GfxContext for Context { self.0.device.descriptor_buffer.is_some() } + fn supports_alpha_modes(&self) -> bool { + self.0.device.descriptor_buffer.is_some() + } + fn create_dmabuf_buffer( &self, dmabuf: &OwnedFd, diff --git a/src/gfx_apis/vulkan/alpha_modes.rs b/src/gfx_apis/vulkan/alpha_modes.rs new file mode 100644 index 00000000..9480c2b0 --- /dev/null +++ b/src/gfx_apis/vulkan/alpha_modes.rs @@ -0,0 +1,15 @@ +use crate::gfx_api::AlphaMode; + +pub const AM_PREMULTIPLIED_ELECTRICAL: u32 = 0; +pub const AM_PREMULTIPLIED_OPTICAL: u32 = 1; +pub const AM_STRAIGHT: u32 = 2; + +impl AlphaMode { + pub fn to_vulkan(self) -> u32 { + match self { + AlphaMode::PremultipliedElectrical => AM_PREMULTIPLIED_ELECTRICAL, + AlphaMode::PremultipliedOptical => AM_PREMULTIPLIED_OPTICAL, + AlphaMode::Straight => AM_STRAIGHT, + } + } +} diff --git a/src/gfx_apis/vulkan/pipeline.rs b/src/gfx_apis/vulkan/pipeline.rs index 3e446eb2..5351a483 100644 --- a/src/gfx_apis/vulkan/pipeline.rs +++ b/src/gfx_apis/vulkan/pipeline.rs @@ -1,7 +1,10 @@ use { - crate::gfx_apis::vulkan::{ - VulkanError, descriptor::VulkanDescriptorSetLayout, device::VulkanDevice, - shaders::VulkanShader, + crate::{ + gfx_api::AlphaMode, + gfx_apis::vulkan::{ + VulkanError, descriptor::VulkanDescriptorSetLayout, device::VulkanDevice, + shaders::VulkanShader, + }, }, arrayvec::ArrayVec, ash::{ @@ -37,6 +40,7 @@ pub(super) struct PipelineCreateInfo { pub(super) blend: bool, pub(super) src_has_alpha: bool, pub(super) has_alpha_mult: bool, + pub(super) alpha_mode: AlphaMode, pub(super) eotf: u32, pub(super) inv_eotf: u32, pub(super) descriptor_set_layouts: ArrayVec, 2>, @@ -76,8 +80,8 @@ impl VulkanDevice { }; let destroy_layout = on_drop(|| unsafe { self.device.destroy_pipeline_layout(pipeline_layout, None) }); - let mut frag_spec_data = ArrayVec::<_, { 5 * 4 }>::new(); - let mut frag_spec_entries = ArrayVec::<_, 5>::new(); + let mut frag_spec_data = ArrayVec::<_, { 6 * 4 }>::new(); + let mut frag_spec_entries = ArrayVec::<_, 6>::new(); let mut frag_spec_entry = |data: &[u8]| { let entry = SpecializationMapEntry::default() .constant_id(frag_spec_entries.len() as _) @@ -91,6 +95,7 @@ impl VulkanDevice { frag_spec_entry(&info.eotf.to_ne_bytes()); frag_spec_entry(&info.inv_eotf.to_ne_bytes()); frag_spec_entry(&(info.has_color_management_data as u32).to_ne_bytes()); + frag_spec_entry(&info.alpha_mode.to_vulkan().to_ne_bytes()); let frag_spec = SpecializationInfo::default() .map_entries(&frag_spec_entries) .data(&frag_spec_data); diff --git a/src/gfx_apis/vulkan/renderer.rs b/src/gfx_apis/vulkan/renderer.rs index 29a983a2..44d11c2c 100644 --- a/src/gfx_apis/vulkan/renderer.rs +++ b/src/gfx_apis/vulkan/renderer.rs @@ -8,8 +8,8 @@ use { }, cpu_worker::PendingJob, gfx_api::{ - AcquireSync, BufferResv, BufferResvUser, GfxApiOpt, GfxBlendBuffer, GfxFormat, - GfxTexture, GfxWriteModifier, ReleaseSync, SyncFile, + AcquireSync, AlphaMode, BufferResv, BufferResvUser, GfxApiOpt, GfxBlendBuffer, + GfxFormat, GfxTexture, GfxWriteModifier, ReleaseSync, SyncFile, }, gfx_apis::vulkan::{ VulkanError, @@ -209,6 +209,7 @@ struct VulkanTexOp { alpha: f32, source_type: TexSourceType, copy_type: TexCopyType, + alpha_mode: AlphaMode, range_address: DeviceAddress, instances: u32, tex_cd: Rc, @@ -258,6 +259,7 @@ type FillPipelines = Rc>>; struct TexPipelineKey { tex_copy_type: TexCopyType, tex_source_type: TexSourceType, + tex_alpha_mode: AlphaMode, eotf: VulkanEotf, has_color_management_data: bool, } @@ -431,6 +433,7 @@ impl VulkanRenderer { blend: src_has_alpha, src_has_alpha, has_alpha_mult: false, + alpha_mode: AlphaMode::PremultipliedOptical, // all transformations are applied in the compositor eotf: EOTF_LINEAR, inv_eotf: EOTF_LINEAR, @@ -474,11 +477,16 @@ impl VulkanRenderer { tex_cd: &ColorDescription, tex_copy_type: TexCopyType, tex_source_type: TexSourceType, + mut tex_alpha_mode: AlphaMode, has_color_management_data: bool, ) -> Result, VulkanError> { + if tex_source_type == TexSourceType::Opaque { + tex_alpha_mode = AlphaMode::PremultipliedElectrical; + } let key = TexPipelineKey { tex_copy_type, tex_source_type, + tex_alpha_mode, eotf: tex_cd.eotf.to_vulkan(), has_color_management_data, }; @@ -505,6 +513,7 @@ impl VulkanRenderer { blend: src_has_alpha || has_alpha_mult, src_has_alpha, has_alpha_mult, + alpha_mode: key.tex_alpha_mode, eotf: key.eotf.to_vulkan(), inv_eotf: pipelines.eotf.to_vulkan(), descriptor_set_layouts: self.tex_descriptor_set_layouts.clone(), @@ -543,6 +552,7 @@ impl VulkanRenderer { blend: false, src_has_alpha: true, has_alpha_mult: false, + alpha_mode: AlphaMode::PremultipliedElectrical, eotf: key.eotf.to_vulkan(), inv_eotf: fb_eotf.to_vulkan(), descriptor_set_layouts, @@ -886,6 +896,7 @@ impl VulkanRenderer { alpha: ct.alpha.unwrap_or_default(), source_type, copy_type, + alpha_mode: ct.alpha_mode, range_address: 0, instances: 0, tex_cd: ct.cd.clone(), @@ -1333,6 +1344,7 @@ impl VulkanRenderer { &c.tex_cd, c.copy_type, c.source_type, + c.alpha_mode, c.color_management_data_address.is_some(), )?; bind(&pipeline); diff --git a/src/gfx_apis/vulkan/shaders/alpha_modes.glsl b/src/gfx_apis/vulkan/shaders/alpha_modes.glsl new file mode 100644 index 00000000..1bb87a3e --- /dev/null +++ b/src/gfx_apis/vulkan/shaders/alpha_modes.glsl @@ -0,0 +1,8 @@ +#ifndef ALPHA_MODES_GLSL +#define ALPHA_MODES_GLSL + +#define AM_PREMULTIPLIED_ELECTRICAL 0 +#define AM_PREMULTIPLIED_OPTICAL 1 +#define AM_STRAIGHT 2 + +#endif diff --git a/src/gfx_apis/vulkan/shaders/frag_spec_const.glsl b/src/gfx_apis/vulkan/shaders/frag_spec_const.glsl index cf7f8a7c..29e3b2ef 100644 --- a/src/gfx_apis/vulkan/shaders/frag_spec_const.glsl +++ b/src/gfx_apis/vulkan/shaders/frag_spec_const.glsl @@ -6,5 +6,6 @@ layout(constant_id = 1) const bool has_alpha_multiplier = false; layout(constant_id = 2) const uint eotf = 0; layout(constant_id = 3) const uint inv_eotf = 0; layout(constant_id = 4) const bool has_matrix = false; +layout(constant_id = 5) const uint alpha_mode = 0; #endif diff --git a/src/gfx_apis/vulkan/shaders/tex.frag b/src/gfx_apis/vulkan/shaders/tex.frag index df6ee5ec..e1ccacda 100644 --- a/src/gfx_apis/vulkan/shaders/tex.frag +++ b/src/gfx_apis/vulkan/shaders/tex.frag @@ -8,6 +8,7 @@ #include "tex.common.glsl" #include "tex_set.glsl" #include "eotfs.glsl" +#include "alpha_modes.glsl" layout(set = 0, binding = 0) uniform sampler sam; layout(location = 0) in vec2 tex_pos; @@ -15,12 +16,15 @@ layout(location = 0) out vec4 out_color; void main() { vec4 c = textureLod(sampler2D(tex, sam), tex_pos, 0); - if (eotf != inv_eotf || has_matrix) { + if (eotf != inv_eotf || has_matrix || alpha_mode != AM_PREMULTIPLIED_ELECTRICAL) { vec3 rgb = c.rgb; - if (src_has_alpha) { + if (src_has_alpha && alpha_mode == AM_PREMULTIPLIED_ELECTRICAL) { rgb /= mix(c.a, 1.0, c.a == 0.0); } rgb = apply_eotf(rgb); + if (src_has_alpha && alpha_mode == AM_PREMULTIPLIED_OPTICAL) { + rgb /= mix(c.a, 1.0, c.a == 0.0); + } if (has_matrix) { rgb = (cm_data.matrix * vec4(rgb, 1.0)).rgb; } diff --git a/src/gfx_apis/vulkan/shaders_bin/legacy_fill.frag.spv b/src/gfx_apis/vulkan/shaders_bin/legacy_fill.frag.spv index 961877a707b4260e86b4b1b16952ea5f26bbee82..b1377f0a9e52111fdeb7bb355adeacd7c54a8d4c 100644 GIT binary patch delta 82 zcmX@Y{)3&DnMs+Qfq{{Mn}L@>b|Y^yqYx_tD}xLJ14Cj?K}KSHZhlJYW+QJi0qYx_tD}yZq14Cj?K}KSHZhlJYEmbC1XL@+Qg zxHGUYgfW4PW?E4g#pBmf{1NiFVd11keF zg9;M^Ls5DX11kd?gE|ufLvc}Zd`4n%JXjqANDT{v8509TL1Iy2E||~G;5GRpo3yDH z69X9JCYBUsRzOtxFflMB=f2s7c669U;sM{><3nc&dr=0-Hf)NAORV|%D}+j&cFf= z0uUdh*`0xz0pv-LKRp;&z-*8>3j+g#2LmgE*W`no!i-*%4{{0DgFLRt019=8IUv3g z5Kx~k?${+%2Hb@Ml79_?2bz1=wC?FUZVEjS^UkdCXSO|eM zfy@FqvS@N6m#}UzRH*~lC}watL9Ay1vq7pQpjMZFJjB?!`6`zv3qt}U132k` z6lp{G@*v#|3=Ad=Yz&tf7#I|o7#LPFK-7WcVB(5Q3=GQ{7#L)kAZiR5n8E5nNe!k( zgNcD*6&AgkObqo5%NZEJkpfZ#vs{OXfq|KUfdR(1ga$6mKr18zL2@v0YbFM`c_1|s z3@i+uObiU1ObiU5NR@*|I7m!^frY`Fsh)uWfs@GWUdP}5tLX!wt&2($Hc$@5{IeL z$D+o7iGcwmzJ-AmoKg)zsSqS+&A`C05?o#}Fc>j0Fc>m1FxW6KFn|mNSpagjF%tv0 zL=9kI1AD`S38EIH9)vp>Si$0^ObiSlwIF#rXekU5`^mrr_YBCR5OeDp7|fvtgA{{8 z8pOAR8fL-7z+lS204}CM@}STHiGf1P7Adqq$=`;FfdM223M~*D77}(?Lc*SjfdM4$ zSPuCMSRCevIH)7~ph+{HiGcwm22uyJ7$gSr1k4f;4bz_h)ep6l zArWe)Jg6jw1#S`(0|Q7QC=x)1f)s(oV49Mlnm|QAOiv0_4=9pAdO&JGVlX{vP(7g1 z8>S~6ss|K6cJ&O*3?M}yL6GZVg&2qi1!ERS6*L$@MSdm|0|Q756pSD?NKFos8cJ%%sfDz`)4B&A`i0Igz)Vv3z5zDH}gCg8~x+Ls5DX11kd?gYx9NY~s2G zObiSKiA9OI3=9mc4D1YMObiUp`8oMTzKMB>>8ZJ?c_l81C5a4d46F=hlNH&86)l(; z7?N}2Q$V7u3@i-JC?;?)giQ`*m(Pu1VqgGkWME)mV_;(d@fjEx7|K$MN-~pEi$QEQ z1{Sb5BLf3NZfOn!$g~6|28OWIqLS1KkUka$5FezrAio&w1`r>lz9h9G9wf%fz{-#` z`60WoW)c%f9jXl=6H}NN7{HDN`;e8Pe6uV^H)Fjr6DWirTHG0!!5#;h;K9HGW`kr{ z7#J8lKpqE4FfcH%GcYg+pouAi6f!U{xHGUYfPzMm0b(wUuY|-8gWAc+z#zl`vJ@05 zAhSW1#7v&ZC2R^30r?MPECdfIS#QX|%y5~3fdLd|+6*iV35*O3YD^3a z%nS?+5)3R1rc4YBoJehh!0AHoD2*MAo*0NJjh`nei<|*K_LiI58{_Y#mpF38JH&Pis>tYvMwn7 zfmDDJ0x07m^PMNxij_OcLqqNt0}F#J69a=B69WTC><0rAm~G3z0*)y~CI$v>CI$w7 z1`cqlR$^jc0EsD1c9asX2iXM@`Od)1po(N7DE?KL7{Fp66G3c8237`8@=}MI2uc?q zTR^_kU}9hZiNn-rVo{^T#J~U&-@?EOPGj0k4D}2kL2CvEhLzy5gMmSZiGe|ziGjg} zfq?;JD98ek=XIGFz-3wh0~^>IdQ1?tAoU>J0WQ-R81$JK7(i-4@^%c6au6i;lYt5D z8IVUI=GHSX7(xvODF%f!h;Ios%!rAB!IXi40VEER2Za_$3=~=>NTDUe#K2(8#J~U& z1BDid4GIZRinn570GAeS3=9k)OF^mMnu&n{ByL;JzykJ-4b%~V;PRS*!4?z(PzzvU zc2F@;nE?~Chl+ue1~9OLBiw-rq93FlEYHBeFp+^3Ea%9?zyPuwqz05ActJty#Kgb= zl5m8l2#^RUz+nCX(IB^jRJ%Z(3JMQUg#hBi!pjxpR|W=fMFElrg%?N+6khHiH!?6V zfYK`{b-6JyFo48B;RRxY!pnhyp`O75OVaUVVgQT79N`6ZL?1MwyqOpnKw=PRLAhAbuq29O#M8{`;J(UbwYA`V{lt2YRE`w#PQc#nMiGcy60VEGH92No~Iph!kg#?HXiy9CO e3y}(Fh=BBhN`DalF9Rck1p_04+2*sduVnz`pxvJU diff --git a/src/gfx_apis/vulkan/shaders_hash.txt b/src/gfx_apis/vulkan/shaders_hash.txt index 9d144084..ab855a2d 100644 --- a/src/gfx_apis/vulkan/shaders_hash.txt +++ b/src/gfx_apis/vulkan/shaders_hash.txt @@ -1,8 +1,9 @@ +302a9f250bdc4f8e0e71a9f77c9a8a7aa55fd003bc91c2422a700c4abd83f54e src/gfx_apis/vulkan/shaders/alpha_modes.glsl b6a0df1e231fab533499329636b7a580384784418baee06c147af5fcc384cf5c src/gfx_apis/vulkan/shaders/eotfs.glsl 8a38df18851cd13884499820f26939fb7319f45d913d867f254d8118d59fb117 src/gfx_apis/vulkan/shaders/fill.common.glsl 21c488d12aa5ad2f109ec44cb856dfe837e02ea9025b5ed64439d742c17cbf30 src/gfx_apis/vulkan/shaders/fill.frag 4fb481d8d73afdfb0d8f077eb8665d86f06c8a32a91e44ed369ef5dff554646d src/gfx_apis/vulkan/shaders/fill.vert -63af15c4e00587a7bb8494934c88d9874712a511217829b50f3c08fa3c461082 src/gfx_apis/vulkan/shaders/frag_spec_const.glsl +f93524fd077bc9984702b1e0f92232f80bfe28a0a92439dc164c1ea41fd16d64 src/gfx_apis/vulkan/shaders/frag_spec_const.glsl c315a064b48dd5bdb607a6b79c30d31b6e59ffec69e93d50ab875abf97c41bbf src/gfx_apis/vulkan/shaders/legacy/fill.common.glsl 590d061b97446fc501158609eaf098b71bc7b328c008b586ff36613ce690d618 src/gfx_apis/vulkan/shaders/legacy/fill.frag ad22a79e1a88a12daa40c0a2b953084c129a408297c8ca544d60e0b6001470b9 src/gfx_apis/vulkan/shaders/legacy/fill.vert @@ -13,6 +14,6 @@ e0a8769dd7938dd02e66db9e9048ed6bef8f8c42671f2e2c7a7976a6d498f685 src/gfx_apis/vu 5069f619c7d722815a022e2d84720a2d8290af49a3ed49ea0cd26b52115cc39a src/gfx_apis/vulkan/shaders/out.frag 0adc7e12328c15fb3e7e6c8b8701a182223c2f15337e14131f41dd247e697809 src/gfx_apis/vulkan/shaders/out.vert e22d4d3318a350def8ef19c7b27dc6a308a84c2fe9d7c02b81107f72073cd481 src/gfx_apis/vulkan/shaders/tex.common.glsl -06993d4d882fe5c651e5ab54f0116b9622352a97f3575985076ef464b472dd39 src/gfx_apis/vulkan/shaders/tex.frag +1f196cee646a934072beb3e5648a5042c035953d9a0c26b0a22e330c2f8bb994 src/gfx_apis/vulkan/shaders/tex.frag 423cf327c9fcc4070dbf75321c1224a1589b6cf3d2f1ea5e8bd0362e1a9f3aa1 src/gfx_apis/vulkan/shaders/tex.vert b982f7101c22931a33b32dce3408387f3392c0f0ad0ca5852da265b0d12856bb src/gfx_apis/vulkan/shaders/tex_set.glsl