diff --git a/notes/Home.txt b/notes/Home.txt index 3afcc167..0a1dfff5 100644 --- a/notes/Home.txt +++ b/notes/Home.txt @@ -16,6 +16,21 @@ Main Systems: [[VKProcessor:DynamicVertex|DynamicVertex]] =========== [[VKProcessor:CompuState|CompuState]] [[~/source/Trac3r-rust/doc/sfml_rust/compute/compu_state/struct.CompuState.html|===========]] + +-------------------- + + +=== Trac3r : A program to convert images to 2D toolpaths === + + TODO: + + Text rendering is half implemented. + + Need generalized interface for render (image, texture, text) + + Currently using local copies of a few libraries: + shade_runner + vulkano/vulkano-win + vulkano/vulkano-shaders + vulkano/vulkano + -------------------- ====== Warming Up ====== diff --git a/resources/examples/vulkan_example.rs b/resources/examples/vulkan_example.rs deleted file mode 100644 index 01b390cf..00000000 --- a/resources/examples/vulkan_example.rs +++ /dev/null @@ -1,525 +0,0 @@ - -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::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass}; -use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice, QueueFamily}; -use vulkano::pipeline::{ComputePipeline, GraphicsPipeline}; -use vulkano::pipeline::viewport::Viewport; -use vulkano::sync::{FlushError, GpuFuture}; -use vulkano::sync; -use vulkano::image::SwapchainImage; -use vulkano::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError}; -use vulkano::swapchain; -use std::time::SystemTime; -use std::sync::Arc; -use std::ffi::CStr; -use std::path::PathBuf; -use shade_runner as sr; -use image::{DynamicImage, GenericImage, GenericImageView, ImageBuffer}; -use vulkano::descriptor::pipeline_layout::PipelineLayout; -use shade_runner::{ComputeLayout, CompileError}; -use vulkano::descriptor::descriptor_set::PersistentDescriptorSetBuf; -use shaderc::CompileOptions; -use winit::{Event, EventsLoop, Window, WindowBuilder, WindowEvent}; -use vulkano_win::VkSurfaceBuild; -use vulkano::SafeDeref; - - - -fn main() { - let instance = { - let extensions = vulkano_win::required_extensions(); - Instance::new(None, &extensions, None).unwrap() - }; - - let physical = PhysicalDevice::enumerate(&instance).next().unwrap(); - - // The objective of this example is to draw a triangle on a window. To do so, we first need to - // create the window. - // - // This is done by creating a `WindowBuilder` from the `winit` crate, then calling the - // `build_vk_surface` method provided by the `VkSurfaceBuild` trait from `vulkano_win`. If you - // ever get an error about `build_vk_surface` being undefined in one of your projects, this - // probably means that you forgot to import this trait. - // - // This returns a `vulkano::swapchain::Surface` object that contains both a cross-platform winit - // window and a cross-platform Vulkan surface that represents the surface of the window. - let mut events_loop = EventsLoop::new(); - - let surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap(); - let window = surface.window(); - - let queue_family = physical.queue_families().find(|&q| { - // We take the first queue that supports drawing to our window. - q.supports_graphics() && - surface.is_supported(q).unwrap_or(false) && - q.supports_compute() - }).unwrap(); - - let device_ext = DeviceExtensions { khr_swapchain: true, ..DeviceExtensions::none() }; - let (device, mut queues) = Device::new(physical, physical.supported_features(), &device_ext, - [(queue_family, 0.5)].iter().cloned()).unwrap(); - - let queue = queues.next().unwrap(); - - // Before we can draw on the surface, we have to create what is called a swapchain. Creating - // a swapchain allocates the color buffers that will contain the image that will ultimately - // be visible on the screen. These images are returned alongside with the swapchain. - let (mut swapchain, images) = { - // Querying the capabilities of the surface. When we create the swapchain we can only - // pass values that are allowed by the capabilities. - let capabilities = surface.capabilities(physical).unwrap(); - - let usage = capabilities.supported_usage_flags; - - // The alpha mode indicates how the alpha value of the final image will behave. For example - // you can choose whether the window will be opaque or transparent. - let alpha = capabilities.supported_composite_alpha.iter().next().unwrap(); - - // Choosing the internal format that the images will have. - let format = capabilities.supported_formats[0].0; - - // The dimensions of the window, only used to initially setup the swapchain. - // NOTE: - // On some drivers the swapchain dimensions are specified by `caps.current_extent` and the - // swapchain size must use these dimensions. - // These dimensions are always the same as the window dimensions - // - // However other drivers dont specify a value i.e. `caps.current_extent` is `None` - // These drivers will allow anything but the only sensible value is the window dimensions. - // - // Because for both of these cases, the swapchain needs to be the window dimensions, we just use that. - let initial_dimensions = if let Some(dimensions) = window.get_inner_size() { - // convert to physical pixels - let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into(); - [dimensions.0, dimensions.1] - } else { - // The window no longer exists so exit the application. - return; - }; - - // Please take a look at the docs for the meaning of the parameters we didn't mention. - Swapchain::new(device.clone(), surface.clone(), capabilities.min_image_count, format, - initial_dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha, - PresentMode::Fifo, true, None).unwrap() - }; - - - // We now create a buffer that will store the shape of our triangle. - let vertex_buffer = { - #[derive(Default, Debug, Clone)] - struct Vertex { position: [f32; 2] } - vulkano::impl_vertex!(Vertex, position); - - CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), [ - Vertex { position: [-0.5, -0.25] }, - Vertex { position: [0.0, 0.5] }, - Vertex { position: [0.25, -0.1] } - ].iter().cloned()).unwrap() - }; - - mod vs { - vulkano_shaders::shader! { - ty: "vertex", - src: " -#version 450 - -layout(location = 0) in vec2 position; - -void main() { - gl_Position = vec4(position, 0.0, 1.0); -}" - } - } - - mod fs { - vulkano_shaders::shader! { - ty: "fragment", - src: " -#version 450 - -layout(location = 0) out vec4 f_color; - -void main() { - f_color = vec4(1.0, 0.0, 0.0, 1.0); -} -" - } - } - - let vs = vs::Shader::load(device.clone()).unwrap(); - let fs = fs::Shader::load(device.clone()).unwrap(); - - // The next step is to create a *render pass*, which is an object that describes where the - // output of the graphics pipeline will go. It describes the layout of the images - // where the colors, depth and/or stencil information will be written. - let render_pass = Arc::new(vulkano::single_pass_renderpass!( - device.clone(), - attachments: { - // `color` is a custom name we give to the first and only attachment. - color: { - // `load: Clear` means that we ask the GPU to clear the content of this - // attachment at the start of the drawing. - load: Clear, - // `store: Store` means that we ask the GPU to store the output of the draw - // in the actual image. We could also ask it to discard the result. - store: Store, - // `format: ` indicates the type of the format of the image. This has to - // be one of the types of the `vulkano::format` module (or alternatively one - // of your structs that implements the `FormatDesc` trait). Here we use the - // same format as the swapchain. - format: swapchain.format(), - // TODO: - samples: 1, - } - }, - pass: { - // We use the attachment named `color` as the one and only color attachment. - color: [color], - // No depth-stencil attachment is indicated with empty brackets. - depth_stencil: {} - } - ).unwrap()); - - // Before we draw we have to create what is called a pipeline. This is similar to an OpenGL - // program, but much more specific. - let pipeline = Arc::new(GraphicsPipeline::start() - // We need to indicate the layout of the vertices. - // The type `SingleBufferDefinition` actually contains a template parameter corresponding - // to the type of each vertex. But in this code it is automatically inferred. - .vertex_input_single_buffer() - // 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 - // the entry point. - .vertex_shader(vs.main_entry_point(), ()) - // The content of the vertex buffer describes a list of triangles. - .triangle_list() - // Use a resizable viewport set to draw over the entire window - .viewports_dynamic_scissors_irrelevant(1) - // See `vertex_shader`. - .fragment_shader(fs.main_entry_point(), ()) - - .depth_stencil_simple_depth() - // 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. - .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) - // Now that our builder is filled, we call `build()` to obtain an actual pipeline. - .build(device.clone()) - .unwrap()); - - // Dynamic viewports allow us to recreate just the viewport when the window is resized - // Otherwise we would have to recreate the whole pipeline. - let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None }; - - // The render pass we created above only describes the layout of our framebuffers. Before we - // can draw we also need to create the actual framebuffers. - // - // Since we need to draw to multiple images, we are going to create a different framebuffer for - // each image. - let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state); - - // Initialization is finally finished! - - // In some situations, the swapchain will become invalid by itself. This includes for example - // when the window is resized (as the images of the swapchain will no longer match the - // window's) or, on Android, when the application went to the background and goes back to the - // foreground. - // - // In this situation, acquiring a swapchain image or presenting it will return an error. - // Rendering to an image of that swapchain will not produce any error, but may or may not work. - // To continue rendering, we need to recreate the swapchain by creating a new swapchain. - // Here, we remember that we need to do this for the next loop iteration. - let mut recreate_swapchain = false; - - // In the loop below we are going to submit commands to the GPU. Submitting a command produces - // an object that implements the `GpuFuture` trait, which holds the resources for as long as - // they are in use by the GPU. - // - // Destroying the `GpuFuture` blocks until the GPU is finished executing it. In order to avoid - // that, we store the submission of the previous frame here. - let mut previous_frame_end = Box::new(sync::now(device.clone())) as Box; - - loop { - // It is important to call this function from time to time, otherwise resources will keep - // accumulating and you will eventually reach an out of memory error. - // Calling this function polls various fences in order to determine what the GPU has - // already processed, and frees the resources that are no longer needed. - previous_frame_end.cleanup_finished(); - - // Whenever the window resizes we need to recreate everything dependent on the window size. - // In this example that includes the swapchain, the framebuffers and the dynamic state viewport. - if recreate_swapchain { - // Get the new dimensions of the window. - let dimensions = if let Some(dimensions) = window.get_inner_size() { - let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into(); - [dimensions.0, dimensions.1] - } else { - return; - }; - - let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) { - Ok(r) => r, - // This error tends to happen when the user is manually resizing the window. - // Simply restarting the loop is the easiest way to fix this issue. - Err(SwapchainCreationError::UnsupportedDimensions) => continue, - Err(err) => panic!("{:?}", err) - }; - - swapchain = new_swapchain; - // Because framebuffers contains an Arc on the old swapchain, we need to - // recreate framebuffers as well. - framebuffers = window_size_dependent_setup(&new_images, render_pass.clone(), &mut dynamic_state); - - recreate_swapchain = false; - } - - // Before we can draw on the output, we have to *acquire* an image from the swapchain. If - // no image is available (which happens if you submit draw commands too quickly), then the - // function will block. - // This operation returns the index of the image that we are allowed to draw upon. - // - // This function can block if no image is available. The parameter is an optional timeout - // after which the function call will return an error. - let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) { - Ok(r) => r, - Err(AcquireError::OutOfDate) => { - recreate_swapchain = true; - continue; - } - Err(err) => panic!("{:?}", err) - }; - - // Specify the color to clear the framebuffer with i.e. blue - let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into()); - - - { - 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("simple-edge.compute")); - - - 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 = - shade_runner::load_compute_with_options(compute_path, options) - .expect("Failed to compile"); - - let vulkano_entry = - shade_runner::parse_compute(&shader) - .expect("failed to parse"); - - let x = unsafe { - vulkano::pipeline::shader::ShaderModule::from_words(device.clone(), &shader.compute) - }.unwrap(); - - let c_pipeline = Arc::new({ - unsafe { - ComputePipeline::new(device.clone(), &x.compute_entry_point( - CStr::from_bytes_with_nul_unchecked(b"main\0"), - vulkano_entry.compute_layout), &(), - ).unwrap() - } - }); - - 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/images/")); - compute_path.push(PathBuf::from("funky-bird.jpg")); - - let img = image::open(compute_path).expect("Couldn't find image"); - - let xy = img.dimensions(); - - let data_length = xy.0 * xy.1 * 4; - let pixel_count = img.raw_pixels().len(); - println!("Pixel count {}", pixel_count); - - let mut image_buffer = Vec::new(); - if pixel_count != data_length as usize { - println!("Creating apha channel..."); - for i in img.raw_pixels().iter() { - if (image_buffer.len() + 1) % 4 == 0 { - image_buffer.push(255); - } - image_buffer.push(*i); - } - image_buffer.push(255); - } else { - image_buffer = img.raw_pixels(); - } - - println!("Buffer length {}", image_buffer.len()); - println!("Size {:?}", xy); - - println!("Allocating Buffers..."); - - // Pull out the image data and place it in a buffer for the kernel to write to and for us to read from - let write_buffer = { - let mut buff = image_buffer.iter(); - let data_iter = (0..data_length).map(|n| *(buff.next().unwrap())); - CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), data_iter).unwrap() - }; - - - // Pull out the image data and place it in a buffer for the kernel to read from - let read_buffer = { - let mut buff = image_buffer.iter(); - let data_iter = (0..data_length).map(|n| *(buff.next().unwrap())); - CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), data_iter).unwrap() - }; - - - // A buffer to hold many i32 values to use as settings - let settings_buffer = { - let vec = vec![xy.0, xy.1]; - let mut buff = vec.iter(); - let data_iter = - (0..2).map(|n| *(buff.next().unwrap())); - CpuAccessibleBuffer::from_iter(device.clone(), - BufferUsage::all(), - data_iter).unwrap() - }; - - println!("Done"); - - // Create the data descriptor set for our previously created shader pipeline - let mut set = - PersistentDescriptorSet::start(c_pipeline.clone(), 0) - .add_buffer(write_buffer.clone()).unwrap() - .add_buffer(read_buffer.clone()).unwrap() - .add_buffer(settings_buffer.clone()).unwrap(); - - let mut set = Arc::new(set.build().unwrap()); - - - - - // In order to draw, we have to build a *command buffer*. The command buffer object holds - // the list of commands that are going to be executed. - // - // Building a command buffer is an expensive operation (usually a few hundred - // microseconds), but it is known to be a hot path in the driver and is expected to be - // optimized. - // - // Note that we have to pass a queue family when we create the command buffer. The command - // buffer will only be executable on that given queue family. - let command_buffer = - AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()) - .unwrap() - - .dispatch([xy.0, xy.1, 1], - c_pipeline.clone(), - set.clone(), ()).unwrap() - // Before we can draw, we have to *enter a render pass*. There are two methods to do - // this: `draw_inline` and `draw_secondary`. The latter is a bit more advanced and is - // not covered here. - // - // The third parameter builds the list of values to clear the attachments with. The API - // is similar to the list of attachments when building the framebuffers, except that - // only the attachments that use `load: Clear` appear in the list. - .begin_render_pass(framebuffers[image_num].clone(), false, clear_values) - .unwrap() - - - // We are now inside the first subpass of the render pass. We add a draw command. - // - // The last two parameters contain the list of resources to pass to the shaders. - // Since we used an `EmptyPipeline` object, the objects have to be `()`. - .draw(pipeline.clone(), &dynamic_state, vertex_buffer.clone(), (), ()) - .unwrap() - - // We leave the render pass by calling `draw_end`. Note that if we had multiple - // subpasses we could have called `next_inline` (or `next_secondary`) to jump to the - // next subpass. - .end_render_pass() - .unwrap() - - // Finish building the command buffer by calling `build`. - .build().unwrap(); - - let future = previous_frame_end.join(acquire_future) - .then_execute(queue.clone(), command_buffer).unwrap() - - // The color output is now expected to contain our triangle. But in order to show it on - // the screen, we have to *present* the image by calling `present`. - // - // This function does not actually present the image immediately. Instead it submits a - // present command at the end of the queue. This means that it will only be presented once - // the GPU has finished executing the command buffer that draws the triangle. - .then_swapchain_present(queue.clone(), swapchain.clone(), image_num) - .then_signal_fence_and_flush(); - - match future { - Ok(future) => { - previous_frame_end = Box::new(future) as Box<_>; - } - Err(FlushError::OutOfDate) => { - recreate_swapchain = true; - previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>; - } - Err(e) => { - println!("{:?}", e); - previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>; - } - } - } - // Note that in more complex programs it is likely that one of `acquire_next_image`, - // `command_buffer::submit`, or `present` will block for some time. This happens when the - // GPU's queue is full and the driver has to wait until the GPU finished some work. - // - // Unfortunately the Vulkan API doesn't provide any way to not wait or to detect when a - // wait would happen. Blocking may be the desired behavior, but if you don't want to - // block you should spawn a separate thread dedicated to submissions. - - // Handling the window events in order to close the program when the user wants to close - // it. - let mut done = false; - events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - Event::WindowEvent { event: WindowEvent::Resized(_), .. } => recreate_swapchain = true, - _ => () - } - }); - if done { return; } - } -} - -/// This method is called once during initialization, then again whenever the window is resized -fn window_size_dependent_setup( - images: &[Arc>], - render_pass: Arc, - dynamic_state: &mut DynamicState, -) -> Vec> { - let dimensions = images[0].dimensions(); - - let viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [dimensions[0] as f32, dimensions[1] as f32], - depth_range: 0.0..1.0, - }; - dynamic_state.viewports = Some(vec!(viewport)); - - images.iter().map(|image| { - Arc::new( - Framebuffer::start(render_pass.clone()) - .add(image.clone()).unwrap() - .build().unwrap() - ) as Arc - }).collect::>() -} - diff --git a/resources/examples/vulkano_img_example.rs b/resources/examples/vulkano_img_example.rs deleted file mode 100644 index a82234ee..00000000 --- a/resources/examples/vulkano_img_example.rs +++ /dev/null @@ -1,292 +0,0 @@ -Skip to content - -Search or jump to… - -Pull requests -Issues -Marketplace -Explore - -@MitchellHansen -69 -1,789 192 vulkano-rs/vulkano -Code Issues 171 Pull requests 15 Security Insights -vulkano/examples/src/bin/image/main.rs -@rukai rukai Fix warnings on nightly (#1213) -fc6ac6f 15 days ago -279 lines (232 sloc) 9.86 KB - -// Copyright (c) 2016 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// or the MIT -// license , -// at your option. All files in the project carrying such -// notice may not be copied, modified, or distributed except -// according to those terms. - -use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer}; -use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState}; -use vulkano::descriptor::descriptor_set::PersistentDescriptorSet; -use vulkano::device::{Device, DeviceExtensions}; -use vulkano::format::Format; -use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract}; -use vulkano::image::{SwapchainImage, ImmutableImage, Dimensions}; -use vulkano::instance::{Instance, PhysicalDevice}; -use vulkano::pipeline::GraphicsPipeline; -use vulkano::pipeline::viewport::Viewport; -use vulkano::sampler::{Sampler, SamplerAddressMode, Filter, MipmapMode}; -use vulkano::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError}; -use vulkano::swapchain; -use vulkano::sync::{GpuFuture, FlushError}; -use vulkano::sync; - -use vulkano_win::VkSurfaceBuild; - -use winit::{EventsLoop, Window, WindowBuilder, Event, WindowEvent}; - -use image::ImageFormat; - -use std::sync::Arc; - -fn main() { - // The start of this example is exactly the same as `triangle`. You should read the - // `triangle` example if you haven't done so yet. - - let extensions = vulkano_win::required_extensions(); - let instance = Instance::new(None, &extensions, None).unwrap(); - - let physical = PhysicalDevice::enumerate(&instance).next().unwrap(); - println!("Using device: {} (type: {:?})", physical.name(), physical.ty()); - - let mut events_loop = EventsLoop::new(); - let surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap(); - let window = surface.window(); - - let queue_family = physical.queue_families().find(|&q| - q.supports_graphics() && surface.is_supported(q).unwrap_or(false) - ).unwrap(); - - let device_ext = DeviceExtensions { khr_swapchain: true, .. DeviceExtensions::none() }; - let (device, mut queues) = Device::new(physical, physical.supported_features(), &device_ext, - [(queue_family, 0.5)].iter().cloned()).unwrap(); - let queue = queues.next().unwrap(); - - let (mut swapchain, images) = { - let caps = surface.capabilities(physical).unwrap(); - - let usage = caps.supported_usage_flags; - let alpha = caps.supported_composite_alpha.iter().next().unwrap(); - let format = caps.supported_formats[0].0; - - let initial_dimensions = if let Some(dimensions) = window.get_inner_size() { - // convert to physical pixels - let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into(); - [dimensions.0, dimensions.1] - } else { - // The window no longer exists so exit the application. - return; - }; - - Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, - initial_dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha, - PresentMode::Fifo, true, None).unwrap() - }; - - - #[derive(Default, Debug, Clone)] - struct Vertex { position: [f32; 2] } - vulkano::impl_vertex!(Vertex, position); - - let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter( - device.clone(), - BufferUsage::all(), - [ - Vertex { position: [-0.5, -0.5 ] }, - Vertex { position: [-0.5, 0.5 ] }, - Vertex { position: [ 0.5, -0.5 ] }, - Vertex { position: [ 0.5, 0.5 ] }, - ].iter().cloned() - ).unwrap(); - - let vs = vs::Shader::load(device.clone()).unwrap(); - let fs = fs::Shader::load(device.clone()).unwrap(); - - let render_pass = Arc::new( - vulkano::single_pass_renderpass!(device.clone(), - attachments: { - color: { - load: Clear, - store: Store, - format: swapchain.format(), - samples: 1, - } - }, - pass: { - color: [color], - depth_stencil: {} - } - ).unwrap() - ); - - let (texture, tex_future) = { - let image = image::load_from_memory_with_format(include_bytes!("image_img.png"), - ImageFormat::PNG).unwrap().to_rgba(); - let image_data = image.into_raw().clone(); - - ImmutableImage::from_iter( - image_data.iter().cloned(), - Dimensions::Dim2d { width: 93, height: 93 }, - Format::R8G8B8A8Srgb, - queue.clone() - ).unwrap() - }; - - let sampler = Sampler::new(device.clone(), Filter::Linear, Filter::Linear, - MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, - SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap(); - - let pipeline = Arc::new(GraphicsPipeline::start() - .vertex_input_single_buffer::() - .vertex_shader(vs.main_entry_point(), ()) - .triangle_strip() - .viewports_dynamic_scissors_irrelevant(1) - .fragment_shader(fs.main_entry_point(), ()) - .blend_alpha_blending() - .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) - .build(device.clone()) - .unwrap()); - - let set = Arc::new(PersistentDescriptorSet::start(pipeline.clone(), 0) - .add_sampled_image(texture.clone(), sampler.clone()).unwrap() - .build().unwrap() - ); - - let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None }; - let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state); - - let mut recreate_swapchain = false; - let mut previous_frame_end = Box::new(tex_future) as Box; - - loop { - previous_frame_end.cleanup_finished(); - if recreate_swapchain { - let dimensions = if let Some(dimensions) = window.get_inner_size() { - let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into(); - [dimensions.0, dimensions.1] - } else { - return; - }; - - let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) { - Ok(r) => r, - Err(SwapchainCreationError::UnsupportedDimensions) => continue, - Err(err) => panic!("{:?}", err) - }; - - swapchain = new_swapchain; - framebuffers = window_size_dependent_setup(&new_images, render_pass.clone(), &mut dynamic_state); - - recreate_swapchain = false; - } - - let (image_num, future) = match swapchain::acquire_next_image(swapchain.clone(), None) { - Ok(r) => r, - Err(AcquireError::OutOfDate) => { - recreate_swapchain = true; - continue; - } - Err(err) => panic!("{:?}", err) - }; - - let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into()); - - let cb = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()) - .unwrap() - .begin_render_pass(framebuffers[image_num].clone(), false, clear_values).unwrap() - .draw(pipeline.clone(), &dynamic_state, vertex_buffer.clone(), set.clone(), ()).unwrap() - .end_render_pass().unwrap() - .build().unwrap(); - - let future = previous_frame_end.join(future) - .then_execute(queue.clone(), cb).unwrap() - .then_swapchain_present(queue.clone(), swapchain.clone(), image_num) - .then_signal_fence_and_flush(); - - match future { - Ok(future) => { - previous_frame_end = Box::new(future) as Box<_>; - } - Err(FlushError::OutOfDate) => { - recreate_swapchain = true; - previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>; - } - Err(e) => { - println!("{:?}", e); - previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>; - } - } - - let mut done = false; - events_loop.poll_events(|ev| { - match ev { - Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true, - Event::WindowEvent { event: WindowEvent::Resized(_), .. } => recreate_swapchain = true, - _ => () - } - }); - if done { return; } - } -} - -/// This method is called once during initialization, then again whenever the window is resized -fn window_size_dependent_setup( - images: &[Arc>], - render_pass: Arc, - dynamic_state: &mut DynamicState -) -> Vec> { - let dimensions = images[0].dimensions(); - - let viewport = Viewport { - origin: [0.0, 0.0], - dimensions: [dimensions[0] as f32, dimensions[1] as f32], - depth_range: 0.0 .. 1.0, - }; - dynamic_state.viewports = Some(vec!(viewport)); - - images.iter().map(|image| { - Arc::new( - Framebuffer::start(render_pass.clone()) - .add(image.clone()).unwrap() - .build().unwrap() - ) as Arc - }).collect::>() -} - -mod vs { - vulkano_shaders::shader!{ - ty: "vertex", - src: " -#version 450 -layout(location = 0) in vec2 position; -layout(location = 0) out vec2 tex_coords; -void main() { - gl_Position = vec4(position, 0.0, 1.0); - tex_coords = position + vec2(0.5); -}" - } -} - -mod fs { - vulkano_shaders::shader!{ - ty: "fragment", - src: " -#version 450 -layout(location = 0) in vec2 tex_coords; -layout(location = 0) out vec4 f_color; -layout(set = 0, binding = 0) uniform sampler2D tex; -void main() { - f_color = texture(tex, tex_coords); -}" - } -} diff --git a/src/canvas/canvas_state.rs b/src/canvas/canvas_state.rs index 01b43b7d..cc2f79ff 100644 --- a/src/canvas/canvas_state.rs +++ b/src/canvas/canvas_state.rs @@ -200,7 +200,7 @@ impl CanvasState { let mut compute_path = project_root.clone(); compute_path.push(PathBuf::from("resources/images/")); - compute_path.push(PathBuf::from(image_filename)); + compute_path.push(PathBuf::from(image_filename.clone())); let img = image::open(compute_path).expect("Couldn't find image"); @@ -212,7 +212,7 @@ impl CanvasState { let mut image_buffer = Vec::new(); if pixel_count != data_length as usize { - println!("Creating apha channel..."); + println!("Creating alpha channel for {}", image_filename.clone()); for i in img.raw_pixels().iter() { if (image_buffer.len() + 1) % 4 == 0 { image_buffer.push(255); @@ -236,7 +236,6 @@ impl CanvasState { /// Load a texture using it's filename from a file. Returns the handle of the loaded texture pub fn load_texture(&mut self, filename: String) -> Option> { - let texture_buffer = self.get_texture_from_file(filename.clone()); let handle = Arc::new(CanvasTextureHandle { handle: self.texture_buffers.len() as u32 diff --git a/src/compute/compu_state.rs b/src/compute/compu_state.rs index 7f6efcc8..dcc471d1 100644 --- a/src/compute/compu_state.rs +++ b/src/compute/compu_state.rs @@ -105,13 +105,13 @@ impl CompuState { let buffer = self.compute_buffers.get(buffer_id).unwrap(); let kernel = self.kernels.get(kernel_id).unwrap(); - let p = kernel.clone().get_pipeline(); - let d = buffer.get_descriptor_set(kernel.clone().get_pipeline()); + let pipeline = kernel.clone().get_pipeline(); + let descriptorset = buffer.get_descriptor_set(kernel.clone().get_pipeline()); let size = buffer.get_size(); command_buffer = command_buffer - .dispatch([size.0 / 8, size.1 / 8, 1], p, d, ()).unwrap() + .dispatch([size.0 / 8, size.1 / 8, 1], pipeline, descriptorset, ()).unwrap() } // i = (Buffer, Image, Kernel) diff --git a/src/drawables/mod.rs b/src/drawables/mod.rs new file mode 100644 index 00000000..2b278093 --- /dev/null +++ b/src/drawables/mod.rs @@ -0,0 +1,3 @@ +pub mod polygon; +pub mod sprite; +pub mod rect; \ No newline at end of file diff --git a/src/drawables/polygon.rs b/src/drawables/polygon.rs new file mode 100644 index 00000000..dc326a12 --- /dev/null +++ b/src/drawables/polygon.rs @@ -0,0 +1,71 @@ +use std::sync::Arc; +use crate::canvas::*; +use crate::canvas::managed::handles::{CanvasFontHandle, CanvasImageHandle, CanvasTextureHandle, Handle}; +use crate::canvas::canvas_frame::{Drawable}; +use crate::util::vertex::{VertexTypes, TextureVertex3D, Vertex3D, ColorVertex3D}; +use crate::drawables::sprite::Sprite; + +/// Convex multi verticy polygon +#[derive(Debug, Clone)] +pub struct Polygon { + + pub verts: VertexTypes, + + position: (f32, f32), + size: (f32, f32), +} + +/// Container class which implements drawable. +impl Polygon { + + /// + pub fn new(position: (f32, f32), + size: (f32, f32), + depth: u32,) -> Polygon { + + let normalized_depth = (depth as f32 / 255.0); + + let verts = vec![ + ColorVertex3D{v_position: [-0.5, -0.5, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [-1.0, 1.0, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [-0.25, 0.0, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [-0.25, 0.0, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [-1.0, 1.0, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [0.0, 0.5, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [0.25, 0.0, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [-1.0, 1.0, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [0.0, 0.5, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [0.5, -0.5, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [-1.0, 1.0, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [0.25, 0.0, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [0.25, -0.5, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [-1.0, 1.0, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [0.5, -0.5, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [0.25, -0.5, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [-1.0, 1.0, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [0.0, -0.1, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [-0.25, -0.5, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [-1.0, 1.0, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [0.0, -0.1, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [-0.5, -0.5, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [-1.0, 1.0, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ColorVertex3D{v_position: [-0.25, -0.5, normalized_depth], color: [1.0, 1.0, 0.0, 1.0] }, + ]; + + + Polygon { + verts: VertexTypes::ColorType(verts), + position: position, + size: size, + } + } +} +impl Drawable for Polygon { + fn get(&self) -> VertexTypes { + self.verts.clone() + } + +} + + + diff --git a/src/drawables/rect.rs b/src/drawables/rect.rs new file mode 100644 index 00000000..d867cb00 --- /dev/null +++ b/src/drawables/rect.rs @@ -0,0 +1,57 @@ +use crate::canvas::canvas_frame::Drawable; +use crate::util::vertex::{VertexTypes, ColorVertex3D}; + +/// +#[derive(Debug, Clone)] +pub struct Rect { + + pub verts: VertexTypes, + + position: (f32, f32), + size: (f32, f32), +} + +/// Container class which implements drawable. +impl Rect { + + /// + pub fn new(position: (f32, f32), + size: (f32, f32), + depth: u32) -> Rect { + + let normalized_depth = (depth as f32 / 255.0); + + let verts = vec![ + ColorVertex3D{ + v_position: [position.0, position.1, normalized_depth], // top left + color: [0.0, 1.0, 1.0, 0.5] }, + ColorVertex3D{ + v_position: [position.0, position.1 + size.1, normalized_depth], // bottom left + color: [1.0, 1.0, 1.0, 1.0] }, + ColorVertex3D{ + v_position: [position.0 + size.0, position.1 + size.1, normalized_depth], // bottom right + color: [1.0, 1.0, 1.0, 1.0] }, + ColorVertex3D{ + v_position: [position.0, position.1, normalized_depth], // top left + color: [1.0, 1.0, 1.0, 1.0] }, + ColorVertex3D{ + v_position: [position.0 + size.0, position.1 + size.1, normalized_depth], // bottom right + color: [1.0, 1.0, 1.0, 1.0] }, + ColorVertex3D{ + v_position: [position.0 + size.0, position.1, normalized_depth], // top right + color: [1.0, 1.0, 1.0, 1.0] }, + ]; + + Rect { + verts: VertexTypes::ColorType(verts), + position: position, + size: size, + } + } +} +impl Drawable for Rect { + fn get(&self) -> VertexTypes { + self.verts.clone() + } + +} diff --git a/src/sprite.rs b/src/drawables/sprite.rs similarity index 100% rename from src/sprite.rs rename to src/drawables/sprite.rs diff --git a/src/main.rs b/src/main.rs index 12e373a1..7ecfb4b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,6 @@ use vulkano::sync::GpuFuture; use winit::{EventsLoop, WindowBuilder, WindowEvent, Event, DeviceEvent, VirtualKeyCode, ElementState}; use winit::dpi::LogicalSize; use vulkano_win::VkSurfaceBuild; -use sprite::Sprite; use crate::util::load_raw; @@ -30,34 +29,15 @@ use std::sync::Arc; use crate::canvas::managed::handles::{CanvasTextureHandle, Handle, CanvasFontHandle}; use crate::util::vertex::{VertexTypes, TextureVertex3D}; use crate::compute::managed::handles::{CompuBufferHandle, CompuKernelHandle}; - +use crate::drawables::sprite::Sprite; +use crate::drawables::rect::Rect; pub mod util; pub mod vkprocessor; -pub mod sprite; - +pub mod drawables; pub mod canvas; pub mod compute; -/* - - Trac3r : A program to convert images to 2D toolpaths - - TODO: - + Text rendering is half implemented. - + Need generalized interface for render (image, texture, text) - + Currently using local copies of a few libraries: - shade_runner - vulkano/vulkano-win - vulkano/vulkano-shaders - vulkano/vulkano - + Need to generate runtime vertex definitions if I want to have on the fly shaders - - - -*/ - - pub fn main() { hprof::start_frame(); @@ -125,8 +105,12 @@ pub fn main() { let font_handle : Arc = processor.get_font_handle(String::from("sansation.ttf")).unwrap(); - let funky_sprite = Sprite::new((0.0, -0.5), (0.5, 0.5), 0, funky_handle.clone()); + let funky_sprite = Sprite::new((0.0, 0.5), (0.5, 0.5), 0, funky_handle.clone()); let sfml_sprite = Sprite::new((0.0, -0.5), (0.5, 0.5), 1, sfml_handle.clone()); + let rect = Rect::new((-0.5, -0.5), (0.5, 0.5), 1); + + + //let sfml_sprite = Sprite::new((0.0, -0.5), (0.5, 0.5), 1, sfml_handle.clone()); //let text_sprite = Text::new((-0.1,-0.1), (10.0, 10.0), font_handle.clone()); //let test_polygon = Poly::new_with_color((-0.5, -0.5), (0.5, 0.5), 1, (1.0,0.0,0.0,0.0)); @@ -187,20 +171,15 @@ pub fn main() { break; } - - let funky_sprite = Sprite::new((0.0, -0.5), (0.5, 0.5), 0, funky_handle.clone()); - let mut canvas_frame = CanvasFrame::default(); - canvas_frame.draw(&funky_sprite); - canvas_frame.draw(&sfml_sprite); +// canvas_frame.draw(&funky_sprite); +// canvas_frame.draw(&sfml_sprite); +// canvas_frame.draw(&rect); let mut compu_frame = CompuFrame::new(); -// compu_frame.add(compute_buffer.clone(), compute_kernel.clone()); + compu_frame.add(compute_buffer.clone(), compute_kernel.clone()); // compu_frame.add_with_image_swap(compute_buffer.clone(), compute_kernel.clone(), &compu_sprite1); -// -// let mut canvas = CanvasFrame::new(); -// canvas.draw(&funky_sprite); -// canvas.draw(&test_polygon); + { let g = hprof::enter("Run"); @@ -213,7 +192,6 @@ pub fn main() { drop(l); -return; hprof::end_frame(); hprof::profiler().print_timing(); } diff --git a/src/util/mod.rs b/src/util/mod.rs index 5c4a0bf1..8aa17a2e 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -26,7 +26,7 @@ pub fn load_raw(filename: String) -> (Vec, (u32,u32)) { let mut image_buffer = Vec::new(); if pixel_count != data_length as usize { - println!("Creating apha channel..."); + println!("Creating alpha channel for {}", filename); for i in img.raw_pixels().iter() { if (image_buffer.len() + 1) % 4 == 0 { image_buffer.push(255); diff --git a/src/vkprocessor.rs b/src/vkprocessor.rs index 7ffb54da..f4f127a9 100644 --- a/src/vkprocessor.rs +++ b/src/vkprocessor.rs @@ -222,10 +222,9 @@ impl<'a> VkProcessor<'a> { self.compute_state.write_compute_buffer(handle, data) } - /// + /// Run the VKprocessor for a single frame, consuming the Canvas/Compu Frames pub fn run(&mut self, surface: &'a Arc>, - //canvas_frame: CanvasFrame, canvas_frame: CanvasFrame, compute_frame: CompuFrame, ) {