steamvr poc works
This commit is contained in:
561
src/graphics.rs
561
src/graphics.rs
@@ -1,22 +1,26 @@
|
||||
use std::{error::Error, io::Cursor, slice::Iter, sync::Arc};
|
||||
use std::{
|
||||
error::Error,
|
||||
io::Cursor,
|
||||
os::fd::{FromRawFd, IntoRawFd},
|
||||
slice::Iter,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use ash::vk::SubmitInfo;
|
||||
use smallvec::smallvec;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use vulkano::{
|
||||
buffer::{
|
||||
allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo},
|
||||
Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer,
|
||||
},
|
||||
command_buffer::{
|
||||
allocator::{
|
||||
CommandBufferAllocator, CommandBufferBuilderAlloc, StandardCommandBufferAllocator,
|
||||
},
|
||||
allocator::{StandardCommandBufferAllocator, StandardCommandBufferAllocatorCreateInfo},
|
||||
sys::{CommandBufferBeginInfo, UnsafeCommandBufferBuilder},
|
||||
AutoCommandBufferBuilder, CommandBufferExecFuture, CommandBufferInheritanceInfo,
|
||||
CommandBufferInheritanceRenderPassType, CommandBufferInheritanceRenderingInfo,
|
||||
CommandBufferLevel, CommandBufferUsage, PrimaryAutoCommandBuffer,
|
||||
PrimaryCommandBufferAbstract, RenderingAttachmentInfo, RenderingInfo,
|
||||
SecondaryAutoCommandBuffer, SubpassContents,
|
||||
CommandBufferInheritanceRenderPassInfo, CommandBufferInheritanceRenderPassType,
|
||||
CommandBufferLevel, CommandBufferUsage, CopyBufferToImageInfo, PrimaryAutoCommandBuffer,
|
||||
PrimaryCommandBufferAbstract, RenderPassBeginInfo, SecondaryAutoCommandBuffer,
|
||||
SubpassBeginInfo, SubpassContents, SubpassEndInfo,
|
||||
},
|
||||
descriptor_set::{
|
||||
allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet,
|
||||
@@ -27,33 +31,47 @@ use vulkano::{
|
||||
},
|
||||
format::Format,
|
||||
image::{
|
||||
sys::Image, AttachmentImage, ImageCreateFlags, ImageDimensions, ImageError, ImageLayout,
|
||||
ImageUsage, ImageViewAbstract, ImmutableImage, MipmapsCount, StorageImage, SubresourceData,
|
||||
SwapchainImage,
|
||||
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
|
||||
sys::RawImage,
|
||||
view::ImageView,
|
||||
Image, ImageCreateInfo, ImageLayout, ImageTiling, ImageType, ImageUsage, SampleCount,
|
||||
SubresourceLayout,
|
||||
},
|
||||
instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions},
|
||||
memory::{
|
||||
allocator::{
|
||||
AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter, StandardMemoryAllocator,
|
||||
},
|
||||
DedicatedAllocation, DeviceMemory, ExternalMemoryHandleType, ExternalMemoryHandleTypes,
|
||||
MemoryAllocateInfo, MemoryImportInfo, ResourceMemory,
|
||||
},
|
||||
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::{AttachmentBlend, ColorBlendState},
|
||||
color_blend::{AttachmentBlend, ColorBlendAttachmentState, ColorBlendState},
|
||||
input_assembly::InputAssemblyState,
|
||||
render_pass::PipelineRenderingCreateInfo,
|
||||
vertex_input::Vertex,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::{Vertex, VertexDefinition},
|
||||
viewport::{Viewport, ViewportState},
|
||||
GraphicsPipelineCreateInfo,
|
||||
},
|
||||
GraphicsPipeline, Pipeline, PipelineBindPoint,
|
||||
layout::PipelineDescriptorSetLayoutCreateInfo,
|
||||
DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout,
|
||||
PipelineShaderStageCreateInfo,
|
||||
},
|
||||
render_pass::{
|
||||
AttachmentDescription, AttachmentLoadOp, AttachmentReference, AttachmentStoreOp,
|
||||
Framebuffer, FramebufferCreateInfo, RenderPass, RenderPassCreateInfo, Subpass,
|
||||
SubpassDescription,
|
||||
},
|
||||
render_pass::{LoadOp, StoreOp},
|
||||
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
|
||||
shader::ShaderModule,
|
||||
swapchain::{CompositeAlpha, Surface, Swapchain, SwapchainCreateInfo},
|
||||
sync::{
|
||||
fence::Fence, future::NowFuture, AccessFlags, DependencyInfo, GpuFuture,
|
||||
ImageMemoryBarrier, PipelineStages,
|
||||
},
|
||||
Version, VulkanLibrary, VulkanObject,
|
||||
DeviceSize, VulkanLibrary, VulkanObject,
|
||||
};
|
||||
use vulkano_win::VkSurfaceBuild;
|
||||
use winit::{
|
||||
event_loop::EventLoop,
|
||||
window::{Window, WindowBuilder},
|
||||
@@ -98,8 +116,11 @@ impl WlxGraphics {
|
||||
#[cfg(not(debug_assertions))]
|
||||
let layers = vec![];
|
||||
|
||||
// TODO headless
|
||||
let event_loop = EventLoop::new();
|
||||
let library_extensions = Surface::required_extensions(&event_loop);
|
||||
|
||||
let library = VulkanLibrary::new().unwrap();
|
||||
let library_extensions = vulkano_win::required_extensions(&library);
|
||||
let required_extensions = library_extensions.union(&vk_instance_extensions);
|
||||
|
||||
log::debug!("Instance exts for app: {:?}", &required_extensions);
|
||||
@@ -108,9 +129,9 @@ impl WlxGraphics {
|
||||
let instance = Instance::new(
|
||||
library,
|
||||
InstanceCreateInfo {
|
||||
flags: InstanceCreateFlags::ENUMERATE_PORTABILITY,
|
||||
enabled_extensions: required_extensions,
|
||||
enabled_layers: layers,
|
||||
enumerate_portability: true,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
@@ -128,17 +149,15 @@ impl WlxGraphics {
|
||||
log::debug!("Device exts for app: {:?}", &device_extensions);
|
||||
|
||||
// TODO headless
|
||||
let event_loop = EventLoop::new();
|
||||
let surface = WindowBuilder::new()
|
||||
.build_vk_surface(&event_loop, instance.clone())
|
||||
.unwrap();
|
||||
let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap());
|
||||
let surface = Surface::from_window(instance.clone(), window.clone()).unwrap();
|
||||
|
||||
let (physical_device, my_extensions, 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.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering
|
||||
//})
|
||||
.filter_map(|p| {
|
||||
let runtime_extensions = vk_device_extensions_fn(&p);
|
||||
log::debug!(
|
||||
@@ -178,9 +197,9 @@ impl WlxGraphics {
|
||||
physical_device.properties().device_name,
|
||||
);
|
||||
|
||||
if physical_device.api_version() < Version::V1_3 {
|
||||
device_extensions.khr_dynamic_rendering = true;
|
||||
}
|
||||
//if physical_device.api_version() < Version::V1_3 {
|
||||
// device_extensions.khr_dynamic_rendering = true;
|
||||
//}
|
||||
|
||||
let (device, mut queues) = Device::new(
|
||||
physical_device,
|
||||
@@ -203,11 +222,16 @@ impl WlxGraphics {
|
||||
|
||||
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
|
||||
let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new(
|
||||
device.clone(),
|
||||
StandardCommandBufferAllocatorCreateInfo {
|
||||
secondary_buffer_count: 32,
|
||||
..Default::default()
|
||||
},
|
||||
));
|
||||
let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(
|
||||
device.clone(),
|
||||
Default::default(),
|
||||
));
|
||||
let descriptor_set_allocator =
|
||||
Arc::new(StandardDescriptorSetAllocator::new(device.clone()));
|
||||
|
||||
let vertices = [
|
||||
Vert2Uv {
|
||||
@@ -228,13 +252,14 @@ impl WlxGraphics {
|
||||
},
|
||||
];
|
||||
let quad_verts = Buffer::from_iter(
|
||||
&memory_allocator,
|
||||
memory_allocator.clone(),
|
||||
BufferCreateInfo {
|
||||
usage: BufferUsage::VERTEX_BUFFER,
|
||||
..Default::default()
|
||||
},
|
||||
AllocationCreateInfo {
|
||||
usage: MemoryUsage::Upload,
|
||||
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
|
||||
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||
..Default::default()
|
||||
},
|
||||
vertices.into_iter(),
|
||||
@@ -242,13 +267,14 @@ impl WlxGraphics {
|
||||
.unwrap();
|
||||
|
||||
let quad_indices = Buffer::from_iter(
|
||||
&memory_allocator,
|
||||
memory_allocator.clone(),
|
||||
BufferCreateInfo {
|
||||
usage: BufferUsage::INDEX_BUFFER,
|
||||
..Default::default()
|
||||
},
|
||||
AllocationCreateInfo {
|
||||
usage: MemoryUsage::Upload,
|
||||
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
|
||||
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||
..Default::default()
|
||||
},
|
||||
INDICES.iter().cloned(),
|
||||
@@ -271,10 +297,7 @@ impl WlxGraphics {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn create_swapchain(
|
||||
&self,
|
||||
format: Option<Format>,
|
||||
) -> (Arc<Swapchain>, Vec<Arc<SwapchainImage>>) {
|
||||
pub fn create_swapchain(&self, format: Option<Format>) -> (Arc<Swapchain>, Vec<Arc<Image>>) {
|
||||
let (min_image_count, composite_alpha, image_format) = if let Some(format) = format {
|
||||
(1, CompositeAlpha::Opaque, format)
|
||||
} else {
|
||||
@@ -314,7 +337,7 @@ impl WlxGraphics {
|
||||
self.surface.clone(),
|
||||
SwapchainCreateInfo {
|
||||
min_image_count,
|
||||
image_format: Some(image_format),
|
||||
image_format,
|
||||
image_extent: window.inner_size().into(),
|
||||
image_usage: ImageUsage::COLOR_ATTACHMENT,
|
||||
composite_alpha,
|
||||
@@ -370,13 +393,14 @@ impl WlxGraphics {
|
||||
T: BufferContents + Clone,
|
||||
{
|
||||
Buffer::from_iter(
|
||||
&self.memory_allocator,
|
||||
self.memory_allocator.clone(),
|
||||
BufferCreateInfo {
|
||||
usage,
|
||||
..Default::default()
|
||||
},
|
||||
AllocationCreateInfo {
|
||||
usage: MemoryUsage::Upload,
|
||||
memory_type_filter: MemoryTypeFilter::PREFER_HOST
|
||||
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||
..Default::default()
|
||||
},
|
||||
contents.cloned(),
|
||||
@@ -384,12 +408,8 @@ impl WlxGraphics {
|
||||
.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,
|
||||
};
|
||||
pub fn dmabuf_texture(&self, frame: DmabufFrame) -> Option<Arc<Image>> {
|
||||
let extent = [frame.format.width, frame.format.height, 1];
|
||||
|
||||
let format = match frame.format.fourcc {
|
||||
DRM_FORMAT_ABGR8888 => Format::R8G8B8A8_UNORM,
|
||||
@@ -399,60 +419,145 @@ impl WlxGraphics {
|
||||
_ => 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,
|
||||
let layouts: Vec<SubresourceLayout> = (0..frame.num_planes)
|
||||
.into_iter()
|
||||
.map(|i| {
|
||||
let plane = &frame.planes[i];
|
||||
SubresourceLayout {
|
||||
offset: plane.offset as _,
|
||||
size: 0,
|
||||
row_pitch: plane.stride as _,
|
||||
})
|
||||
array_pitch: None,
|
||||
depth_pitch: None,
|
||||
}
|
||||
})
|
||||
.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,
|
||||
)
|
||||
}
|
||||
let external_memory_handle_types = ExternalMemoryHandleTypes::DMA_BUF;
|
||||
|
||||
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,
|
||||
let image = RawImage::new(
|
||||
self.device.clone(),
|
||||
ImageCreateInfo {
|
||||
image_type: ImageType::Dim2d,
|
||||
format,
|
||||
extent,
|
||||
usage: ImageUsage::SAMPLED | ImageUsage::TRANSFER_SRC,
|
||||
external_memory_handle_types,
|
||||
tiling: ImageTiling::DrmFormatModifier,
|
||||
drm_format_modifiers: vec![frame.format.modifier],
|
||||
drm_format_modifier_plane_layouts: layouts,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
tex
|
||||
let requirements = image.memory_requirements()[0];
|
||||
let memory_type_index = self
|
||||
.memory_allocator
|
||||
.find_memory_type_index(
|
||||
requirements.memory_type_bits,
|
||||
MemoryTypeFilter::PREFER_DEVICE,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
debug_assert!(self.device.enabled_extensions().khr_external_memory_fd);
|
||||
debug_assert!(self.device.enabled_extensions().khr_external_memory);
|
||||
debug_assert!(self.device.enabled_extensions().ext_external_memory_dma_buf);
|
||||
|
||||
let memory = unsafe {
|
||||
if frame.num_planes != 1 {
|
||||
log::error!("Unsupported number of DMA-buf planes: {}", frame.num_planes);
|
||||
return None;
|
||||
}
|
||||
let Some(fd) = frame.planes[0].fd else {
|
||||
log::error!("DMA-buf plane has no FD");
|
||||
return None;
|
||||
};
|
||||
|
||||
let file = std::fs::File::from_raw_fd(fd);
|
||||
let new_file = file.try_clone().unwrap();
|
||||
file.into_raw_fd();
|
||||
|
||||
DeviceMemory::import(
|
||||
self.device.clone(),
|
||||
MemoryAllocateInfo {
|
||||
allocation_size: requirements.layout.size(),
|
||||
memory_type_index,
|
||||
dedicated_allocation: Some(DedicatedAllocation::Image(&image)),
|
||||
..Default::default()
|
||||
},
|
||||
MemoryImportInfo::Fd {
|
||||
file: new_file,
|
||||
handle_type: ExternalMemoryHandleType::DmaBuf,
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let allocations: SmallVec<[ResourceMemory; 1]> =
|
||||
smallvec![ResourceMemory::new_dedicated(memory)];
|
||||
|
||||
if let Some(image) = image.bind_memory(allocations).ok() {
|
||||
Some(Arc::new(image))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_texture(&self, width: u32, height: u32, format: Format) -> Arc<Image> {
|
||||
Image::new(
|
||||
self.memory_allocator.clone(),
|
||||
ImageCreateInfo {
|
||||
image_type: ImageType::Dim2d,
|
||||
format,
|
||||
extent: [width, height, 1],
|
||||
usage: ImageUsage::TRANSFER_SRC
|
||||
| ImageUsage::SAMPLED
|
||||
| ImageUsage::COLOR_ATTACHMENT,
|
||||
..Default::default()
|
||||
},
|
||||
AllocationCreateInfo::default(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn create_pipeline(
|
||||
self: &Arc<Self>,
|
||||
render_target: Arc<ImageView>,
|
||||
vert: Arc<ShaderModule>,
|
||||
frag: Arc<ShaderModule>,
|
||||
format: Format,
|
||||
) -> Arc<WlxPipeline> {
|
||||
Arc::new(WlxPipeline::new(self.clone(), vert, frag, format))
|
||||
Arc::new(WlxPipeline::new(
|
||||
render_target,
|
||||
self.clone(),
|
||||
vert,
|
||||
frag,
|
||||
format,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn create_command_buffer(
|
||||
pub fn create_pipeline_with_layouts(
|
||||
self: &Arc<Self>,
|
||||
usage: CommandBufferUsage,
|
||||
) -> WlxCommandBuffer<PrimaryAutoCommandBuffer> {
|
||||
render_target: Arc<ImageView>,
|
||||
vert: Arc<ShaderModule>,
|
||||
frag: Arc<ShaderModule>,
|
||||
format: Format,
|
||||
initial_layout: ImageLayout,
|
||||
final_layout: ImageLayout,
|
||||
) -> Arc<WlxPipeline> {
|
||||
Arc::new(WlxPipeline::new_with_layout(
|
||||
render_target,
|
||||
self.clone(),
|
||||
vert,
|
||||
frag,
|
||||
format,
|
||||
initial_layout,
|
||||
final_layout,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn create_command_buffer(self: &Arc<Self>, usage: CommandBufferUsage) -> WlxCommandBuffer {
|
||||
let command_buffer = AutoCommandBufferBuilder::primary(
|
||||
&self.command_buffer_allocator,
|
||||
self.queue.queue_family_index(),
|
||||
@@ -482,31 +587,25 @@ impl WlxGraphics {
|
||||
..ImageMemoryBarrier::image(image)
|
||||
};
|
||||
|
||||
let builder_alloc = self
|
||||
.command_buffer_allocator
|
||||
.allocate(
|
||||
self.queue.queue_family_index(),
|
||||
CommandBufferLevel::Primary,
|
||||
1,
|
||||
)
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
let command_buffer = unsafe {
|
||||
let mut builder = UnsafeCommandBufferBuilder::new(
|
||||
&builder_alloc.inner(),
|
||||
&self.command_buffer_allocator,
|
||||
self.queue.queue_family_index(),
|
||||
CommandBufferLevel::Primary,
|
||||
CommandBufferBeginInfo {
|
||||
usage: CommandBufferUsage::OneTimeSubmit,
|
||||
inheritance_info: None,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
builder.pipeline_barrier(&DependencyInfo {
|
||||
image_memory_barriers: smallvec![barrier],
|
||||
..Default::default()
|
||||
});
|
||||
builder
|
||||
.pipeline_barrier(&DependencyInfo {
|
||||
image_memory_barriers: smallvec![barrier],
|
||||
..Default::default()
|
||||
})
|
||||
.unwrap();
|
||||
builder.build().unwrap()
|
||||
};
|
||||
|
||||
@@ -535,24 +634,27 @@ impl WlxGraphics {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WlxCommandBuffer<T> {
|
||||
pub struct WlxCommandBuffer {
|
||||
graphics: Arc<WlxGraphics>,
|
||||
command_buffer: AutoCommandBufferBuilder<T, Arc<StandardCommandBufferAllocator>>,
|
||||
command_buffer: AutoCommandBufferBuilder<
|
||||
PrimaryAutoCommandBuffer<Arc<StandardCommandBufferAllocator>>,
|
||||
Arc<StandardCommandBufferAllocator>,
|
||||
>,
|
||||
}
|
||||
|
||||
impl<T> WlxCommandBuffer<T> {
|
||||
pub fn begin(mut self, render_target: Arc<dyn ImageViewAbstract>) -> Self {
|
||||
impl WlxCommandBuffer {
|
||||
pub fn begin_render_pass(mut self, pipeline: &WlxPipeline) -> 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()
|
||||
})
|
||||
.begin_render_pass(
|
||||
RenderPassBeginInfo {
|
||||
clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())],
|
||||
..RenderPassBeginInfo::framebuffer(pipeline.framebuffer.clone())
|
||||
},
|
||||
SubpassBeginInfo {
|
||||
contents: SubpassContents::SecondaryCommandBuffers,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
self
|
||||
}
|
||||
@@ -571,26 +673,46 @@ impl<T> WlxCommandBuffer<T> {
|
||||
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::Log2, // required for TRANSFER_SRC
|
||||
format,
|
||||
&mut self.command_buffer,
|
||||
) -> Arc<Image> {
|
||||
let image = Image::new(
|
||||
self.graphics.memory_allocator.clone(),
|
||||
ImageCreateInfo {
|
||||
image_type: ImageType::Dim2d,
|
||||
format,
|
||||
extent: [width, height, 1],
|
||||
usage: ImageUsage::TRANSFER_DST | ImageUsage::TRANSFER_SRC | ImageUsage::SAMPLED,
|
||||
..Default::default()
|
||||
},
|
||||
AllocationCreateInfo::default(),
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let buffer: Subbuffer<[u8]> = Buffer::new_slice(
|
||||
self.graphics.memory_allocator.clone(),
|
||||
BufferCreateInfo {
|
||||
usage: BufferUsage::TRANSFER_SRC,
|
||||
..Default::default()
|
||||
},
|
||||
AllocationCreateInfo {
|
||||
memory_type_filter: MemoryTypeFilter::PREFER_HOST
|
||||
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||
..Default::default()
|
||||
},
|
||||
data.len() as DeviceSize,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
buffer.write().unwrap().copy_from_slice(data.as_slice());
|
||||
|
||||
self.command_buffer
|
||||
.copy_buffer_to_image(CopyBufferToImageInfo::buffer_image(buffer, image.clone()))
|
||||
.unwrap();
|
||||
|
||||
image
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn texture2d_png(&mut self, bytes: Vec<u8>) -> Arc<ImmutableImage> {
|
||||
pub fn texture2d_png(&mut self, bytes: Vec<u8>) -> Arc<Image> {
|
||||
let cursor = Cursor::new(bytes);
|
||||
let decoder = png::Decoder::new(cursor);
|
||||
let mut reader = decoder.read_info().unwrap();
|
||||
@@ -604,13 +726,15 @@ impl<T> WlxCommandBuffer<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl WlxCommandBuffer<PrimaryAutoCommandBuffer> {
|
||||
pub fn end_render(mut self) -> Self {
|
||||
self.command_buffer.end_rendering().unwrap();
|
||||
impl WlxCommandBuffer {
|
||||
pub fn end_render_pass(mut self) -> Self {
|
||||
self.command_buffer
|
||||
.end_render_pass(SubpassEndInfo::default())
|
||||
.unwrap();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> PrimaryAutoCommandBuffer {
|
||||
pub fn build(self) -> Arc<PrimaryAutoCommandBuffer<Arc<StandardCommandBufferAllocator>>> {
|
||||
self.command_buffer.build().unwrap()
|
||||
}
|
||||
|
||||
@@ -629,11 +753,79 @@ impl WlxCommandBuffer<PrimaryAutoCommandBuffer> {
|
||||
pub struct WlxPipeline {
|
||||
pub graphics: Arc<WlxGraphics>,
|
||||
pub pipeline: Arc<GraphicsPipeline>,
|
||||
pub render_pass: Arc<RenderPass>,
|
||||
pub framebuffer: Arc<Framebuffer>,
|
||||
pub view: Arc<ImageView>,
|
||||
pub format: Format,
|
||||
}
|
||||
|
||||
impl WlxPipeline {
|
||||
fn new(
|
||||
render_target: Arc<ImageView>,
|
||||
graphics: Arc<WlxGraphics>,
|
||||
vert: Arc<ShaderModule>,
|
||||
frag: Arc<ShaderModule>,
|
||||
format: Format,
|
||||
) -> 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: {},
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Self::new_from_pass(render_target, render_pass, graphics, vert, frag, format)
|
||||
}
|
||||
|
||||
fn new_with_layout(
|
||||
render_target: Arc<ImageView>,
|
||||
graphics: Arc<WlxGraphics>,
|
||||
vert: Arc<ShaderModule>,
|
||||
frag: Arc<ShaderModule>,
|
||||
format: Format,
|
||||
initial_layout: ImageLayout,
|
||||
final_layout: ImageLayout,
|
||||
) -> Self {
|
||||
let render_pass_description = RenderPassCreateInfo {
|
||||
attachments: vec![AttachmentDescription {
|
||||
format: 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).unwrap();
|
||||
|
||||
Self::new_from_pass(render_target, render_pass, graphics, vert, frag, format)
|
||||
}
|
||||
|
||||
fn new_from_pass(
|
||||
render_target: Arc<ImageView>,
|
||||
render_pass: Arc<RenderPass>,
|
||||
graphics: Arc<WlxGraphics>,
|
||||
vert: Arc<ShaderModule>,
|
||||
frag: Arc<ShaderModule>,
|
||||
@@ -641,24 +833,64 @@ impl WlxPipeline {
|
||||
) -> 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())
|
||||
|
||||
let vertex_input_state = Vert2Uv::per_vertex()
|
||||
.definition(&vep.info().input_interface)
|
||||
.unwrap();
|
||||
|
||||
let stages = smallvec![
|
||||
PipelineShaderStageCreateInfo::new(vep),
|
||||
PipelineShaderStageCreateInfo::new(fep),
|
||||
];
|
||||
|
||||
let layout = PipelineLayout::new(
|
||||
graphics.device.clone(),
|
||||
PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages)
|
||||
.into_pipeline_layout_create_info(graphics.device.clone())
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let framebuffer = Framebuffer::new(
|
||||
render_pass.clone(),
|
||||
FramebufferCreateInfo {
|
||||
attachments: vec![render_target.clone()],
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
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: Some(AttachmentBlend::alpha()),
|
||||
..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).unwrap().into()),
|
||||
..GraphicsPipelineCreateInfo::layout(layout)
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Self {
|
||||
graphics,
|
||||
pipeline,
|
||||
format,
|
||||
render_pass,
|
||||
framebuffer,
|
||||
view: render_target,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,7 +901,7 @@ impl WlxPipeline {
|
||||
pub fn uniform_sampler(
|
||||
&self,
|
||||
set: usize,
|
||||
texture: Arc<dyn ImageViewAbstract>,
|
||||
texture: Arc<ImageView>,
|
||||
filter: Filter,
|
||||
) -> Arc<PersistentDescriptorSet> {
|
||||
let sampler = Sampler::new(
|
||||
@@ -689,6 +921,7 @@ impl WlxPipeline {
|
||||
&self.graphics.descriptor_set_allocator,
|
||||
layout.clone(),
|
||||
[WriteDescriptorSet::image_view_sampler(0, texture, sampler)],
|
||||
[],
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
@@ -701,6 +934,8 @@ impl WlxPipeline {
|
||||
self.graphics.memory_allocator.clone(),
|
||||
SubbufferAllocatorCreateInfo {
|
||||
buffer_usage: BufferUsage::UNIFORM_BUFFER,
|
||||
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
|
||||
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
@@ -716,6 +951,7 @@ impl WlxPipeline {
|
||||
&self.graphics.descriptor_set_allocator,
|
||||
layout.clone(),
|
||||
[WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)],
|
||||
[],
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
@@ -743,7 +979,7 @@ pub struct WlxPass {
|
||||
vertex_buffer: Subbuffer<[Vert2Uv]>,
|
||||
index_buffer: Subbuffer<[u16]>,
|
||||
descriptor_sets: Vec<Arc<PersistentDescriptorSet>>,
|
||||
pub command_buffer: Arc<SecondaryAutoCommandBuffer>,
|
||||
pub command_buffer: Arc<SecondaryAutoCommandBuffer<Arc<StandardCommandBufferAllocator>>>,
|
||||
}
|
||||
|
||||
impl WlxPass {
|
||||
@@ -755,9 +991,9 @@ impl WlxPass {
|
||||
descriptor_sets: Vec<Arc<PersistentDescriptorSet>>,
|
||||
) -> Self {
|
||||
let viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions,
|
||||
depth_range: 0.0..1.0,
|
||||
offset: [0.0, 0.0],
|
||||
extent: dimensions,
|
||||
depth_range: 0.0..=1.0,
|
||||
};
|
||||
|
||||
let pipeline_inner = pipeline.inner().clone();
|
||||
@@ -766,10 +1002,10 @@ impl WlxPass {
|
||||
pipeline.graphics.queue.queue_family_index(),
|
||||
CommandBufferUsage::MultipleSubmit,
|
||||
CommandBufferInheritanceInfo {
|
||||
render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRendering(
|
||||
CommandBufferInheritanceRenderingInfo {
|
||||
color_attachment_formats: vec![Some(pipeline.format)],
|
||||
..Default::default()
|
||||
render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRenderPass(
|
||||
CommandBufferInheritanceRenderPassInfo {
|
||||
subpass: Subpass::from(pipeline.render_pass.clone(), 0).unwrap(),
|
||||
framebuffer: None,
|
||||
},
|
||||
)),
|
||||
..Default::default()
|
||||
@@ -778,16 +1014,21 @@ impl WlxPass {
|
||||
.unwrap();
|
||||
|
||||
command_buffer
|
||||
.set_viewport(0, [viewport])
|
||||
.set_viewport(0, smallvec![viewport])
|
||||
.unwrap()
|
||||
.bind_pipeline_graphics(pipeline_inner)
|
||||
.unwrap()
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Graphics,
|
||||
pipeline.inner().layout().clone(),
|
||||
0,
|
||||
descriptor_sets.clone(),
|
||||
)
|
||||
.unwrap()
|
||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||
.unwrap()
|
||||
.bind_index_buffer(index_buffer.clone())
|
||||
.unwrap()
|
||||
.draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0)
|
||||
.or_else(|err| {
|
||||
if let Some(source) = err.source() {
|
||||
@@ -802,7 +1043,7 @@ impl WlxPass {
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
descriptor_sets,
|
||||
command_buffer: Arc::new(command_buffer.build().unwrap()),
|
||||
command_buffer: command_buffer.build().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user