mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 08:14:20 +00:00
Add trivial tessellation example and fix building a pipeline that uses tessellation shaders (#1024)
This commit is contained in:
parent
1d6503553a
commit
7dc5de217b
297
examples/src/bin/tessellation.rs
Normal file
297
examples/src/bin/tessellation.rs
Normal file
@ -0,0 +1,297 @@
|
||||
// Copyright (c) 2016 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
||||
// 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<Vec<Arc<vulkano::framebuffer::Framebuffer<_,_>>>> = None;
|
||||
let mut recreate_swapchain = false;
|
||||
let mut previous_frame_end = Box::new(now(device.clone())) as Box<GpuFuture>;
|
||||
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::<Vec<_>>());
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
@ -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.
|
||||
///
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -499,7 +499,7 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
|
||||
};
|
||||
|
||||
match tess.tessellation_evaluation_shader.0.ty() {
|
||||
GraphicsShaderType::TessellationControl => {},
|
||||
GraphicsShaderType::TessellationEvaluation => {},
|
||||
_ => return Err(GraphicsPipelineCreationError::WrongShaderType),
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user