Advertisement
Guest User

Untitled

a guest
Jan 19th, 2018
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 23.29 KB | None | 0 0
  1. // Copyright (c) 2016 The vulkano developers
  2. // Licensed under the Apache License, Version 2.0
  3. // <LICENSE-APACHE or
  4. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT
  5. // license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
  6. // at your option. All files in the project carrying such
  7. // notice may not be copied, modified, or distributed except
  8. // according to those terms.
  9.  
  10.  
  11. // Welcome to the triangle example!
  12. //
  13. // This is the only example that is entirely detailed. All the other examples avoid code
  14. // duplication by using helper functions.
  15. //
  16. // This example assumes that you are already more or less familiar with graphics programming
  17. // and that you want to learn Vulkan. This means that for example it won't go into details about
  18. // what a vertex or a shader is.
  19.  
  20. // For the purpose of this example all unused code is allowed.
  21. #![allow(dead_code)]
  22.  
  23. // The `vulkano` crate is the main crate that you must use to use Vulkan.
  24. #[macro_use]
  25. extern crate vulkano;
  26. // The `vulkano_shader_derive` crate allows us to use the `VulkanoShader` custom derive that we use
  27. // in this example.
  28. #[macro_use]
  29. extern crate vulkano_shader_derive;
  30. // However the Vulkan library doesn't provide any functionality to create and handle windows, as
  31. // this would be out of scope. In order to open a window, we are going to use the `winit` crate.
  32. extern crate winit;
  33. // The `vulkano_win` crate is the link between `vulkano` and `winit`. Vulkano doesn't know about
  34. // winit, and winit doesn't know about vulkano, so import a crate that will provide a link between
  35. // the two.
  36. extern crate vulkano_win;
  37.  
  38. use vulkano_win::VkSurfaceBuild;
  39.  
  40. use vulkano::buffer::BufferUsage;
  41. use vulkano::buffer::CpuAccessibleBuffer;
  42. use vulkano::command_buffer::AutoCommandBufferBuilder;
  43. use vulkano::command_buffer::DynamicState;
  44. use vulkano::device::Device;
  45. use vulkano::framebuffer::Framebuffer;
  46. use vulkano::framebuffer::Subpass;
  47. use vulkano::instance::Instance;
  48. use vulkano::pipeline::GraphicsPipeline;
  49. use vulkano::pipeline::viewport::Viewport;
  50. use vulkano::swapchain;
  51. use vulkano::swapchain::PresentMode;
  52. use vulkano::swapchain::SurfaceTransform;
  53. use vulkano::swapchain::Swapchain;
  54. use vulkano::swapchain::AcquireError;
  55. use vulkano::swapchain::SwapchainCreationError;
  56. use vulkano::sync::now;
  57. use vulkano::sync::GpuFuture;
  58.  
  59. use vulkano::image::{AttachmentImage, ImageAccess};
  60. use vulkano::format::{Format, ClearValue};
  61.  
  62. use std::iter;
  63. use std::sync::Arc;
  64. use std::mem;
  65.  
  66. fn main() {
  67.     // The first step of any vulkan program is to create an instance.
  68.     let instance = {
  69.         // When we create an instance, we have to pass a list of extensions that we want to enable.
  70.         //
  71.         // All the window-drawing functionalities are part of non-core extensions that we need
  72.         // to enable manually. To do so, we ask the `vulkano_win` crate for the list of extensions
  73.         // required to draw to a window.
  74.         let extensions = vulkano_win::required_extensions();
  75.  
  76.         // Now creating the instance.
  77.         Instance::new(None, &extensions, None).expect("failed to create Vulkan instance")
  78.     };
  79.  
  80.     // We then choose which physical device to use.
  81.     //
  82.     // In a real application, there are three things to take into consideration:
  83.     //
  84.     // - Some devices may not support some of the optional features that may be required by your
  85.     //   application. You should filter out the devices that don't support your app.
  86.     //
  87.     // - Not all devices can draw to a certain surface. Once you create your window, you have to
  88.     //   choose a device that is capable of drawing to it.
  89.     //
  90.     // - You probably want to leave the choice between the remaining devices to the user.
  91.     //
  92.     // For the sake of the example we are just going to use the first device, which should work
  93.     // most of the time.
  94.     let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
  95.                             .next().expect("no device available");
  96.     // Some little debug infos.
  97.     println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
  98.  
  99.  
  100.     // The objective of this example is to draw a triangle on a window. To do so, we first need to
  101.     // create the window.
  102.     //
  103.     // This is done by creating a `WindowBuilder` from the `winit` crate, then calling the
  104.     // `build_vk_surface` method provided by the `VkSurfaceBuild` trait from `vulkano_win`. If you
  105.     // ever get an error about `build_vk_surface` being undefined in one of your projects, this
  106.     // probably means that you forgot to import this trait.
  107.     //
  108.     // This returns a `vulkano_win::Window` object that contains both a cross-platform winit
  109.     // window and a cross-platform Vulkan surface that represents the surface of the window.
  110.     let mut events_loop = winit::EventsLoop::new();
  111.     let window = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
  112.    
  113.     // The next step is to choose which GPU queue will execute our draw commands.
  114.     //
  115.     // Devices can provide multiple queues to run commands in parallel (for example a draw queue
  116.     // and a compute queue), similar to CPU threads. This is something you have to have to manage
  117.     // manually in Vulkan.
  118.     //
  119.     // In a real-life application, we would probably use at least a graphics queue and a transfers
  120.     // queue to handle data transfers in parallel. In this example we only use one queue.
  121.     //
  122.     // We have to choose which queues to use early on, because we will need this info very soon.
  123.     let queue = physical.queue_families().find(|&q| {
  124.         // We take the first queue that supports drawing to our window.
  125.         q.supports_graphics() && window.surface().is_supported(q).unwrap_or(false)
  126.     }).expect("couldn't find a graphical queue family");
  127.  
  128.     // Now initializing the device. This is probably the most important object of Vulkan.
  129.     //
  130.     // We have to pass five parameters when creating a device:
  131.     //
  132.     // - Which physical device to connect to.
  133.     //
  134.     // - A list of optional features and extensions that our program needs to work correctly.
  135.     //   Some parts of the Vulkan specs are optional and must be enabled manually at device
  136.     //   creation. In this example the only thing we are going to need is the `khr_swapchain`
  137.     //   extension that allows us to draw to a window.
  138.     //
  139.     // - A list of layers to enable. This is very niche, and you will usually pass `None`.
  140.     //
  141.     // - The list of queues that we are going to use. The exact parameter is an iterator whose
  142.     //   items are `(Queue, f32)` where the floating-point represents the priority of the queue
  143.     //   between 0.0 and 1.0. The priority of the queue is a hint to the implementation about how
  144.     //   much it should prioritize queues between one another.
  145.     //
  146.     // The list of created queues is returned by the function alongside with the device.
  147.     let (device, mut queues) = {
  148.         let device_ext = vulkano::device::DeviceExtensions {
  149.             khr_swapchain: true,
  150.             .. vulkano::device::DeviceExtensions::none()
  151.         };
  152.  
  153.         Device::new(physical, physical.supported_features(), &device_ext,
  154.                     [(queue, 0.5)].iter().cloned()).expect("failed to create device")
  155.     };
  156.  
  157.     // Since we can request multiple queues, the `queues` variable is in fact an iterator. In this
  158.     // example we use only one queue, so we just retreive the first and only element of the
  159.     // iterator and throw it away.
  160.     let queue = queues.next().unwrap();
  161.  
  162.     // The dimensions of the surface.
  163.     // This variable needs to be mutable since the viewport can change size.
  164.     let mut dimensions;
  165.  
  166.     // Before we can draw on the surface, we have to create what is called a swapchain. Creating
  167.     // a swapchain allocates the color buffers that will contain the image that will ultimately
  168.     // be visible on the screen. These images are returned alongside with the swapchain.
  169.     let (mut swapchain, mut images) = {
  170.         // Querying the capabilities of the surface. When we create the swapchain we can only
  171.         // pass values that are allowed by the capabilities.
  172.         let caps = window.surface().capabilities(physical)
  173.                          .expect("failed to get surface capabilities");
  174.        
  175.         dimensions = caps.current_extent.unwrap_or([1024, 768]);
  176.  
  177.         // We choose the dimensions of the swapchain to match the current extent of the surface.
  178.         // If `caps.current_extent` is `None`, this means that the window size will be determined
  179.         // by the dimensions of the swapchain, in which case we just use the width and height defined above.
  180.  
  181.         // The alpha mode indicates how the alpha value of the final image will behave. For example
  182.         // you can choose whether the window will be opaque or transparent.
  183.         let alpha = caps.supported_composite_alpha.iter().next().unwrap();
  184.  
  185.         // Choosing the internal format that the images will have.
  186.         let format = caps.supported_formats[0].0;
  187.  
  188.         // Please take a look at the docs for the meaning of the parameters we didn't mention.
  189.         Swapchain::new(device.clone(), window.surface().clone(), caps.min_image_count, format,
  190.                        dimensions, 1, caps.supported_usage_flags, &queue,
  191.                        SurfaceTransform::Identity, alpha, PresentMode::Fifo, true,
  192.                        None).expect("failed to create swapchain")
  193.     };
  194.  
  195.     // We now create a buffer that will store the shape of our triangle.
  196.     let vertex_buffer = {
  197.         #[derive(Debug, Clone)]
  198.         struct Vertex { position: [f32; 2] }
  199.         impl_vertex!(Vertex, position);
  200.  
  201.         CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), [
  202.             Vertex { position: [-0.5, -0.25] },
  203.             Vertex { position: [0.0, 0.5] },
  204.             Vertex { position: [0.25, -0.1] }
  205.         ].iter().cloned()).expect("failed to create buffer")
  206.     };
  207.  
  208.     // The next step is to create the shaders.
  209.     //
  210.     // The raw shader creation API provided by the vulkano library is unsafe, for various reasons.
  211.     //
  212.     // TODO: explain this in details
  213.     mod vs {
  214.         #[derive(VulkanoShader)]
  215.         #[ty = "vertex"]
  216.         #[src = "
  217. #version 450
  218.  
  219. layout(location = 0) in vec2 position;
  220.  
  221. void main() {
  222.    gl_Position = vec4(position, 0.0, 1.0);
  223. }
  224. "]
  225.         struct Dummy;
  226.     }
  227.  
  228.     mod fs {
  229.         #[derive(VulkanoShader)]
  230.         #[ty = "fragment"]
  231.         #[src = "
  232. #version 450
  233.  
  234. layout(location = 0) out vec4 f_color;
  235.  
  236. void main() {
  237.    f_color = vec4(1.0, 0.0, 0.0, 1.0);
  238. }
  239. "]
  240.         struct Dummy;
  241.     }
  242.  
  243.     let vs = vs::Shader::load(device.clone()).expect("failed to create shader module");
  244.     let fs = fs::Shader::load(device.clone()).expect("failed to create shader module");
  245.  
  246.     // At this point, OpenGL initialization would be finished. However in Vulkan it is not. OpenGL
  247.     // implicitely does a lot of computation whenever you draw. In Vulkan, you have to do all this
  248.     // manually.
  249.  
  250.     // The next step is to create a *render pass*, which is an object that describes where the
  251.     // output of the graphics pipeline will go. It describes the layout of the images
  252.     // where the colors, depth and/or stencil information will be written.
  253.     let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
  254.         attachments: {
  255.             multisample_color: {
  256.                 load: Clear,
  257.                 store: DontCare,
  258.                 format: swapchain.format(),
  259.                 samples: 8,
  260.             },
  261.             multisampled_depth: {
  262.                 load:    Clear,
  263.                 store:   DontCare,
  264.                 format:  Format::D16Unorm,
  265.                 samples: 8,
  266.             },
  267.             resolve_color: {
  268.                 load: DontCare,
  269.                 store: Store,
  270.                 format: swapchain.format(),
  271.                 samples: 1,
  272.             },
  273.             resolve_depth: {
  274.                 load:    DontCare,
  275.                 store:   Store,
  276.                 format:  Format::D16Unorm,
  277.                 samples: 1,
  278.                 initial_layout: ImageLayout::Undefined,
  279.                 final_layout: ImageLayout::DepthStencilAttachmentOptimal,
  280.             }
  281.         },
  282.         pass: {
  283.             color: [multisample_color],
  284.             depth_stencil: {multisampled_depth},
  285.             resolve: [resolve_color],
  286.         }
  287.     ).unwrap());
  288.  
  289.     // Before we draw we have to create what is called a pipeline. This is similar to an OpenGL
  290.     // program, but much more specific.
  291.     let pipeline = Arc::new(GraphicsPipeline::start()
  292.         // We need to indicate the layout of the vertices.
  293.         // The type `SingleBufferDefinition` actually contains a template parameter corresponding
  294.         // to the type of each vertex. But in this code it is automatically inferred.
  295.         .vertex_input_single_buffer()
  296.         // A Vulkan shader can in theory contain multiple entry points, so we have to specify
  297.         // which one. The `main` word of `main_entry_point` actually corresponds to the name of
  298.         // the entry point.
  299.         .vertex_shader(vs.main_entry_point(), ())
  300.         // The content of the vertex buffer describes a list of triangles.
  301.         .triangle_list()
  302.         // Use a resizable viewport set to draw over the entire window
  303.         .viewports_dynamic_scissors_irrelevant(1)
  304.         // See `vertex_shader`.
  305.         .fragment_shader(fs.main_entry_point(), ())
  306.         // We have to indicate which subpass of which render pass this pipeline is going to be used
  307.         // in. The pipeline will only be usable from this particular subpass.
  308.         .render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
  309.         // Now that our builder is filled, we call `build()` to obtain an actual pipeline.
  310.         .build(device.clone())
  311.         .unwrap());
  312.  
  313.     // The render pass we created above only describes the layout of our framebuffers. Before we
  314.     // can draw we also need to create the actual framebuffers.
  315.     //
  316.     // Since we need to draw to multiple images, we are going to create a different framebuffer for
  317.     // each image.
  318.     let mut framebuffers: Option<Vec<Arc<vulkano::framebuffer::Framebuffer<_,_>>>> = None;
  319.  
  320.     // Initialization is finally finished!
  321.  
  322.     // In some situations, the swapchain will become invalid by itself. This includes for example
  323.     // when the window is resized (as the images of the swapchain will no longer match the
  324.     // window's) or, on Android, when the application went to the background and goes back to the
  325.     // foreground.
  326.     //
  327.     // In this situation, acquiring a swapchain image or presenting it will return an error.
  328.     // Rendering to an image of that swapchain will not produce any error, but may or may not work.
  329.     // To continue rendering, we need to recreate the swapchain by creating a new swapchain.
  330.     // Here, we remember that we need to do this for the next loop iteration.
  331.     let mut recreate_swapchain = false;
  332.  
  333.     // In the loop below we are going to submit commands to the GPU. Submitting a command produces
  334.     // an object that implements the `GpuFuture` trait, which holds the resources for as long as
  335.     // they are in use by the GPU.
  336.     //
  337.     // Destroying the `GpuFuture` blocks until the GPU is finished executing it. In order to avoid
  338.     // that, we store the submission of the previous frame here.
  339.     let mut previous_frame_end = Box::new(now(device.clone())) as Box<GpuFuture>;
  340.  
  341.     loop {
  342.         // It is important to call this function from time to time, otherwise resources will keep
  343.         // accumulating and you will eventually reach an out of memory error.
  344.         // Calling this function polls various fences in order to determine what the GPU has
  345.         // already processed, and frees the resources that are no longer needed.
  346.         previous_frame_end.cleanup_finished();
  347.  
  348.         // If the swapchain needs to be recreated, recreate it
  349.         if recreate_swapchain {
  350.             // Get the new dimensions for the viewport/framebuffers.
  351.             dimensions = window.surface().capabilities(physical)
  352.                         .expect("failed to get surface capabilities")
  353.                         .current_extent.unwrap();
  354.            
  355.             let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
  356.                 Ok(r) => r,
  357.                 // This error tends to happen when the user is manually resizing the window.
  358.                 // Simply restarting the loop is the easiest way to fix this issue.
  359.                 Err(SwapchainCreationError::UnsupportedDimensions) => {
  360.                     continue;
  361.                 },
  362.                 Err(err) => panic!("{:?}", err)
  363.             };
  364.  
  365.             mem::replace(&mut swapchain, new_swapchain);
  366.             mem::replace(&mut images, new_images);
  367.  
  368.             framebuffers = None;
  369.  
  370.             recreate_swapchain = false;
  371.         }
  372.  
  373.         // Because framebuffers contains an Arc on the old swapchain, we need to
  374.         // recreate framebuffers as well.
  375.         if framebuffers.is_none() {
  376.             let new_framebuffers = Some(images.iter().map(|image| {
  377.                 let dim = image.dimensions().width_height();
  378.                 let multisample_image = AttachmentImage::transient_multisampled(device.clone(), dim, 8, image.format()).unwrap();
  379.                 let multisample_depth = AttachmentImage::transient_multisampled(device.clone(), dim, 8, Format::D16Unorm).unwrap();
  380.                 let depth = AttachmentImage::transient(device.clone(), dim, Format::D16Unorm).unwrap();
  381.                 Arc::new(Framebuffer::start(render_pass.clone())
  382.                          .add(multisample_image.clone()).unwrap()
  383.                          .add(multisample_depth.clone()).unwrap()
  384.                          .add(image.clone()).unwrap()
  385.                          .add(depth.clone()).unwrap()
  386.                          .build().unwrap())
  387.             }).collect::<Vec<_>>());
  388.             mem::replace(&mut framebuffers, new_framebuffers);
  389.         }
  390.  
  391.         // Before we can draw on the output, we have to *acquire* an image from the swapchain. If
  392.         // no image is available (which happens if you submit draw commands too quickly), then the
  393.         // function will block.
  394.         // This operation returns the index of the image that we are allowed to draw upon.
  395.         //
  396.         // This function can block if no image is available. The parameter is an optional timeout
  397.         // after which the function call will return an error.
  398.         let (image_num, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(),
  399.                                                                               None) {
  400.             Ok(r) => r,
  401.             Err(AcquireError::OutOfDate) => {
  402.                 recreate_swapchain = true;
  403.                 continue;
  404.             },
  405.             Err(err) => panic!("{:?}", err)
  406.         };
  407.  
  408.         // In order to draw, we have to build a *command buffer*. The command buffer object holds
  409.         // the list of commands that are going to be executed.
  410.         //
  411.         // Building a command buffer is an expensive operation (usually a few hundred
  412.         // microseconds), but it is known to be a hot path in the driver and is expected to be
  413.         // optimized.
  414.         //
  415.         // Note that we have to pass a queue family when we create the command buffer. The command
  416.         // buffer will only be executable on that given queue family.
  417.         let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
  418.             // Before we can draw, we have to *enter a render pass*. There are two methods to do
  419.             // this: `draw_inline` and `draw_secondary`. The latter is a bit more advanced and is
  420.             // not covered here.
  421.             //
  422.             // The third parameter builds the list of values to clear the attachments with. The API
  423.             // is similar to the list of attachments when building the framebuffers, except that
  424.             // only the attachments that use `load: Clear` appear in the list.
  425.             .begin_render_pass(framebuffers.as_ref().unwrap()[image_num].clone(), false,
  426.                                vec![[0.0, 0.0, 1.0, 1.0].into(), 1f32.into(), ClearValue::None, ClearValue::None])
  427.             .unwrap()
  428.  
  429.             // We are now inside the first subpass of the render pass. We add a draw command.
  430.             //
  431.             // The last two parameters contain the list of resources to pass to the shaders.
  432.             // Since we used an `EmptyPipeline` object, the objects have to be `()`.
  433.             .draw(pipeline.clone(),
  434.                   DynamicState {
  435.                       line_width: None,
  436.                       // TODO: Find a way to do this without having to dynamically allocate a Vec every frame.
  437.                       viewports: Some(vec![Viewport {
  438.                           origin: [0.0, 0.0],
  439.                           dimensions: [dimensions[0] as f32, dimensions[1] as f32],
  440.                           depth_range: 0.0 .. 1.0,
  441.                       }]),
  442.                       scissors: None,
  443.                   },
  444.                   vertex_buffer.clone(), (), ())
  445.             .unwrap()
  446.  
  447.             // We leave the render pass by calling `draw_end`. Note that if we had multiple
  448.             // subpasses we could have called `next_inline` (or `next_secondary`) to jump to the
  449.             // next subpass.
  450.             .end_render_pass()
  451.             .unwrap()
  452.  
  453.             // Finish building the command buffer by calling `build`.
  454.             .build().unwrap();
  455.  
  456.         let future = previous_frame_end.join(acquire_future)
  457.             .then_execute(queue.clone(), command_buffer).unwrap()
  458.  
  459.             // The color output is now expected to contain our triangle. But in order to show it on
  460.             // the screen, we have to *present* the image by calling `present`.
  461.             //
  462.             // This function does not actually present the image immediately. Instead it submits a
  463.             // present command at the end of the queue. This means that it will only be presented once
  464.             // the GPU has finished executing the command buffer that draws the triangle.
  465.             .then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
  466.             .then_signal_fence_and_flush().unwrap();
  467.         previous_frame_end = Box::new(future) as Box<_>;
  468.  
  469.         // Note that in more complex programs it is likely that one of `acquire_next_image`,
  470.         // `command_buffer::submit`, or `present` will block for some time. This happens when the
  471.         // GPU's queue is full and the driver has to wait until the GPU finished some work.
  472.         //
  473.         // Unfortunately the Vulkan API doesn't provide any way to not wait or to detect when a
  474.         // wait would happen. Blocking may be the desired behavior, but if you don't want to
  475.         // block you should spawn a separate thread dedicated to submissions.
  476.  
  477.         // Handling the window events in order to close the program when the user wants to close
  478.         // it.
  479.         let mut done = false;
  480.         events_loop.poll_events(|ev| {
  481.             match ev {
  482.                 winit::Event::WindowEvent { event: winit::WindowEvent::Closed, .. } => done = true,
  483.                 _ => ()
  484.             }
  485.         });
  486.         if done { return; }
  487.     }
  488. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement