added compute kernel helper

master
mitchellhansen 5 years ago
parent e476cb2e4e
commit 2327a7f05f

@ -56,7 +56,26 @@ mod util;
mod button; mod button;
mod workpiece; mod workpiece;
//struct Sprite {
// pub texture:
//
//
//}
/* /*
How the F am I going to do sprites?
I need sprites for the slider and buttons at least
The background + render of the toolpath can probably just be straight up hand manipulated textures
Sprite will have 4 verticies and a texture along with position and size attributes
*/ */
fn main() { fn main() {

@ -15,7 +15,7 @@ use image::{DynamicImage, ImageBuffer};
use image::GenericImageView; use image::GenericImageView;
use vulkano::descriptor::pipeline_layout::PipelineLayout; use vulkano::descriptor::pipeline_layout::PipelineLayout;
use image::GenericImage; use image::GenericImage;
use shade_runner::{ComputeLayout, CompileError, FragLayout, FragInput, FragOutput, VertInput, VertOutput, VertLayout}; use shade_runner::{ComputeLayout, CompileError, FragLayout, FragInput, FragOutput, VertInput, VertOutput, VertLayout, CompiledShaders, Entry};
use vulkano::descriptor::descriptor_set::{PersistentDescriptorSetBuf, PersistentDescriptorSetImg, PersistentDescriptorSetSampler}; use vulkano::descriptor::descriptor_set::{PersistentDescriptorSetBuf, PersistentDescriptorSetImg, PersistentDescriptorSetSampler};
use shaderc::CompileOptions; use shaderc::CompileOptions;
use vulkano::framebuffer::{Subpass, RenderPass, RenderPassAbstract, Framebuffer, FramebufferAbstract}; use vulkano::framebuffer::{Subpass, RenderPass, RenderPassAbstract, Framebuffer, FramebufferAbstract};
@ -35,6 +35,10 @@ use vulkano::image::attachment::AttachmentImage;
use vulkano::image::{Dimensions, ImageUsage}; use vulkano::image::{Dimensions, ImageUsage};
use vulkano::format::Format; use vulkano::format::Format;
use vulkano::sampler::{Sampler, Filter, MipmapMode, SamplerAddressMode}; use vulkano::sampler::{Sampler, Filter, MipmapMode, SamplerAddressMode};
use image::flat::NormalForm::ColumnMajorPacked;
mod compute_kernel;
use crate::vkprocessor::compute_kernel::ComputeKernel;
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
struct tVertex { position: [f32; 2] } struct tVertex { position: [f32; 2] }
@ -64,13 +68,14 @@ fn window_size_dependent_setup(
} }
#[repr(C)] #[repr(C)]
struct MySpecConstants { #[derive(Clone)]
my_integer_constant: i32, struct SimpleSpecializationConstants {
a_boolean: u32, first_constant: i32,
floating_point: f32, second_constant: u32,
third_constant: f32,
} }
unsafe impl SpecializationConstants for MySpecConstants { unsafe impl SpecializationConstants for SimpleSpecializationConstants {
fn descriptors() -> &'static [SpecializationMapEntry] { fn descriptors() -> &'static [SpecializationMapEntry] {
static DESCRIPTORS: [SpecializationMapEntry; 3] = [ static DESCRIPTORS: [SpecializationMapEntry; 3] = [
SpecializationMapEntry { SpecializationMapEntry {
@ -96,6 +101,9 @@ unsafe impl SpecializationConstants for MySpecConstants {
pub struct VkProcessor<'a> { pub struct VkProcessor<'a> {
pub compute_kernel: Option<ComputeKernel>,
pub vertex_shader_path: PathBuf,
pub fragment_shader_path: PathBuf,
pub instance: Arc<Instance>, pub instance: Arc<Instance>,
pub physical: PhysicalDevice<'a>, pub physical: PhysicalDevice<'a>,
pub graphics_pipeline: Option<Arc<GraphicsPipelineAbstract + Sync + Send>>, pub graphics_pipeline: Option<Arc<GraphicsPipelineAbstract + Sync + Send>>,
@ -107,7 +115,7 @@ pub struct VkProcessor<'a> {
pub img_set: Option<Arc<PersistentDescriptorSet<Arc<dyn GraphicsPipelineAbstract + Send + Sync>, ((((), PersistentDescriptorSetImg<Arc<ImmutableImage<Format>>>), PersistentDescriptorSetSampler), PersistentDescriptorSetImg<Arc<AttachmentImage>>)>>>, pub img_set: Option<Arc<PersistentDescriptorSet<Arc<dyn GraphicsPipelineAbstract + Send + Sync>, ((((), PersistentDescriptorSetImg<Arc<ImmutableImage<Format>>>), PersistentDescriptorSetSampler), PersistentDescriptorSetImg<Arc<AttachmentImage>>)>>>,
pub graphics_image_buffer: Option<Arc<ImmutableImage<Format>>>, pub graphics_image_buffer: Option<Arc<ImmutableImage<Format>>>,
pub image_buffer: Vec<u8>, pub image_buffer: Vec<u8>,
pub img_buffers: Vec<Arc<CpuAccessibleBuffer<[u8]>>>, pub compute_image_buffers: Vec<Arc<CpuAccessibleBuffer<[u8]>>>,
pub settings_buffer: Option<Arc<CpuAccessibleBuffer<[u32]>>>, pub settings_buffer: Option<Arc<CpuAccessibleBuffer<[u32]>>>,
pub swapchain: Option<Arc<Swapchain<Window>>>, pub swapchain: Option<Arc<Swapchain<Window>>>,
pub images: Option<Vec<Arc<SwapchainImage<Window>>>>, pub images: Option<Vec<Arc<SwapchainImage<Window>>>>,
@ -115,7 +123,7 @@ pub struct VkProcessor<'a> {
pub render_pass: Option<Arc<RenderPassAbstract + Send + Sync>>, pub render_pass: Option<Arc<RenderPassAbstract + Send + Sync>>,
pub vertex_buffer: Option<Arc<(dyn BufferAccess + std::marker::Send + std::marker::Sync + 'static)>>, pub vertex_buffer: Option<Arc<(dyn BufferAccess + std::marker::Send + std::marker::Sync + 'static)>>,
pub dynamic_state: DynamicState, pub dynamic_state: DynamicState,
pub graphics_iamge_swap_buffer: Option<std::sync::Arc<vulkano::image::attachment::AttachmentImage>>, pub graphics_image_swap_buffer: Option<std::sync::Arc<vulkano::image::attachment::AttachmentImage>>,
} }
@ -140,6 +148,9 @@ impl<'a> VkProcessor<'a> {
let queue = queues.next().unwrap(); let queue = queues.next().unwrap();
VkProcessor { VkProcessor {
compute_kernel: Option::None,
vertex_shader_path: Default::default(),
fragment_shader_path: Default::default(),
instance: instance.clone(), instance: instance.clone(),
physical: physical.clone(), physical: physical.clone(),
graphics_pipeline: Option::None, graphics_pipeline: Option::None,
@ -151,7 +162,7 @@ impl<'a> VkProcessor<'a> {
img_set: Option::None, img_set: Option::None,
graphics_image_buffer: None, graphics_image_buffer: None,
image_buffer: Vec::new(), image_buffer: Vec::new(),
img_buffers: Vec::new(), compute_image_buffers: Vec::new(),
settings_buffer: Option::None, settings_buffer: Option::None,
swapchain: Option::None, swapchain: Option::None,
images: Option::None, images: Option::None,
@ -159,49 +170,18 @@ impl<'a> VkProcessor<'a> {
render_pass: Option::None, render_pass: Option::None,
vertex_buffer: Option::None, vertex_buffer: Option::None,
dynamic_state: DynamicState { line_width: None, viewports: None, scissors: None }, dynamic_state: DynamicState { line_width: None, viewports: None, scissors: None },
graphics_iamge_swap_buffer: None, graphics_image_swap_buffer: None,
} }
} }
pub fn compile_kernel(&mut self, filename: String) {
let project_root =
std::env::current_dir()
.expect("failed to get root directory");
let mut compute_path = project_root.clone();
compute_path.push(PathBuf::from("resources/shaders/"));
compute_path.push(PathBuf::from(filename));
let mut options = CompileOptions::new().ok_or(CompileError::CreateCompiler).unwrap();
options.add_macro_definition("SETTING_POS_X", Some("0"));
options.add_macro_definition("SETTING_POS_Y", Some("1"));
options.add_macro_definition("SETTING_BUCKETS_START", Some("2"));
options.add_macro_definition("SETTING_BUCKETS_LEN", Some("2"));
let shader =
sr::load_compute_with_options(compute_path, options)
.expect("Failed to compile");
let vulkano_entry = pub fn compile_kernel(&mut self, filename: String) {
sr::parse_compute(&shader)
.expect("failed to parse");
let x = unsafe {
vulkano::pipeline::shader::ShaderModule::from_words(self.device.clone(), &shader.compute)
}.unwrap();
let compute_pipeline = Arc::new({ self.compute_kernel = Some(ComputeKernel::new(filename, self.device.clone()));
unsafe { self.compute_pipeline = Some(self.compute_kernel.clone().unwrap().get_pipeline());
ComputePipeline::new(self.device.clone(), &x.compute_entry_point(
CStr::from_bytes_with_nul_unchecked(b"main\0"),
vulkano_entry.compute_layout), &(),
).unwrap()
} }
});
self.compute_pipeline = Some(compute_pipeline);
}
pub fn compile_shaders(&mut self, filename: String, surface: &'a Arc<Surface<Window>>) { pub fn compile_shaders(&mut self, filename: String, surface: &'a Arc<Surface<Window>>) {
@ -262,16 +242,9 @@ impl<'a> VkProcessor<'a> {
options.add_macro_definition("SETTING_BUCKETS_START", Some("2")); options.add_macro_definition("SETTING_BUCKETS_START", Some("2"));
options.add_macro_definition("SETTING_BUCKETS_LEN", Some("2")); options.add_macro_definition("SETTING_BUCKETS_LEN", Some("2"));
let shader = sr::load(vertex_shader_path, fragment_shader_path).expect(""); // TODO: better compile message, run til successful compile
// let shader = match sr::load(vertex_shader_path, fragment_shader_path) { let shader = sr::load(vertex_shader_path, fragment_shader_path)
// Ok(t) => t, .expect("Shader didn't compile");
// Err(e) => {
//
// panic!(e);
// }
// };
let vulkano_entry = let vulkano_entry =
sr::parse(&shader) sr::parse(&shader)
@ -285,7 +258,7 @@ impl<'a> VkProcessor<'a> {
vulkano::pipeline::shader::ShaderModule::from_words(self.device.clone(), &shader.vertex) vulkano::pipeline::shader::ShaderModule::from_words(self.device.clone(), &shader.vertex)
}.unwrap(); }.unwrap();
let frag_entry_point: GraphicsEntryPoint<MySpecConstants, FragInput, FragOutput, FragLayout> = unsafe { let frag_entry_point: GraphicsEntryPoint<SimpleSpecializationConstants, FragInput, FragOutput, FragLayout> = unsafe {
x1.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"), x1.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"),
vulkano_entry.frag_input, vulkano_entry.frag_input,
vulkano_entry.frag_output, vulkano_entry.frag_output,
@ -293,7 +266,7 @@ impl<'a> VkProcessor<'a> {
GraphicsShaderType::Fragment) GraphicsShaderType::Fragment)
}; };
let vert_entry_point: GraphicsEntryPoint<MySpecConstants, VertInput, VertOutput, VertLayout> = unsafe { let vert_entry_point: GraphicsEntryPoint<SimpleSpecializationConstants, VertInput, VertOutput, VertLayout> = unsafe {
x2.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"), x2.graphics_entry_point(CStr::from_bytes_with_nul_unchecked(b"main\0"),
vulkano_entry.vert_input, vulkano_entry.vert_input,
vulkano_entry.vert_output, vulkano_entry.vert_output,
@ -345,20 +318,20 @@ impl<'a> VkProcessor<'a> {
// A Vulkan shader can in theory contain multiple entry points, so we have to specify // A Vulkan shader can in theory contain multiple entry points, so we have to specify
// which one. The `main` word of `main_entry_point` actually corresponds to the name of // which one. The `main` word of `main_entry_point` actually corresponds to the name of
// the entry point. // the entry point.
.vertex_shader(vert_entry_point, MySpecConstants { .vertex_shader(vert_entry_point, SimpleSpecializationConstants {
my_integer_constant: 0, first_constant: 0,
a_boolean: 0, second_constant: 0,
floating_point: 0.0, third_constant: 0.0,
}) })
// The content of the vertex buffer describes a list of triangles. // The content of the vertex buffer describes a list of triangles.
.triangle_fan() .triangle_fan()
// Use a resizable viewport set to draw over the entire window // Use a resizable viewport set to draw over the entire window
.viewports_dynamic_scissors_irrelevant(1) .viewports_dynamic_scissors_irrelevant(1)
// See `vertex_shader`. // See `vertex_shader`.
.fragment_shader(frag_entry_point, MySpecConstants { .fragment_shader(frag_entry_point, SimpleSpecializationConstants {
my_integer_constant: 0, first_constant: 0,
a_boolean: 0, second_constant: 0,
floating_point: 0.0, third_constant: 0.0,
}) })
// We have to indicate which subpass of which render pass this pipeline is going to be used // We have to indicate which subpass of which render pass this pipeline is going to be used
// in. The pipeline will only be usable from this particular subpass. // in. The pipeline will only be usable from this particular subpass.
@ -467,8 +440,8 @@ impl<'a> VkProcessor<'a> {
self.compute_set = Some(Arc::new(set.build().unwrap())); self.compute_set = Some(Arc::new(set.build().unwrap()));
self.img_buffers.push(write_buffer); self.compute_image_buffers.push(write_buffer);
self.img_buffers.push(read_buffer); self.compute_image_buffers.push(read_buffer);
self.settings_buffer = Some(settings_buffer); self.settings_buffer = Some(settings_buffer);
@ -493,9 +466,6 @@ impl<'a> VkProcessor<'a> {
Dimensions::Dim2d { width: self.xy.0, height: self.xy.1 }, Dimensions::Dim2d { width: self.xy.0, height: self.xy.1 },
Format::R8G8B8A8Srgb, Format::R8G8B8A8Srgb,
self.queue.clone() self.queue.clone()
// self.image_buffer.iter().cloned(),
// Format::R8G8B8A8Uint,
).unwrap() ).unwrap()
}; };
@ -516,14 +486,13 @@ impl<'a> VkProcessor<'a> {
MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat,
SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap(); SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap();
self.img_set = Some(Arc::new(PersistentDescriptorSet::start(self.graphics_pipeline.clone().unwrap().clone(), 0) self.img_set = Some(Arc::new(PersistentDescriptorSet::start(self.graphics_pipeline.clone().unwrap().clone(), 0)
.add_sampled_image(texture.clone(), sampler.clone()).unwrap() .add_sampled_image(texture.clone(), sampler.clone()).unwrap()
.add_image(attachment_image.clone().unwrap().clone()).unwrap() .add_image(attachment_image.clone().unwrap().clone()).unwrap()
.build().unwrap())); .build().unwrap()));
self.graphics_image_buffer = Some(texture.clone()); self.graphics_image_buffer = Some(texture.clone());
self.graphics_iamge_swap_buffer = Some(attachment_image.clone().unwrap()); self.graphics_image_swap_buffer = Some(attachment_image.clone().unwrap());
} }
pub fn run(&mut self, surface: &'a Arc<Surface<Window>>, mut frame_future: Box<dyn GpuFuture>) -> Box<dyn GpuFuture> { pub fn run(&mut self, surface: &'a Arc<Surface<Window>>, mut frame_future: Box<dyn GpuFuture>) -> Box<dyn GpuFuture> {
@ -585,8 +554,8 @@ impl<'a> VkProcessor<'a> {
self.compute_pipeline.clone().unwrap().clone(), self.compute_pipeline.clone().unwrap().clone(),
self.compute_set.clone().unwrap().clone(), ()).unwrap() self.compute_set.clone().unwrap().clone(), ()).unwrap()
.copy_buffer_to_image(self.img_buffers.get(0).unwrap().clone(), .copy_buffer_to_image(self.compute_image_buffers.get(0).unwrap().clone(),
self.graphics_iamge_swap_buffer.clone().unwrap()).unwrap() self.graphics_image_swap_buffer.clone().unwrap()).unwrap()
.begin_render_pass(framebuffers[image_num].clone(), false, clear_values) .begin_render_pass(framebuffers[image_num].clone(), false, clear_values)
.unwrap() .unwrap()
@ -600,7 +569,7 @@ impl<'a> VkProcessor<'a> {
.build().unwrap(); .build().unwrap();
let mut data_buffer_content = self.img_buffers.get(0).unwrap().read().unwrap(); let mut data_buffer_content = self.compute_image_buffers.get(0).unwrap().read().unwrap();
let img = ImageBuffer::from_fn(self.xy.0, self.xy.1, |x, y| { let img = ImageBuffer::from_fn(self.xy.0, self.xy.1, |x, y| {
let r = data_buffer_content[((self.xy.0 * y + x) * 4 + 0) as usize] as u8; let r = data_buffer_content[((self.xy.0 * y + x) * 4 + 0) as usize] as u8;
let g = data_buffer_content[((self.xy.0 * y + x) * 4 + 1) as usize] as u8; let g = data_buffer_content[((self.xy.0 * y + x) * 4 + 1) as usize] as u8;

@ -0,0 +1,143 @@
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, DeviceLocalBuffer, ImmutableBuffer, BufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState};
use vulkano::descriptor::descriptor_set::{PersistentDescriptorSet, StdDescriptorPoolAlloc};
use vulkano::device::{Device, DeviceExtensions, QueuesIter, Queue};
use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice, QueueFamily};
use vulkano::pipeline::{ComputePipeline, GraphicsPipeline, GraphicsPipelineAbstract};
use vulkano::sync::{GpuFuture, FlushError};
use vulkano::sync;
use std::time::SystemTime;
use std::sync::Arc;
use std::ffi::CStr;
use std::path::PathBuf;
use shade_runner as sr;
use image::{DynamicImage, ImageBuffer};
use image::GenericImageView;
use vulkano::descriptor::pipeline_layout::PipelineLayout;
use image::GenericImage;
use shade_runner::{ComputeLayout, CompileError, FragLayout, FragInput, FragOutput, VertInput, VertOutput, VertLayout, CompiledShaders, Entry};
use vulkano::descriptor::descriptor_set::{PersistentDescriptorSetBuf, PersistentDescriptorSetImg, PersistentDescriptorSetSampler};
use shaderc::CompileOptions;
use vulkano::framebuffer::{Subpass, RenderPass, RenderPassAbstract, Framebuffer, FramebufferAbstract};
use vulkano::pipeline::shader::{GraphicsShaderType, ShaderModule, GraphicsEntryPoint, SpecializationConstants, SpecializationMapEntry};
use vulkano::swapchain::{Swapchain, PresentMode, SurfaceTransform, Surface, SwapchainCreationError, AcquireError};
use vulkano::swapchain::acquire_next_image;
use vulkano::image::swapchain::SwapchainImage;
use winit::{EventsLoop, WindowBuilder, Window, Event, WindowEvent};
use vulkano_win::VkSurfaceBuild;
use vulkano::pipeline::vertex::{SingleBufferDefinition, Vertex};
use vulkano::descriptor::PipelineLayoutAbstract;
use std::alloc::Layout;
use vulkano::pipeline::viewport::Viewport;
use image::ImageFormat;
use vulkano::image::immutable::ImmutableImage;
use vulkano::image::attachment::AttachmentImage;
use vulkano::image::{Dimensions, ImageUsage};
use vulkano::format::Format;
use vulkano::sampler::{Sampler, Filter, MipmapMode, SamplerAddressMode};
use image::flat::NormalForm::ColumnMajorPacked;
use crate::vkprocessor::SimpleSpecializationConstants;
#[derive(Clone)]
pub struct ComputeKernel {
compute_pipeline: Option<std::sync::Arc<ComputePipeline<PipelineLayout<shade_runner::layouts::ComputeLayout>>>>,
compute_kernel_path: PathBuf,
shader: CompiledShaders,
entry: Entry,
shader_module: Arc<ShaderModule>,
device: Arc<Device>,
specialization_constants: SimpleSpecializationConstants,
}
impl ComputeKernel {
fn get_path(filename: String) -> PathBuf {
let project_root =
std::env::current_dir()
.expect("failed to get root directory");
let mut compute_path = project_root.clone();
compute_path.push(PathBuf::from("resources/shaders/"));
compute_path.push(PathBuf::from(filename));
compute_path
}
pub fn new(filename: String, device: Arc<Device>) -> ComputeKernel {
let compute_path = ComputeKernel::get_path(filename);
let mut options = CompileOptions::new().ok_or(CompileError::CreateCompiler).unwrap();
let shader = sr::load_compute_with_options(compute_path.clone(), options)
.expect("Failed to compile");
let entry = sr::parse_compute(&shader)
.expect("Failed to parse");
let shader_module = unsafe {
vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader.compute)
}.unwrap();
ComputeKernel {
device: device,
shader: shader,
compute_pipeline: Option::None,
compute_kernel_path: compute_path,
entry: entry,
shader_module: shader_module,
specialization_constants: SimpleSpecializationConstants {
first_constant: 0,
second_constant: 0,
third_constant: 0.0
}
}
}
pub fn get_pipeline(&mut self) -> std::sync::Arc<ComputePipeline<PipelineLayout<shade_runner::layouts::ComputeLayout>>> {
match self.compute_pipeline.clone() {
Some(t) => t,
None => {
self.compute_pipeline = Some(Arc::new({
unsafe {
ComputePipeline::new(self.device.clone(), &self.shader_module.compute_entry_point(
CStr::from_bytes_with_nul_unchecked(b"main\0"),
self.entry.compute_layout.clone()), &self.specialization_constants,
).unwrap()
}
}));
self.compute_pipeline.clone().unwrap()
}
}
}
pub fn recompile_kernel(&mut self) {
self.compile_kernel(String::from(self.compute_kernel_path.clone().to_str().unwrap()));
}
pub fn compile_kernel(&mut self, filename: String) -> std::sync::Arc<ComputePipeline<PipelineLayout<shade_runner::layouts::ComputeLayout>>> {
let mut options = CompileOptions::new().ok_or(CompileError::CreateCompiler).unwrap();
self.compute_kernel_path = ComputeKernel::get_path(filename);
self.shader =
sr::load_compute_with_options(self.compute_kernel_path.clone(), options)
.expect("Failed to compile");
self.entry =
sr::parse_compute(&self.shader)
.expect("Failed to parse");
self.shader_module = unsafe {
vulkano::pipeline::shader::ShaderModule::from_words(self.device.clone(), &self.shader.compute)
}.unwrap();
self.get_pipeline()
}
}
Loading…
Cancel
Save