From 7dc5de217bd1d29c0c3fb74e151728a7af33d634 Mon Sep 17 00:00:00 2001 From: Lucas Kent Date: Fri, 24 Aug 2018 20:01:00 +1000 Subject: [PATCH] Add trivial tessellation example and fix building a pipeline that uses tessellation shaders (#1024) --- examples/src/bin/tessellation.rs | 297 ++++++++++++++++++ vulkano/src/buffer/usage.rs | 2 +- vulkano/src/image/usage.rs | 2 +- .../src/pipeline/graphics_pipeline/builder.rs | 2 +- 4 files changed, 300 insertions(+), 3 deletions(-) create mode 100644 examples/src/bin/tessellation.rs diff --git a/examples/src/bin/tessellation.rs b/examples/src/bin/tessellation.rs new file mode 100644 index 00000000..4c5ab619 --- /dev/null +++ b/examples/src/bin/tessellation.rs @@ -0,0 +1,297 @@ +// 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. + +// TODO +// This example doesnt work yet! +// Maybe it's an issue with the example maybe it's an issue with vulkano. +// I checked it in so we can use it to test the issue. +// Delete this comment when the example is working + +#[macro_use] +extern crate vulkano; +#[macro_use] +extern crate vulkano_shader_derive; +extern crate winit; +extern crate vulkano_win; + +use vulkano_win::VkSurfaceBuild; + +use vulkano::buffer::BufferUsage; +use vulkano::buffer::CpuAccessibleBuffer; +use vulkano::command_buffer::AutoCommandBufferBuilder; +use vulkano::command_buffer::DynamicState; +use vulkano::device::Device; +use vulkano::framebuffer::Framebuffer; +use vulkano::framebuffer::Subpass; +use vulkano::instance::Instance; +use vulkano::pipeline::GraphicsPipeline; +use vulkano::pipeline::viewport::Viewport; +use vulkano::swapchain; +use vulkano::swapchain::PresentMode; +use vulkano::swapchain::SurfaceTransform; +use vulkano::swapchain::Swapchain; +use vulkano::swapchain::AcquireError; +use vulkano::swapchain::SwapchainCreationError; +use vulkano::sync::now; +use vulkano::sync::GpuFuture; + +use std::sync::Arc; + +fn main() { + let instance = { + let extensions = vulkano_win::required_extensions(); + Instance::new(None, &extensions, None).expect("failed to create Vulkan instance") + }; + + let physical = vulkano::instance::PhysicalDevice::enumerate(&instance) + .next().expect("no device available"); + println!("Using device: {} (type: {:?})", physical.name(), physical.ty()); + + let mut events_loop = winit::EventsLoop::new(); + let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap(); + + let queue = physical.queue_families().find(|&q| { + q.supports_graphics() && surface.is_supported(q).unwrap_or(false) + }).expect("couldn't find a graphical queue family"); + let (device, mut queues) = { + let device_ext = vulkano::device::DeviceExtensions { + khr_swapchain: true, + .. vulkano::device::DeviceExtensions::none() + }; + + Device::new(physical, physical.supported_features(), &device_ext, + [(queue, 0.5)].iter().cloned()).expect("failed to create device") + }; + let queue = queues.next().unwrap(); + + let mut dimensions; + + let (mut swapchain, mut images) = { + let caps = surface.capabilities(physical) + .expect("failed to get surface capabilities"); + + dimensions = caps.current_extent.unwrap_or([1024, 768]); + let alpha = caps.supported_composite_alpha.iter().next().unwrap(); + let format = caps.supported_formats[0].0; + + Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, + dimensions, 1, caps.supported_usage_flags, &queue, + SurfaceTransform::Identity, alpha, PresentMode::Fifo, true, + None).expect("failed to create swapchain") + }; + + let vertex_buffer = { + #[derive(Debug, Clone)] + struct Vertex { position: [f32; 2] } + 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] }, + Vertex { position: [0.25, -0.5] }, + ].iter().cloned()).expect("failed to create buffer") + }; + + mod vs { + #[derive(VulkanoShader)] + #[ty = "vertex"] + #[src = " +#version 450 + +layout(location = 0) in vec2 position; + +void main() { + gl_Position = vec4(position, 0.0, 1.0); +} +"] + #[allow(dead_code)] + struct Dummy; + } + + mod fs { + #[derive(VulkanoShader)] + #[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); +} +"] + #[allow(dead_code)] + struct Dummy; + } + + mod tcs { + #[derive(VulkanoShader)] + #[ty = "tess_ctrl"] + #[src = " +#version 450 + +layout (vertices = 3) out; + +void main(void) +{ + gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; +} + "] + #[allow(dead_code)] + struct Dummy; + } + + mod tes { + #[derive(VulkanoShader)] + #[ty = "tess_eval"] + #[src = " +#version 450 + +layout(quads, equal_spacing, cw) in; + +void main(void) +{ + gl_Position = gl_in[0].gl_Position; +} + "] + #[allow(dead_code)] + struct Dummy; + } + + let vs = vs::Shader::load(device.clone()).expect("failed to create shader module"); + let fs = fs::Shader::load(device.clone()).expect("failed to create shader module"); + let tcs = tcs::Shader::load(device.clone()).expect("failed to create shader module"); + let tes = tes::Shader::load(device.clone()).expect("failed to create shader module"); + + let render_pass = Arc::new(single_pass_renderpass!(device.clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: swapchain.format(), + samples: 1, + } + }, + pass: { + color: [color], + depth_stencil: {} + } + ).unwrap()); + + let pipeline = Arc::new(GraphicsPipeline::start() + .vertex_input_single_buffer() + .vertex_shader(vs.main_entry_point(), ()) + .tessellation_shaders(tcs.main_entry_point(), (), tes.main_entry_point(), ()) + .patch_list(4) + .viewports_dynamic_scissors_irrelevant(1) + .fragment_shader(fs.main_entry_point(), ()) + .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) + .build(device.clone()) + .unwrap()); + + let mut framebuffers: Option>>> = None; + let mut recreate_swapchain = false; + let mut previous_frame_end = Box::new(now(device.clone())) as Box; + let mut dynamic_state = DynamicState { + line_width: None, + viewports: Some(vec![Viewport { + origin: [0.0, 0.0], + dimensions: [dimensions[0] as f32, dimensions[1] as f32], + depth_range: 0.0 .. 1.0, + }]), + scissors: None, + }; + + loop { + previous_frame_end.cleanup_finished(); + if recreate_swapchain { + dimensions = surface.capabilities(physical) + .expect("failed to get surface capabilities") + .current_extent.unwrap(); + + 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; + images = new_images; + framebuffers = None; + dynamic_state.viewports = Some(vec![Viewport { + origin: [0.0, 0.0], + dimensions: [dimensions[0] as f32, dimensions[1] as f32], + depth_range: 0.0 .. 1.0, + }]); + + recreate_swapchain = false; + } + + if framebuffers.is_none() { + framebuffers = Some(images.iter().map(|image| { + Arc::new(Framebuffer::start(render_pass.clone()) + .add(image.clone()).unwrap() + .build().unwrap()) + }).collect::>()); + } + + 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) + }; + + let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap() + .begin_render_pass(framebuffers.as_ref().unwrap()[image_num].clone(), false, + vec![[0.0, 0.0, 1.0, 1.0].into()]) + .unwrap() + .draw(pipeline.clone(), + &dynamic_state, + vertex_buffer.clone(), (), ()) + .unwrap() + .end_render_pass() + .unwrap() + .build().unwrap(); + + let future = previous_frame_end.join(acquire_future) + .then_execute(queue.clone(), command_buffer).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(vulkano::sync::FlushError::OutOfDate) => { + recreate_swapchain = true; + previous_frame_end = Box::new(vulkano::sync::now(device.clone())) as Box<_>; + } + Err(e) => { + println!("{:?}", e); + previous_frame_end = Box::new(vulkano::sync::now(device.clone())) as Box<_>; + } + } + + let mut done = false; + events_loop.poll_events(|ev| { + match ev { + winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true, + _ => () + } + }); + if done { return } + } +} diff --git a/vulkano/src/buffer/usage.rs b/vulkano/src/buffer/usage.rs index e4eb99db..1db4a809 100644 --- a/vulkano/src/buffer/usage.rs +++ b/vulkano/src/buffer/usage.rs @@ -10,7 +10,7 @@ use std::ops::BitOr; use vk; -/// Describes how a buffer is going to be used. This is **not** an optimization. +/// Describes how a buffer is going to be used. This is **not** just an optimization. /// /// If you try to use a buffer in a way that you didn't declare, a panic will happen. /// diff --git a/vulkano/src/image/usage.rs b/vulkano/src/image/usage.rs index 668993fc..ca471851 100644 --- a/vulkano/src/image/usage.rs +++ b/vulkano/src/image/usage.rs @@ -10,7 +10,7 @@ use std::ops::BitOr; use vk; -/// Describes how an image is going to be used. This is **not** an optimization. +/// Describes how an image is going to be used. This is **not** just an optimization. /// /// If you try to use an image in a way that you didn't declare, a panic will happen. /// diff --git a/vulkano/src/pipeline/graphics_pipeline/builder.rs b/vulkano/src/pipeline/graphics_pipeline/builder.rs index 1ff235f8..7fae5010 100644 --- a/vulkano/src/pipeline/graphics_pipeline/builder.rs +++ b/vulkano/src/pipeline/graphics_pipeline/builder.rs @@ -499,7 +499,7 @@ impl }; match tess.tessellation_evaluation_shader.0.ty() { - GraphicsShaderType::TessellationControl => {}, + GraphicsShaderType::TessellationEvaluation => {}, _ => return Err(GraphicsPipelineCreationError::WrongShaderType), };