nothing works

This commit is contained in:
galister
2023-11-09 22:27:05 +09:00
commit f193f33f4e
42 changed files with 9992 additions and 0 deletions

559
src/graphics.rs Normal file
View File

@@ -0,0 +1,559 @@
use std::{sync::Arc, slice::Iter, io::Cursor, error::Error};
use log::{info,error};
use vulkano::{format::Format, device::{physical::PhysicalDeviceType, QueueFlags, DeviceExtensions, Device, DeviceCreateInfo, Features, QueueCreateInfo, Queue}, Version, VulkanLibrary, instance::{Instance, InstanceCreateInfo}, memory::allocator::{StandardMemoryAllocator, AllocationCreateInfo, MemoryUsage}, command_buffer::{allocator::StandardCommandBufferAllocator, CommandBufferUsage, AutoCommandBufferBuilder, PrimaryAutoCommandBuffer, RenderingAttachmentInfo, RenderingInfo, PrimaryCommandBufferAbstract, CommandBufferExecFuture, SubpassContents, SecondaryAutoCommandBuffer, CommandBufferInheritanceInfo, CommandBufferInheritanceRenderPassType, CommandBufferInheritanceRenderingInfo}, descriptor_set::{allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet}, buffer::{Buffer, BufferCreateInfo, BufferUsage, BufferContents, Subbuffer, allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}}, sampler::{Filter, SamplerCreateInfo, SamplerAddressMode, Sampler}, pipeline::{GraphicsPipeline, Pipeline, graphics::{render_pass::PipelineRenderingCreateInfo, vertex_input::Vertex, input_assembly::InputAssemblyState, viewport::{ViewportState, Viewport}, color_blend::{ColorBlendState, AttachmentBlend}}, PipelineBindPoint}, image::{ImageViewAbstract, ImageUsage, SwapchainImage, ImageDimensions, ImmutableImage, MipmapsCount, StorageImage, ImageError, SubresourceData, ImageCreateFlags, AttachmentImage}, swapchain::{Surface, Swapchain, SwapchainCreateInfo, CompositeAlpha}, shader::ShaderModule, render_pass::{StoreOp, LoadOp}, sync::future::NowFuture};
use winit::{event_loop::EventLoop, window::{WindowBuilder, Window}};
use vulkano_win::VkSurfaceBuild;
use wlx_capture::frame::{DmabufFrame, DRM_FORMAT_ABGR8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888};
#[repr(C)]
#[derive(BufferContents, Vertex, Copy, Clone, Debug)]
pub struct Vert2Uv {
#[format(R32G32_SFLOAT)]
pub in_pos: [f32; 2],
#[format(R32G32_SFLOAT)]
pub in_uv: [f32; 2],
}
pub const INDICES : [u16; 6] = [2, 1, 0, 1, 2, 3];
pub struct WlxGraphics {
pub instance: Arc<Instance>,
pub device: Arc<Device>,
pub queue: Arc<Queue>,
pub surface: Arc<Surface>,
pub memory_allocator: Arc<StandardMemoryAllocator>,
pub command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
pub descriptor_set_allocator: Arc<StandardDescriptorSetAllocator>,
pub quad_indices: Subbuffer<[u16]>,
}
impl WlxGraphics {
pub fn new() -> (Arc<Self>, EventLoop<()>) {
#[cfg(debug_assertions)]
let layers = vec!["VK_LAYER_KHRONOS_validation".to_owned()];
#[cfg(not(debug_assertions))]
let layers = vec![];
let library = VulkanLibrary::new().unwrap();
let required_extensions = vulkano_win::required_extensions(&library);
let instance = Instance::new(
library,
InstanceCreateInfo {
enabled_extensions: required_extensions,
enabled_layers: layers,
enumerate_portability: true,
..Default::default()
},
)
.unwrap();
let mut device_extensions = DeviceExtensions {
khr_swapchain: true,
khr_external_memory: true,
khr_external_memory_fd: true,
ext_external_memory_dma_buf: true,
ext_image_drm_format_modifier: true,
..DeviceExtensions::empty()
};
// TODO headless
let event_loop = EventLoop::new();
let surface = WindowBuilder::new()
.build_vk_surface(&event_loop, instance.clone())
.unwrap();
let (physical_device, queue_family_index) = instance
.enumerate_physical_devices()
.unwrap()
.filter(|p| {
p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering
})
.filter(|p| {
p.supported_extensions().contains(&device_extensions)
})
.filter_map(|p| {
p.queue_family_properties()
.iter()
.enumerate()
.position(|(i, q)| {
q.queue_flags.intersects(QueueFlags::GRAPHICS)
&& p.surface_support(i as u32, &surface).unwrap_or(false)
})
.map(|i| (p, i as u32))
})
.min_by_key(|(p, _)| {
match p.properties().device_type {
PhysicalDeviceType::DiscreteGpu => 0,
PhysicalDeviceType::IntegratedGpu => 1,
PhysicalDeviceType::VirtualGpu => 2,
PhysicalDeviceType::Cpu => 3,
PhysicalDeviceType::Other => 4,
_ => 5,
}
})
.expect("no suitable physical device found");
info!(
"Nice {} you have there.",
physical_device.properties().device_name,
);
if physical_device.api_version() < Version::V1_3 {
device_extensions.khr_dynamic_rendering = true;
}
let (device, mut queues) = Device::new(
physical_device,
DeviceCreateInfo {
enabled_extensions: device_extensions,
enabled_features: Features {
dynamic_rendering: true,
..Features::empty()
},
queue_create_infos: vec![QueueCreateInfo {
queue_family_index,
..Default::default()
}],
..Default::default()
},
)
.unwrap();
let queue = queues.next().unwrap();
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new(device.clone(), Default::default()));
let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(device.clone()));
let quad_indices = Buffer::from_iter(
&memory_allocator,
BufferCreateInfo {
usage: BufferUsage::INDEX_BUFFER,
..Default::default()
},
AllocationCreateInfo {
usage: MemoryUsage::Upload,
..Default::default()
},
INDICES.iter().cloned(),
).unwrap();
let me = Self {
instance,
device,
queue,
surface,
memory_allocator,
command_buffer_allocator,
descriptor_set_allocator,
quad_indices,
};
(Arc::new(me), event_loop)
}
pub fn create_swapchain(&self, format: Option<Format>) -> (Arc<Swapchain>, Vec<Arc<SwapchainImage>>) {
let (min_image_count, composite_alpha, image_format) = if let Some(format) = format {
(1, CompositeAlpha::Opaque, format)
} else {
let surface_capabilities = self.device
.physical_device()
.surface_capabilities(&self.surface, Default::default())
.unwrap();
let composite_alpha = surface_capabilities.supported_composite_alpha.into_iter().next().unwrap();
let image_format = Some(
self.device
.physical_device()
.surface_formats(&self.surface, Default::default())
.unwrap()[0]
.0,
);
(surface_capabilities.min_image_count, composite_alpha, image_format.unwrap())
};
let window = self.surface.object().unwrap().downcast_ref::<Window>().unwrap();
let swapchain = Swapchain::new(
self.device.clone(),
self.surface.clone(),
SwapchainCreateInfo {
min_image_count,
image_format: Some(image_format),
image_extent: window.inner_size().into(),
image_usage: ImageUsage::COLOR_ATTACHMENT,
composite_alpha,
..Default::default()
},
)
.unwrap();
swapchain
}
pub fn upload_verts(&self, width: f32, height: f32, x: f32, y: f32, w: f32, h: f32) -> Subbuffer<[Vert2Uv]> {
let rw = width;
let rh = height;
let x0 = x / rw;
let y0 = y / rh;
let x1 = w / rw + x0;
let y1 = h / rh + y0;
let vertices = [
Vert2Uv { in_pos: [x0, y0], in_uv: [0.0, 0.0] },
Vert2Uv { in_pos: [x0, y1], in_uv: [0.0, 1.0] },
Vert2Uv { in_pos: [x1, y0], in_uv: [1.0, 0.0] },
Vert2Uv { in_pos: [x1, y1], in_uv: [1.0, 1.0] },
];
self.upload_buffer(BufferUsage::VERTEX_BUFFER, vertices.iter())
}
pub fn upload_buffer<T>(&self, usage: BufferUsage, contents: Iter<'_, T>) -> Subbuffer<[T]>
where T: BufferContents + Clone {
Buffer::from_iter(
&self.memory_allocator,
BufferCreateInfo {
usage,
..Default::default()
},
AllocationCreateInfo {
usage: MemoryUsage::Upload,
..Default::default()
},
contents.cloned(),
).unwrap()
}
pub fn dmabuf_texture(&self, frame: DmabufFrame) -> Result<Arc<StorageImage>, ImageError> {
let dimensions = ImageDimensions::Dim2d {
width: frame.format.width,
height: frame.format.height,
array_layers: 1,
};
let format = match frame.format.fourcc {
DRM_FORMAT_ABGR8888 => Format::R8G8B8A8_UNORM,
DRM_FORMAT_XBGR8888 => Format::R8G8B8A8_UNORM,
DRM_FORMAT_ARGB8888 => Format::B8G8R8A8_UNORM,
DRM_FORMAT_XRGB8888 => Format::B8G8R8A8_UNORM,
_ => panic!("Unsupported dmabuf format {:x}", frame.format.fourcc),
};
let planes = frame.planes
.iter()
.take(frame.num_planes)
.filter_map(|plane| {
let Some(fd) = plane.fd else {
return None;
};
Some(SubresourceData {
fd,
offset: plane.offset as _,
row_pitch: plane.stride as _,
})
}).collect();
StorageImage::new_from_dma_buf_fd(
&self.memory_allocator,
self.device.clone(),
dimensions,
format,
ImageUsage::SAMPLED | ImageUsage::TRANSFER_SRC,
ImageCreateFlags::empty(),
[self.queue.queue_family_index()],
planes,
frame.format.modifier,
)
}
pub fn render_texture(&self, width: u32, height: u32, format: Format) -> Arc<AttachmentImage> {
let tex = AttachmentImage::with_usage(
&self.memory_allocator,
[width, height],
format,
ImageUsage::SAMPLED | ImageUsage::TRANSFER_SRC | ImageUsage::COLOR_ATTACHMENT,
).unwrap();
tex
}
pub fn create_pipeline(self: &Arc<Self>, vert: Arc<ShaderModule>, frag: Arc<ShaderModule>, format: Format) -> Arc<WlxPipeline> {
Arc::new(WlxPipeline::new(self.clone(), vert, frag, format))
}
pub fn create_command_buffer(self: &Arc<Self>, usage: CommandBufferUsage) -> WlxCommandBuffer<PrimaryAutoCommandBuffer> {
let command_buffer = AutoCommandBufferBuilder::primary(
&self.command_buffer_allocator,
self.queue.queue_family_index(),
usage,
).unwrap();
WlxCommandBuffer { graphics: self.clone(), command_buffer }
}
}
pub struct WlxCommandBuffer<T> {
graphics: Arc<WlxGraphics>,
command_buffer: AutoCommandBufferBuilder<T, Arc<StandardCommandBufferAllocator>>,
}
impl<T> WlxCommandBuffer<T> {
pub fn inner(&self) -> &AutoCommandBufferBuilder<T, Arc<StandardCommandBufferAllocator>> {
&self.command_buffer
}
pub fn inner_mut(&mut self) -> &mut AutoCommandBufferBuilder<T, Arc<StandardCommandBufferAllocator>> {
&mut self.command_buffer
}
pub fn to_inner(self) -> AutoCommandBufferBuilder<T, Arc<StandardCommandBufferAllocator>> {
self.command_buffer
}
pub fn begin(mut self, render_target: Arc<dyn ImageViewAbstract>) -> Self
{
self.command_buffer
.begin_rendering(RenderingInfo {
contents: SubpassContents::SecondaryCommandBuffers,
color_attachments: vec![Some(RenderingAttachmentInfo {
load_op: LoadOp::Clear,
store_op: StoreOp::Store,
clear_value: Some([0.0, 0.0, 0.0, 0.0].into()),
..RenderingAttachmentInfo::image_view(
render_target.clone(),
)
})],
..Default::default()
}).unwrap();
self
}
pub fn run_ref(&mut self, pass: &WlxPass) -> &mut Self
{
let _ = self.command_buffer.execute_commands(pass.command_buffer.clone()).unwrap();
self
}
pub fn run(mut self, pass: &WlxPass) -> Self
{
let _ = self.command_buffer.execute_commands(pass.command_buffer.clone());
self
}
pub fn texture2d(&mut self, width: u32, height: u32, format: Format, data: Vec<u8>) -> Arc<ImmutableImage> {
let dimensions = ImageDimensions::Dim2d {
width,
height,
array_layers: 1,
};
ImmutableImage::from_iter(
&self.graphics.memory_allocator,
data,
dimensions,
MipmapsCount::One,
format,
&mut self.command_buffer,
)
.unwrap()
}
pub fn texture2d_png(&mut self, bytes: Vec<u8>) -> Arc<ImmutableImage> {
let cursor = Cursor::new(bytes);
let decoder = png::Decoder::new(cursor);
let mut reader = decoder.read_info().unwrap();
let info = reader.info();
let width = info.width;
let height = info.height;
let mut image_data = Vec::new();
image_data.resize((info.width * info.height * 4) as usize, 0);
reader.next_frame(&mut image_data).unwrap();
self.texture2d(width, height, Format::R8G8B8A8_UNORM, image_data)
}
}
impl WlxCommandBuffer<PrimaryAutoCommandBuffer> {
pub fn end_render_and_continue(&mut self) {
self.command_buffer.end_rendering().unwrap();
}
pub fn end_render(self) -> PrimaryAutoCommandBuffer {
let mut buf = self.command_buffer;
buf.end_rendering().unwrap();
buf.build().unwrap()
}
pub fn end(self) -> PrimaryAutoCommandBuffer {
self.command_buffer.build().unwrap()
}
pub fn end_render_and_execute(self) -> CommandBufferExecFuture<NowFuture> {
let mut buf = self.command_buffer;
buf.end_rendering().unwrap();
let buf = buf.build().unwrap();
buf.execute(self.graphics.queue.clone()).unwrap()
}
pub fn end_and_execute(self) -> CommandBufferExecFuture<NowFuture> {
let buf = self.command_buffer;
let buf = buf.build().unwrap();
buf.execute(self.graphics.queue.clone()).unwrap()
}
}
pub struct WlxPipeline {
pub graphics: Arc<WlxGraphics>,
pub pipeline: Arc<GraphicsPipeline>,
pub format: Format,
}
impl WlxPipeline {
fn new(graphics: Arc<WlxGraphics>, vert: Arc<ShaderModule>, frag: Arc<ShaderModule>, format: Format) -> Self {
let vep = vert.entry_point("main").unwrap();
let fep = frag.entry_point("main").unwrap();
let pipeline = GraphicsPipeline::start()
.render_pass(PipelineRenderingCreateInfo {
color_attachment_formats: vec![Some(format)],
..Default::default()
})
.color_blend_state(ColorBlendState::default().blend(
AttachmentBlend::alpha()
))
.vertex_input_state(Vert2Uv::per_vertex())
.input_assembly_state(InputAssemblyState::new())
.vertex_shader(vep, ())
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
.fragment_shader(fep, ())
.build(graphics.device.clone())
.unwrap();
Self { graphics, pipeline, format}
}
pub fn inner(&self) -> Arc<GraphicsPipeline> {
self.pipeline.clone()
}
pub fn graphics(&self) -> Arc<WlxGraphics> {
self.graphics.clone()
}
pub fn uniform_sampler(&self, set: usize, texture: Arc<dyn ImageViewAbstract>, filter: Filter) -> Arc<PersistentDescriptorSet> {
let sampler = Sampler::new(
self.graphics.device.clone(),
SamplerCreateInfo {
mag_filter: filter,
min_filter: filter,
address_mode: [SamplerAddressMode::Repeat; 3],
..Default::default()
},
)
.unwrap();
let layout = self.pipeline.layout().set_layouts().get(set).unwrap();
PersistentDescriptorSet::new(
&self.graphics.descriptor_set_allocator,
layout.clone(),
[WriteDescriptorSet::image_view_sampler(0, texture, sampler)],
)
.unwrap()
}
pub fn uniform_buffer<T>(&self, set: usize, data: Vec<T>) -> Arc<PersistentDescriptorSet>
where T: BufferContents + Copy {
let uniform_buffer = SubbufferAllocator::new(
self.graphics.memory_allocator.clone(),
SubbufferAllocatorCreateInfo {
buffer_usage: BufferUsage::UNIFORM_BUFFER,
..Default::default()
},
);
let uniform_buffer_subbuffer = {
let subbuffer = uniform_buffer.allocate_slice(data.len() as _).unwrap();
subbuffer.write().unwrap().copy_from_slice(data.as_slice());
subbuffer
};
let layout = self.pipeline.layout().set_layouts().get(set).unwrap();
PersistentDescriptorSet::new(
&self.graphics.descriptor_set_allocator,
layout.clone(),
[WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)]
).unwrap()
}
pub fn create_pass(self: &Arc<Self>, dimensions: [f32; 2], vertex_buffer: Subbuffer<[Vert2Uv]>, index_buffer: Subbuffer<[u16]>, descriptor_sets: Vec<Arc<PersistentDescriptorSet>>) -> WlxPass {
WlxPass::new(self.clone(), dimensions, vertex_buffer, index_buffer, descriptor_sets)
}
}
pub struct WlxPass
{
pipeline: Arc<WlxPipeline>,
vertex_buffer: Subbuffer<[Vert2Uv]>,
index_buffer: Subbuffer<[u16]>,
descriptor_sets: Vec<Arc<PersistentDescriptorSet>>,
pub command_buffer: Arc<SecondaryAutoCommandBuffer>,
}
impl WlxPass
{
fn new(pipeline: Arc<WlxPipeline>, dimensions: [f32; 2], vertex_buffer: Subbuffer<[Vert2Uv]>, index_buffer: Subbuffer<[u16]>, descriptor_sets: Vec<Arc<PersistentDescriptorSet>>) -> Self {
let viewport = Viewport {
origin: [0.0, 0.0],
dimensions,
depth_range: 0.0..1.0,
};
let pipeline_inner = pipeline.inner().clone();
let mut command_buffer = AutoCommandBufferBuilder::secondary(
&pipeline.graphics.command_buffer_allocator,
pipeline.graphics.queue.queue_family_index(),
CommandBufferUsage::MultipleSubmit,
CommandBufferInheritanceInfo {
render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRendering(
CommandBufferInheritanceRenderingInfo {
color_attachment_formats: vec![Some(pipeline.format)],
..Default::default()
})),
..Default::default()
}
)
.unwrap();
command_buffer.set_viewport(0, [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)
.or_else(|err| {
if let Some(source) = err.source() {
error!("Failed to draw: {}", source);
}
Err(err)
}).unwrap();
Self {
pipeline,
vertex_buffer,
index_buffer,
descriptor_sets,
command_buffer: Arc::new(command_buffer.build().unwrap()),
}
}
}