rework rendering backend

This commit is contained in:
galister
2025-04-06 22:12:56 +09:00
parent 55867e803f
commit cf29682e66
27 changed files with 1135 additions and 1181 deletions

View File

@@ -20,12 +20,6 @@ use {ash::vk, std::os::raw::c_void};
pub type Vert2Buf = Subbuffer<[Vert2Uv]>;
pub type IndexBuf = Subbuffer<[u16]>;
pub type LegacyPipeline = WlxPipeline<WlxPipelineLegacy>;
pub type DynamicPipeline = WlxPipeline<WlxPipelineDynamic>;
pub type LegacyPass = WlxPass<WlxPipelineLegacy>;
pub type DynamicPass = WlxPass<WlxPipelineDynamic>;
use vulkano::{
buffer::{
allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo},
@@ -35,10 +29,9 @@ use vulkano::{
allocator::{StandardCommandBufferAllocator, StandardCommandBufferAllocatorCreateInfo},
sys::{CommandBufferBeginInfo, RawRecordingCommandBuffer},
CommandBuffer, CommandBufferExecFuture, CommandBufferInheritanceInfo,
CommandBufferInheritanceRenderPassInfo, CommandBufferInheritanceRenderPassType,
CommandBufferInheritanceRenderingInfo, CommandBufferLevel, CommandBufferUsage,
CopyBufferToImageInfo, RecordingCommandBuffer, RenderPassBeginInfo,
RenderingAttachmentInfo, RenderingInfo, SubpassBeginInfo, SubpassContents, SubpassEndInfo,
CommandBufferInheritanceRenderPassType, CommandBufferInheritanceRenderingInfo,
CommandBufferLevel, CommandBufferUsage, CopyBufferToImageInfo, RecordingCommandBuffer,
RenderingAttachmentInfo, RenderingInfo, SubpassContents,
},
descriptor_set::{
allocator::StandardDescriptorSetAllocator, DescriptorSet, WriteDescriptorSet,
@@ -52,8 +45,7 @@ use vulkano::{
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
sys::RawImage,
view::ImageView,
Image, ImageCreateInfo, ImageLayout, ImageTiling, ImageType, ImageUsage, SampleCount,
SubresourceLayout,
Image, ImageCreateInfo, ImageLayout, ImageTiling, ImageType, ImageUsage, SubresourceLayout,
},
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
memory::{
@@ -80,11 +72,7 @@ use vulkano::{
layout::PipelineDescriptorSetLayoutCreateInfo,
DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout,
},
render_pass::{
AttachmentDescription, AttachmentLoadOp, AttachmentReference, AttachmentStoreOp,
Framebuffer, FramebufferCreateInfo, RenderPass, RenderPassCreateInfo, Subpass,
SubpassDescription,
},
render_pass::{AttachmentLoadOp, AttachmentStoreOp},
shader::ShaderModule,
sync::{
fence::Fence, future::NowFuture, AccessFlags, DependencyInfo, GpuFuture,
@@ -109,6 +97,8 @@ pub struct Vert2Uv {
pub in_uv: [f32; 2],
}
pub const SWAPCHAIN_FORMAT: Format = Format::R8G8B8A8_SRGB;
pub const INDICES: [u16; 6] = [2, 1, 0, 1, 2, 3];
pub const BLEND_ALPHA: AttachmentBlend = AttachmentBlend {
@@ -546,6 +536,7 @@ impl WlxGraphics {
Ok(Arc::new(me))
}
#[allow(clippy::type_complexity)]
#[cfg(feature = "uidev")]
pub fn new_window() -> anyhow::Result<(
Arc<Self>,
@@ -572,6 +563,7 @@ impl WlxGraphics {
},
)?;
#[allow(deprecated)]
let window = Arc::new(
event_loop
.create_window(Window::default_attributes())
@@ -925,54 +917,12 @@ impl WlxGraphics {
pub fn create_pipeline(
self: &Arc<Self>,
render_target: Arc<ImageView>,
vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>,
format: Format,
blend: Option<AttachmentBlend>,
) -> anyhow::Result<Arc<LegacyPipeline>> {
Ok(Arc::new(LegacyPipeline::new(
render_target,
self.clone(),
vert,
frag,
format,
blend,
)?))
}
#[allow(clippy::too_many_arguments)]
pub fn create_pipeline_with_layouts(
self: &Arc<Self>,
render_target: Arc<ImageView>,
vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>,
format: Format,
blend: Option<AttachmentBlend>,
initial_layout: ImageLayout,
final_layout: ImageLayout,
) -> anyhow::Result<Arc<LegacyPipeline>> {
Ok(Arc::new(LegacyPipeline::new_with_layout(
render_target,
self.clone(),
vert,
frag,
format,
blend,
initial_layout,
final_layout,
)?))
}
#[allow(dead_code)]
pub fn create_pipeline_dynamic(
self: &Arc<Self>,
vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>,
format: Format,
blend: Option<AttachmentBlend>,
) -> anyhow::Result<Arc<DynamicPipeline>> {
Ok(Arc::new(DynamicPipeline::new(
) -> anyhow::Result<Arc<WlxPipeline>> {
Ok(Arc::new(WlxPipeline::new(
self.clone(),
vert,
frag,
@@ -1001,7 +951,6 @@ impl WlxGraphics {
})
}
#[allow(dead_code)]
pub fn transition_layout(
&self,
image: Arc<Image>,
@@ -1066,22 +1015,7 @@ pub struct WlxCommandBuffer {
pub command_buffer: RecordingCommandBuffer,
}
#[allow(dead_code)]
impl WlxCommandBuffer {
pub fn begin_render_pass(&mut self, pipeline: &LegacyPipeline) -> anyhow::Result<()> {
self.command_buffer.begin_render_pass(
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 0.0, 0.0].into())],
..RenderPassBeginInfo::framebuffer(pipeline.data.framebuffer.clone())
},
SubpassBeginInfo {
contents: SubpassContents::SecondaryCommandBuffers,
..Default::default()
},
)?;
Ok(())
}
pub fn begin_rendering(&mut self, render_target: Arc<ImageView>) -> anyhow::Result<()> {
self.command_buffer.begin_rendering(RenderingInfo {
contents: SubpassContents::SecondaryCommandBuffers,
@@ -1096,7 +1030,7 @@ impl WlxCommandBuffer {
Ok(())
}
pub fn run_ref<D>(&mut self, pass: &WlxPass<D>) -> anyhow::Result<()> {
pub fn run_ref(&mut self, pass: &WlxPass) -> anyhow::Result<()> {
self.command_buffer
.execute_commands(pass.command_buffer.clone())?;
Ok(())
@@ -1149,12 +1083,6 @@ impl WlxCommandBuffer {
Ok(image)
}
pub fn end_render_pass(&mut self) -> anyhow::Result<()> {
self.command_buffer
.end_render_pass(SubpassEndInfo::default())?;
Ok(())
}
pub fn end_rendering(&mut self) -> anyhow::Result<()> {
self.command_buffer.end_rendering()?;
Ok(())
@@ -1177,22 +1105,13 @@ impl WlxCommandBuffer {
}
}
pub struct WlxPipelineDynamic {}
pub struct WlxPipelineLegacy {
pub render_pass: Arc<RenderPass>,
pub framebuffer: Arc<Framebuffer>,
}
pub struct WlxPipeline<D> {
pub struct WlxPipeline {
pub graphics: Arc<WlxGraphics>,
pub pipeline: Arc<GraphicsPipeline>,
pub format: Format,
pub data: D,
}
#[allow(dead_code)]
impl WlxPipeline<WlxPipelineDynamic> {
impl WlxPipeline {
fn new(
graphics: Arc<WlxGraphics>,
vert: Arc<ShaderModule>,
@@ -1248,7 +1167,6 @@ impl WlxPipeline<WlxPipelineDynamic> {
graphics,
pipeline,
format,
data: WlxPipelineDynamic {},
})
}
pub fn create_pass(
@@ -1257,8 +1175,8 @@ impl WlxPipeline<WlxPipelineDynamic> {
vertex_buffer: Vert2Buf,
index_buffer: IndexBuf,
descriptor_sets: Vec<Arc<DescriptorSet>>,
) -> anyhow::Result<DynamicPass> {
DynamicPass::new(
) -> anyhow::Result<WlxPass> {
WlxPass::new(
self.clone(),
dimensions,
vertex_buffer,
@@ -1266,178 +1184,24 @@ impl WlxPipeline<WlxPipelineDynamic> {
descriptor_sets,
)
}
}
impl WlxPipeline<WlxPipelineLegacy> {
fn new(
render_target: Arc<ImageView>,
graphics: Arc<WlxGraphics>,
vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>,
format: Format,
blend: Option<AttachmentBlend>,
) -> anyhow::Result<Self> {
let render_pass = vulkano::single_pass_renderpass!(
graphics.device.clone(),
attachments: {
color: {
format: format,
samples: 1,
load_op: Clear,
store_op: Store,
},
},
pass: {
color: [color],
depth_stencil: {},
},
)?;
Self::new_from_pass(
render_target,
render_pass,
graphics,
vert,
frag,
format,
blend,
)
}
#[allow(clippy::too_many_arguments)]
fn new_with_layout(
render_target: Arc<ImageView>,
graphics: Arc<WlxGraphics>,
vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>,
format: Format,
blend: Option<AttachmentBlend>,
initial_layout: ImageLayout,
final_layout: ImageLayout,
) -> anyhow::Result<Self> {
let render_pass_description = RenderPassCreateInfo {
attachments: vec![AttachmentDescription {
format,
samples: SampleCount::Sample1,
load_op: AttachmentLoadOp::Clear,
store_op: AttachmentStoreOp::Store,
initial_layout,
final_layout,
..Default::default()
}],
subpasses: vec![SubpassDescription {
color_attachments: vec![Some(AttachmentReference {
attachment: 0,
layout: ImageLayout::ColorAttachmentOptimal,
..Default::default()
})],
..Default::default()
}],
..Default::default()
};
let render_pass = RenderPass::new(graphics.device.clone(), render_pass_description)?;
Self::new_from_pass(
render_target,
render_pass,
graphics,
vert,
frag,
format,
blend,
)
}
fn new_from_pass(
render_target: Arc<ImageView>,
render_pass: Arc<RenderPass>,
graphics: Arc<WlxGraphics>,
vert: Arc<ShaderModule>,
frag: Arc<ShaderModule>,
format: Format,
blend: Option<AttachmentBlend>,
) -> anyhow::Result<Self> {
let vep = vert.entry_point("main").unwrap(); // want panic
let fep = frag.entry_point("main").unwrap(); // want panic
let vertex_input_state = Vert2Uv::per_vertex().definition(&vep.info().input_interface)?;
let stages = smallvec![
vulkano::pipeline::PipelineShaderStageCreateInfo::new(vep),
vulkano::pipeline::PipelineShaderStageCreateInfo::new(fep),
];
let layout = PipelineLayout::new(
graphics.device.clone(),
PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages)
.into_pipeline_layout_create_info(graphics.device.clone())?,
)?;
let framebuffer = Framebuffer::new(
render_pass.clone(),
FramebufferCreateInfo {
attachments: vec![render_target.clone()],
..Default::default()
},
)?;
let pipeline = GraphicsPipeline::new(
graphics.device.clone(),
None,
GraphicsPipelineCreateInfo {
stages,
vertex_input_state: Some(vertex_input_state),
input_assembly_state: Some(InputAssemblyState::default()),
viewport_state: Some(ViewportState::default()),
color_blend_state: Some(ColorBlendState {
attachments: vec![ColorBlendAttachmentState {
blend,
..Default::default()
}],
..Default::default()
}),
rasterization_state: Some(RasterizationState::default()),
multisample_state: Some(MultisampleState::default()),
dynamic_state: [DynamicState::Viewport].into_iter().collect(),
subpass: Some(
Subpass::from(render_pass.clone(), 0)
.ok_or_else(|| anyhow!("Failed to create subpass"))?
.into(),
),
..GraphicsPipelineCreateInfo::layout(layout)
},
)?;
Ok(Self {
graphics,
pipeline,
format,
data: WlxPipelineLegacy {
render_pass,
framebuffer,
},
})
}
pub fn create_pass(
pub fn create_pass_for_target(
self: &Arc<Self>,
dimensions: [f32; 2],
vertex_buffer: Vert2Buf,
index_buffer: IndexBuf,
tgt: Arc<ImageView>,
descriptor_sets: Vec<Arc<DescriptorSet>>,
) -> anyhow::Result<LegacyPass> {
LegacyPass::new(
) -> anyhow::Result<WlxPass> {
let extent = tgt.image().extent();
WlxPass::new(
self.clone(),
dimensions,
vertex_buffer,
index_buffer,
[extent[0] as _, extent[1] as _],
self.graphics.quad_verts.clone(),
self.graphics.quad_indices.clone(),
descriptor_sets,
)
}
}
impl<D> WlxPipeline<D> {
impl WlxPipeline {
pub fn inner(&self) -> Arc<GraphicsPipeline> {
self.pipeline.clone()
}
@@ -1498,78 +1262,13 @@ impl<D> WlxPipeline<D> {
}
}
#[allow(dead_code)]
pub struct WlxPass<D> {
pipeline: Arc<WlxPipeline<D>>,
vertex_buffer: Vert2Buf,
index_buffer: IndexBuf,
descriptor_sets: Vec<Arc<DescriptorSet>>,
pub struct WlxPass {
pub command_buffer: Arc<CommandBuffer>,
}
impl WlxPass<WlxPipelineLegacy> {
impl WlxPass {
fn new(
pipeline: Arc<LegacyPipeline>,
dimensions: [f32; 2],
vertex_buffer: Vert2Buf,
index_buffer: IndexBuf,
descriptor_sets: Vec<Arc<DescriptorSet>>,
) -> anyhow::Result<Self> {
let viewport = Viewport {
offset: [0.0, 0.0],
extent: dimensions,
depth_range: 0.0..=1.0,
};
let pipeline_inner = pipeline.inner().clone();
let mut command_buffer = RecordingCommandBuffer::new(
pipeline.graphics.command_buffer_allocator.clone(),
pipeline.graphics.queue.queue_family_index(),
CommandBufferLevel::Secondary,
CommandBufferBeginInfo {
usage: CommandBufferUsage::MultipleSubmit,
inheritance_info: Some(CommandBufferInheritanceInfo {
render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRenderPass(
CommandBufferInheritanceRenderPassInfo {
subpass: Subpass::from(pipeline.data.render_pass.clone(), 0)
.ok_or_else(|| anyhow!("Failed to get subpass"))?,
framebuffer: None,
},
)),
..Default::default()
}),
..Default::default()
},
)?;
unsafe {
command_buffer
.set_viewport(0, smallvec![viewport])?
.bind_pipeline_graphics(pipeline_inner)?
.bind_descriptor_sets(
PipelineBindPoint::Graphics,
pipeline.inner().layout().clone(),
0,
descriptor_sets.clone(),
)?
.bind_vertex_buffers(0, vertex_buffer.clone())?
.bind_index_buffer(index_buffer.clone())?
.draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0)?
};
Ok(Self {
pipeline,
vertex_buffer,
index_buffer,
descriptor_sets,
command_buffer: command_buffer.end()?,
})
}
}
impl WlxPass<WlxPipelineDynamic> {
fn new(
pipeline: Arc<DynamicPipeline>,
pipeline: Arc<WlxPipeline>,
dimensions: [f32; 2],
vertex_buffer: Vert2Buf,
index_buffer: IndexBuf,
@@ -1616,15 +1315,57 @@ impl WlxPass<WlxPipelineDynamic> {
};
Ok(Self {
pipeline,
vertex_buffer,
index_buffer,
descriptor_sets,
command_buffer: command_buffer.end()?,
})
}
}
#[derive(Default)]
pub struct CommandBuffers {
inner: Vec<Arc<CommandBuffer>>,
}
impl CommandBuffers {
pub fn push(&mut self, buffer: Arc<CommandBuffer>) {
self.inner.push(buffer);
}
pub fn execute_now(self, queue: Arc<Queue>) -> anyhow::Result<Option<Box<dyn GpuFuture>>> {
let mut buffers = self.inner.into_iter();
let Some(first) = buffers.next() else {
return Ok(None);
};
let future = first.execute(queue.clone())?;
let mut future: Box<dyn GpuFuture> = Box::new(future);
for buf in buffers {
future = Box::new(future.then_execute_same_queue(buf)?);
}
Ok(Some(future))
}
#[cfg(feature = "uidev")]
pub fn execute_after(
self,
queue: Arc<Queue>,
future: Box<dyn GpuFuture>,
) -> anyhow::Result<Box<dyn GpuFuture>> {
let mut buffers = self.inner.into_iter();
let Some(first) = buffers.next() else {
return Ok(future);
};
let future = future.then_execute(queue, first)?;
let mut future: Box<dyn GpuFuture> = Box::new(future);
for buf in buffers {
future = Box::new(future.then_execute_same_queue(buf)?);
}
Ok(future)
}
}
pub fn fourcc_to_vk(fourcc: FourCC) -> anyhow::Result<Format> {
match fourcc.value {
DRM_FORMAT_ABGR8888 => Ok(Format::R8G8B8A8_UNORM),
@@ -1675,15 +1416,3 @@ fn memory_allocator(device: Arc<Device>) -> Arc<StandardMemoryAllocator> {
Arc::new(StandardMemoryAllocator::new(device, create_info))
}
pub fn format_is_srgb(format: Format) -> bool {
matches!(
format,
Format::R8G8B8A8_SRGB
| Format::B8G8R8A8_SRGB
| Format::BC1_RGBA_SRGB_BLOCK
| Format::BC2_SRGB_BLOCK
| Format::BC3_SRGB_BLOCK
| Format::BC7_SRGB_BLOCK
)
}