1
0
Fork 0
forked from wry/wry

vulkan: use single push constant range per pipeline

This commit is contained in:
Julian Orth 2025-02-17 12:15:01 +01:00
parent 5a5f918f71
commit 20716cdd1e
11 changed files with 71 additions and 140 deletions

View file

@ -12,17 +12,7 @@ pub fn main() -> anyhow::Result<()> {
compile_simple("fill.frag")?; compile_simple("fill.frag")?;
compile_simple("fill.vert")?; compile_simple("fill.vert")?;
compile_simple("tex.vert")?; compile_simple("tex.vert")?;
compile_tex_frag("tex.frag.spv", false)?; compile_simple("tex.frag")?;
compile_tex_frag("tex.frag.mult.spv", true)?;
Ok(())
}
fn compile_tex_frag(out: &str, alpha_multiplier: bool) -> anyhow::Result<()> {
let mut opts = CompileOptions::new().unwrap();
if alpha_multiplier {
opts.add_macro_definition("ALPHA_MULTIPLIER", None);
}
compile_shader("tex.frag", out, Some(opts)).with_context(|| out.to_string())?;
Ok(()) Ok(())
} }

View file

@ -27,7 +27,6 @@ use {
pub(super) struct VulkanPipeline { pub(super) struct VulkanPipeline {
pub(super) vert: Rc<VulkanShader>, pub(super) vert: Rc<VulkanShader>,
pub(super) _frag: Rc<VulkanShader>, pub(super) _frag: Rc<VulkanShader>,
pub(super) frag_push_offset: u32,
pub(super) pipeline_layout: PipelineLayout, pub(super) pipeline_layout: PipelineLayout,
pub(super) pipeline: Pipeline, pub(super) pipeline: Pipeline,
pub(super) _frag_descriptor_set_layout: Option<Rc<VulkanDescriptorSetLayout>>, pub(super) _frag_descriptor_set_layout: Option<Rc<VulkanDescriptorSetLayout>>,
@ -39,46 +38,32 @@ pub(super) struct PipelineCreateInfo {
pub(super) frag: Rc<VulkanShader>, pub(super) frag: Rc<VulkanShader>,
pub(super) blend: bool, pub(super) blend: bool,
pub(super) src_has_alpha: bool, pub(super) src_has_alpha: bool,
pub(super) has_alpha_mult: bool,
pub(super) frag_descriptor_set_layout: Option<Rc<VulkanDescriptorSetLayout>>, pub(super) frag_descriptor_set_layout: Option<Rc<VulkanDescriptorSetLayout>>,
} }
impl VulkanDevice { impl VulkanDevice {
pub(super) fn create_pipeline<V, F>( pub(super) fn create_pipeline<P>(
&self, &self,
info: PipelineCreateInfo, info: PipelineCreateInfo,
) -> Result<Rc<VulkanPipeline>, VulkanError> { ) -> Result<Rc<VulkanPipeline>, VulkanError> {
self.create_pipeline_(info, size_of::<V>() as _, size_of::<F>() as _) self.create_pipeline_(info, size_of::<P>() as _)
} }
fn create_pipeline_( fn create_pipeline_(
&self, &self,
info: PipelineCreateInfo, info: PipelineCreateInfo,
vert_push_size: u32, push_size: u32,
frag_push_size: u32,
) -> Result<Rc<VulkanPipeline>, VulkanError> { ) -> Result<Rc<VulkanPipeline>, VulkanError> {
let pipeline_layout = { let pipeline_layout = {
let mut push_constant_ranges = ArrayVec::<_, 2>::new(); let mut push_constant_ranges = ArrayVec::<_, 1>::new();
let mut push_constant_offset = 0; if push_size > 0 {
if vert_push_size > 0 {
push_constant_ranges.push( push_constant_ranges.push(
PushConstantRange::default() PushConstantRange::default()
.stage_flags(ShaderStageFlags::VERTEX) .stage_flags(ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT)
.offset(0) .offset(0)
.size(vert_push_size), .size(push_size),
); );
push_constant_offset += vert_push_size;
}
if frag_push_size > 0 {
push_constant_ranges.push(
PushConstantRange::default()
.stage_flags(ShaderStageFlags::FRAGMENT)
.offset(push_constant_offset)
.size(frag_push_size),
);
#[expect(unused_assignments)]
{
push_constant_offset += frag_push_size;
}
} }
let mut descriptor_set_layouts = ArrayVec::<_, 1>::new(); let mut descriptor_set_layouts = ArrayVec::<_, 1>::new();
descriptor_set_layouts descriptor_set_layouts
@ -91,12 +76,18 @@ impl VulkanDevice {
}; };
let destroy_layout = let destroy_layout =
OnDrop(|| unsafe { self.device.destroy_pipeline_layout(pipeline_layout, None) }); OnDrop(|| unsafe { self.device.destroy_pipeline_layout(pipeline_layout, None) });
let mut frag_spec_data = ArrayVec::<_, 4>::new(); let mut frag_spec_data = ArrayVec::<_, 8>::new();
frag_spec_data.extend((info.src_has_alpha as u32).to_ne_bytes()); let mut frag_spec_entries = ArrayVec::<_, 2>::new();
let frag_spec_entries = [SpecializationMapEntry::default() let mut frag_spec_entry = |data: &[u8]| {
.constant_id(0) let entry = SpecializationMapEntry::default()
.size(4) .constant_id(frag_spec_entries.len() as _)
.offset(0)]; .size(data.len() as _)
.offset(frag_spec_data.len() as _);
frag_spec_entries.push(entry);
frag_spec_data.extend(data.iter().copied());
};
frag_spec_entry(&(info.src_has_alpha as u32).to_ne_bytes());
frag_spec_entry(&(info.has_alpha_mult as u32).to_ne_bytes());
let frag_spec = SpecializationInfo::default() let frag_spec = SpecializationInfo::default()
.map_entries(&frag_spec_entries) .map_entries(&frag_spec_entries)
.data(&frag_spec_data); .data(&frag_spec_data);
@ -173,7 +164,6 @@ impl VulkanDevice {
Ok(Rc::new(VulkanPipeline { Ok(Rc::new(VulkanPipeline {
vert: info.vert, vert: info.vert,
_frag: info.frag, _frag: info.frag,
frag_push_offset: vert_push_size,
pipeline_layout, pipeline_layout,
pipeline, pipeline,
_frag_descriptor_set_layout: info.frag_descriptor_set_layout, _frag_descriptor_set_layout: info.frag_descriptor_set_layout,

View file

@ -17,8 +17,7 @@ use {
pipeline::{PipelineCreateInfo, VulkanPipeline}, pipeline::{PipelineCreateInfo, VulkanPipeline},
semaphore::VulkanSemaphore, semaphore::VulkanSemaphore,
shaders::{ shaders::{
FillFragPushConstants, FillVertPushConstants, TexFragPushConstants, FillPushConstants, TexPushConstants, VulkanShader, FILL_FRAG, FILL_VERT, TEX_FRAG,
TexVertPushConstants, VulkanShader, FILL_FRAG, FILL_VERT, TEX_FRAG, TEX_FRAG_MULT,
TEX_VERT, TEX_VERT,
}, },
VulkanError, VulkanError,
@ -74,7 +73,6 @@ pub struct VulkanRenderer {
pub(super) fill_frag_shader: Rc<VulkanShader>, pub(super) fill_frag_shader: Rc<VulkanShader>,
pub(super) tex_vert_shader: Rc<VulkanShader>, pub(super) tex_vert_shader: Rc<VulkanShader>,
pub(super) tex_frag_shader: Rc<VulkanShader>, pub(super) tex_frag_shader: Rc<VulkanShader>,
pub(super) tex_frag_mult_shader: Rc<VulkanShader>,
pub(super) tex_descriptor_set_layout: Rc<VulkanDescriptorSetLayout>, pub(super) tex_descriptor_set_layout: Rc<VulkanDescriptorSetLayout>,
pub(super) defunct: Cell<bool>, pub(super) defunct: Cell<bool>,
pub(super) pending_cpu_jobs: CopyHashMap<u64, PendingJob>, pub(super) pending_cpu_jobs: CopyHashMap<u64, PendingJob>,
@ -159,7 +157,6 @@ impl VulkanDevice {
let tex_descriptor_set_layout = self.create_descriptor_set_layout(&sampler)?; let tex_descriptor_set_layout = self.create_descriptor_set_layout(&sampler)?;
let tex_vert_shader = self.create_shader(TEX_VERT)?; let tex_vert_shader = self.create_shader(TEX_VERT)?;
let tex_frag_shader = self.create_shader(TEX_FRAG)?; let tex_frag_shader = self.create_shader(TEX_FRAG)?;
let tex_frag_mult_shader = self.create_shader(TEX_FRAG_MULT)?;
let gfx_command_buffers = self.create_command_pool(self.graphics_queue_idx)?; let gfx_command_buffers = self.create_command_pool(self.graphics_queue_idx)?;
let transfer_command_buffers = self let transfer_command_buffers = self
.distinct_transfer_queue_family_idx .distinct_transfer_queue_family_idx
@ -217,7 +214,6 @@ impl VulkanDevice {
fill_frag_shader, fill_frag_shader,
tex_vert_shader, tex_vert_shader,
tex_frag_shader, tex_frag_shader,
tex_frag_mult_shader,
tex_descriptor_set_layout, tex_descriptor_set_layout,
defunct: Cell::new(false), defunct: Cell::new(false),
pending_cpu_jobs: Default::default(), pending_cpu_jobs: Default::default(),
@ -238,42 +234,31 @@ impl VulkanRenderer {
} }
let fill = self let fill = self
.device .device
.create_pipeline::<FillVertPushConstants, FillFragPushConstants>( .create_pipeline::<FillPushConstants>(PipelineCreateInfo {
PipelineCreateInfo { format,
format, vert: self.fill_vert_shader.clone(),
vert: self.fill_vert_shader.clone(), frag: self.fill_frag_shader.clone(),
frag: self.fill_frag_shader.clone(), blend: true,
blend: true, src_has_alpha: true,
src_has_alpha: true, has_alpha_mult: false,
frag_descriptor_set_layout: None, frag_descriptor_set_layout: None,
}, })?;
)?; let create_tex_pipeline = |src_has_alpha, has_alpha_mult| {
let create_tex_pipeline = |src_has_alpha| {
self.device self.device
.create_pipeline::<TexVertPushConstants, ()>(PipelineCreateInfo { .create_pipeline::<TexPushConstants>(PipelineCreateInfo {
format, format,
vert: self.tex_vert_shader.clone(), vert: self.tex_vert_shader.clone(),
frag: self.tex_frag_shader.clone(), frag: self.tex_frag_shader.clone(),
blend: src_has_alpha, blend: src_has_alpha || has_alpha_mult,
src_has_alpha, src_has_alpha,
has_alpha_mult,
frag_descriptor_set_layout: Some(self.tex_descriptor_set_layout.clone()), frag_descriptor_set_layout: Some(self.tex_descriptor_set_layout.clone()),
}) })
}; };
let create_tex_mult_pipeline = |src_has_alpha: bool| { let tex_opaque = create_tex_pipeline(false, false)?;
self.device let tex_alpha = create_tex_pipeline(true, false)?;
.create_pipeline::<TexVertPushConstants, TexFragPushConstants>(PipelineCreateInfo { let tex_mult_opaque = create_tex_pipeline(false, true)?;
format, let tex_mult_alpha = create_tex_pipeline(true, true)?;
vert: self.tex_vert_shader.clone(),
frag: self.tex_frag_mult_shader.clone(),
blend: true,
src_has_alpha,
frag_descriptor_set_layout: Some(self.tex_descriptor_set_layout.clone()),
})
};
let tex_opaque = create_tex_pipeline(false)?;
let tex_alpha = create_tex_pipeline(true)?;
let tex_mult_opaque = create_tex_mult_pipeline(false)?;
let tex_mult_alpha = create_tex_mult_pipeline(true)?;
let pipelines = Rc::new(VulkanFormatPipelines { let pipelines = Rc::new(VulkanFormatPipelines {
fill, fill,
tex: static_map! { tex: static_map! {
@ -514,26 +499,17 @@ impl VulkanRenderer {
GfxApiOpt::Sync => {} GfxApiOpt::Sync => {}
GfxApiOpt::FillRect(r) => { GfxApiOpt::FillRect(r) => {
bind(&pipelines.fill); bind(&pipelines.fill);
let vert = FillVertPushConstants { let push = FillPushConstants {
pos: r.rect.to_points(), pos: r.rect.to_points(),
};
let frag = FillFragPushConstants {
color: r.color.to_array_srgb(), color: r.color.to_array_srgb(),
}; };
unsafe { unsafe {
dev.cmd_push_constants( dev.cmd_push_constants(
buf, buf,
pipelines.fill.pipeline_layout, pipelines.fill.pipeline_layout,
ShaderStageFlags::VERTEX, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT,
0, 0,
uapi::as_bytes(&vert), uapi::as_bytes(&push),
);
dev.cmd_push_constants(
buf,
pipelines.fill.pipeline_layout,
ShaderStageFlags::FRAGMENT,
pipelines.fill.frag_push_offset,
uapi::as_bytes(&frag),
); );
dev.cmd_draw(buf, 4, 1, 0, 0); dev.cmd_draw(buf, 4, 1, 0, 0);
} }
@ -559,9 +535,10 @@ impl VulkanRenderer {
}; };
let pipeline = &pipelines.tex[copy_type][source_type]; let pipeline = &pipelines.tex[copy_type][source_type];
bind(pipeline); bind(pipeline);
let vert = TexVertPushConstants { let push = TexPushConstants {
pos: c.target.to_points(), pos: c.target.to_points(),
tex_pos: c.source.to_points(), tex_pos: c.source.to_points(),
alpha: c.alpha.unwrap_or_default(),
}; };
let image_info = DescriptorImageInfo::default() let image_info = DescriptorImageInfo::default()
.image_view(tex.texture_view) .image_view(tex.texture_view)
@ -580,20 +557,10 @@ impl VulkanRenderer {
dev.cmd_push_constants( dev.cmd_push_constants(
buf, buf,
pipeline.pipeline_layout, pipeline.pipeline_layout,
ShaderStageFlags::VERTEX, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT,
0, 0,
uapi::as_bytes(&vert), uapi::as_bytes(&push),
); );
if let Some(alpha) = c.alpha {
let frag = TexFragPushConstants { alpha };
dev.cmd_push_constants(
buf,
pipeline.pipeline_layout,
ShaderStageFlags::FRAGMENT,
size_of_val(&vert) as _,
uapi::as_bytes(&frag),
);
}
dev.cmd_draw(buf, 4, 1, 0, 0); dev.cmd_draw(buf, 4, 1, 0, 0);
} }
} }

View file

@ -9,7 +9,6 @@ pub const FILL_VERT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/fill.vert
pub const FILL_FRAG: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/fill.frag.spv")); pub const FILL_FRAG: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/fill.frag.spv"));
pub const TEX_VERT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/tex.vert.spv")); pub const TEX_VERT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/tex.vert.spv"));
pub const TEX_FRAG: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/tex.frag.spv")); pub const TEX_FRAG: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/tex.frag.spv"));
pub const TEX_FRAG_MULT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/tex.frag.mult.spv"));
pub struct VulkanShader { pub struct VulkanShader {
pub(super) device: Rc<VulkanDevice>, pub(super) device: Rc<VulkanDevice>,
@ -18,35 +17,22 @@ pub struct VulkanShader {
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[repr(C)] #[repr(C)]
pub struct FillVertPushConstants { pub struct FillPushConstants {
pub pos: [[f32; 2]; 4], pub pos: [[f32; 2]; 4],
}
unsafe impl Packed for FillVertPushConstants {}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct FillFragPushConstants {
pub color: [f32; 4], pub color: [f32; 4],
} }
unsafe impl Packed for FillFragPushConstants {} unsafe impl Packed for FillPushConstants {}
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[repr(C)] #[repr(C)]
pub struct TexVertPushConstants { pub struct TexPushConstants {
pub pos: [[f32; 2]; 4], pub pos: [[f32; 2]; 4],
pub tex_pos: [[f32; 2]; 4], pub tex_pos: [[f32; 2]; 4],
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct TexFragPushConstants {
pub alpha: f32, pub alpha: f32,
} }
unsafe impl Packed for TexVertPushConstants {} unsafe impl Packed for TexPushConstants {}
unsafe impl Packed for TexFragPushConstants {}
impl VulkanDevice { impl VulkanDevice {
pub(super) fn create_shader( pub(super) fn create_shader(

View file

@ -0,0 +1,4 @@
layout(push_constant, std430) uniform Data {
layout(offset = 0) vec2 pos[4];
layout(offset = 32) vec4 color;
} data;

View file

@ -1,10 +1,7 @@
#version 450 #version 450
#include "frag_spec_const.glsl" #include "frag_spec_const.glsl"
#include "fill.common.glsl"
layout(push_constant, std430) uniform Data {
layout(offset = 32) vec4 color;
} data;
layout(location = 0) out vec4 out_color; layout(location = 0) out vec4 out_color;

View file

@ -1,9 +1,7 @@
#version 450 #version 450
//#extension GL_EXT_debug_printf : enable //#extension GL_EXT_debug_printf : enable
layout(push_constant, std430) uniform Data { #include "fill.common.glsl"
layout(offset = 0) vec2 pos[4];
} data;
void main() { void main() {
vec2 pos; vec2 pos;

View file

@ -1 +1,2 @@
layout(constant_id = 0) const bool src_has_alpha = false; layout(constant_id = 0) const bool src_has_alpha = false;
layout(constant_id = 1) const bool has_alpha_multiplier = false;

View file

@ -0,0 +1,5 @@
layout(push_constant, std430) uniform Data {
layout(offset = 0) vec2 pos[4];
layout(offset = 32) vec2 tex_pos[4];
layout(offset = 64) float mul;
} data;

View file

@ -1,24 +1,20 @@
#version 450 #version 450
#include "frag_spec_const.glsl" #include "frag_spec_const.glsl"
#include "tex.common.glsl"
#ifdef ALPHA_MULTIPLIER
layout(push_constant, std430) uniform Data {
layout(offset = 64) float mul;
} data;
#endif
layout(set = 0, binding = 0) uniform sampler2D tex; layout(set = 0, binding = 0) uniform sampler2D tex;
layout(location = 0) in vec2 tex_pos; layout(location = 0) in vec2 tex_pos;
layout(location = 0) out vec4 out_color; layout(location = 0) out vec4 out_color;
void main() { void main() {
#ifdef ALPHA_MULTIPLIER if (has_alpha_multiplier) {
if (src_has_alpha) { if (src_has_alpha) {
out_color = textureLod(tex, tex_pos, 0) * data.mul; out_color = textureLod(tex, tex_pos, 0) * data.mul;
} else {
out_color = vec4(textureLod(tex, tex_pos, 0).rgb * data.mul, data.mul);
}
} else { } else {
out_color = vec4(textureLod(tex, tex_pos, 0).rgb * data.mul, data.mul); out_color = textureLod(tex, tex_pos, 0);
} }
#else // !ALPHA_MULTIPLIER
out_color = textureLod(tex, tex_pos, 0);
#endif
} }

View file

@ -1,10 +1,7 @@
#version 450 #version 450
//#extension GL_EXT_debug_printf : enable //#extension GL_EXT_debug_printf : enable
layout(push_constant, std430) uniform Data { #include "tex.common.glsl"
layout(offset = 0) vec2 pos[4];
layout(offset = 32) vec2 tex_pos[4];
} data;
layout(location = 0) out vec2 tex_pos; layout(location = 0) out vec2 tex_pos;