| // Copyright (c) 2016 The vulkano developers |
| // Licensed under the Apache License, Version 2.0 |
| // <LICENSE-APACHE or |
| // https://www.apache.org/licenses/LICENSE-2.0> or the MIT |
| // license <LICENSE-MIT or https://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. |
| |
| //! This module contains the unit tests of `GraphicsPipeline`. |
| |
| #![cfg(test)] |
| |
| use format::Format; |
| use framebuffer::Subpass; |
| use pipeline::blend::Blend; |
| use pipeline::depth_stencil::DepthStencil; |
| use pipeline::input_assembly::InputAssembly; |
| use pipeline::input_assembly::PrimitiveTopology; |
| use pipeline::layout::PipelineLayoutDesc; |
| use pipeline::multisample::Multisample; |
| use pipeline::shader::ShaderInterface; |
| use pipeline::shader::ShaderModule; |
| use pipeline::vertex::SingleBufferDefinition; |
| use pipeline::viewport::ViewportsState; |
| use pipeline::GraphicsPipeline; |
| use pipeline::GraphicsPipelineCreationError; |
| use pipeline::GraphicsPipelineParams; |
| use std::ffi::CString; |
| |
| #[test] |
| fn create() { |
| let (device, _) = gfx_dev_and_queue!(); |
| |
| let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() }; |
| let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() }; |
| |
| let _ = GraphicsPipeline::new( |
| &device, |
| GraphicsPipelineParams { |
| vertex_input: SingleBufferDefinition::<()>::new(), |
| vertex_shader: unsafe { |
| vs.vertex_shader_entry_point::<(), _, _, _>( |
| &CString::new("main").unwrap(), |
| ShaderInterface::empty(), |
| ShaderInterface::empty(), |
| PipelineLayoutDesc::empty(), |
| ) |
| }, |
| input_assembly: InputAssembly::triangle_list(), |
| tessellation: None, |
| geometry_shader: None, |
| viewport: ViewportsState::Dynamic { num: 1 }, |
| raster: Default::default(), |
| multisample: Multisample::disabled(), |
| fragment_shader: unsafe { |
| fs.fragment_shader_entry_point::<(), _, _, _>( |
| &CString::new("main").unwrap(), |
| ShaderInterface::empty(), |
| ShaderInterface::empty(), |
| PipelineLayoutDesc::empty(), |
| ) |
| }, |
| depth_stencil: DepthStencil::disabled(), |
| blend: Blend::pass_through(), |
| render_pass: Subpass::from( |
| simple_rp::CustomRenderPass::new(&device, &{ |
| simple_rp::Formats { |
| color: (Format::R8G8B8A8Unorm, 1), |
| } |
| }) |
| .unwrap(), |
| 0, |
| ) |
| .unwrap(), |
| }, |
| ) |
| .unwrap(); |
| } |
| |
| #[test] |
| fn bad_primitive_restart() { |
| let (device, _) = gfx_dev_and_queue!(); |
| |
| let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() }; |
| let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() }; |
| |
| let result = GraphicsPipeline::new( |
| &device, |
| GraphicsPipelineParams { |
| vertex_input: SingleBufferDefinition::<()>::new(), |
| vertex_shader: unsafe { |
| vs.vertex_shader_entry_point::<(), _, _, _>( |
| &CString::new("main").unwrap(), |
| ShaderInterface::empty(), |
| ShaderInterface::empty(), |
| PipelineLayoutDesc::empty(), |
| ) |
| }, |
| input_assembly: InputAssembly { |
| topology: PrimitiveTopology::TriangleList, |
| primitive_restart_enable: true, |
| }, |
| tessellation: None, |
| geometry_shader: None, |
| viewport: ViewportsState::Dynamic { num: 1 }, |
| raster: Default::default(), |
| multisample: Multisample::disabled(), |
| fragment_shader: unsafe { |
| fs.fragment_shader_entry_point::<(), _, _, _>( |
| &CString::new("main").unwrap(), |
| ShaderInterface::empty(), |
| ShaderInterface::empty(), |
| PipelineLayoutDesc::empty(), |
| ) |
| }, |
| depth_stencil: DepthStencil::disabled(), |
| blend: Blend::pass_through(), |
| render_pass: Subpass::from( |
| simple_rp::CustomRenderPass::new(&device, &{ |
| simple_rp::Formats { |
| color: (Format::R8G8B8A8Unorm, 1), |
| } |
| }) |
| .unwrap(), |
| 0, |
| ) |
| .unwrap(), |
| }, |
| ); |
| |
| match result { |
| Err(GraphicsPipelineCreationError::PrimitiveDoesntSupportPrimitiveRestart { .. }) => (), |
| _ => panic!(), |
| } |
| } |
| |
| #[test] |
| fn multi_viewport_feature() { |
| let (device, _) = gfx_dev_and_queue!(); |
| |
| let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() }; |
| let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() }; |
| |
| let result = GraphicsPipeline::new( |
| &device, |
| GraphicsPipelineParams { |
| vertex_input: SingleBufferDefinition::<()>::new(), |
| vertex_shader: unsafe { |
| vs.vertex_shader_entry_point::<(), _, _, _>( |
| &CString::new("main").unwrap(), |
| ShaderInterface::empty(), |
| ShaderInterface::empty(), |
| PipelineLayoutDesc::empty(), |
| ) |
| }, |
| input_assembly: InputAssembly::triangle_list(), |
| tessellation: None, |
| geometry_shader: None, |
| viewport: ViewportsState::Dynamic { num: 2 }, |
| raster: Default::default(), |
| multisample: Multisample::disabled(), |
| fragment_shader: unsafe { |
| fs.fragment_shader_entry_point::<(), _, _, _>( |
| &CString::new("main").unwrap(), |
| ShaderInterface::empty(), |
| ShaderInterface::empty(), |
| PipelineLayoutDesc::empty(), |
| ) |
| }, |
| depth_stencil: DepthStencil::disabled(), |
| blend: Blend::pass_through(), |
| render_pass: Subpass::from( |
| simple_rp::CustomRenderPass::new(&device, &{ |
| simple_rp::Formats { |
| color: (Format::R8G8B8A8Unorm, 1), |
| } |
| }) |
| .unwrap(), |
| 0, |
| ) |
| .unwrap(), |
| }, |
| ); |
| |
| match result { |
| Err(GraphicsPipelineCreationError::MultiViewportFeatureNotEnabled) => (), |
| _ => panic!(), |
| } |
| } |
| |
| #[test] |
| fn max_viewports() { |
| let (device, _) = gfx_dev_and_queue!(multi_viewport); |
| |
| let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() }; |
| let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() }; |
| |
| let result = GraphicsPipeline::new( |
| &device, |
| GraphicsPipelineParams { |
| vertex_input: SingleBufferDefinition::<()>::new(), |
| vertex_shader: unsafe { |
| vs.vertex_shader_entry_point::<(), _, _, _>( |
| &CString::new("main").unwrap(), |
| ShaderInterface::empty(), |
| ShaderInterface::empty(), |
| PipelineLayoutDesc::empty(), |
| ) |
| }, |
| input_assembly: InputAssembly::triangle_list(), |
| tessellation: None, |
| geometry_shader: None, |
| viewport: ViewportsState::Dynamic { num: !0 }, |
| raster: Default::default(), |
| multisample: Multisample::disabled(), |
| fragment_shader: unsafe { |
| fs.fragment_shader_entry_point::<(), _, _, _>( |
| &CString::new("main").unwrap(), |
| ShaderInterface::empty(), |
| ShaderInterface::empty(), |
| PipelineLayoutDesc::empty(), |
| ) |
| }, |
| depth_stencil: DepthStencil::disabled(), |
| blend: Blend::pass_through(), |
| render_pass: Subpass::from( |
| simple_rp::CustomRenderPass::new(&device, &{ |
| simple_rp::Formats { |
| color: (Format::R8G8B8A8Unorm, 1), |
| } |
| }) |
| .unwrap(), |
| 0, |
| ) |
| .unwrap(), |
| }, |
| ); |
| |
| match result { |
| Err(GraphicsPipelineCreationError::MaxViewportsExceeded { .. }) => (), |
| _ => panic!(), |
| } |
| } |
| |
| #[test] |
| fn no_depth_attachment() { |
| let (device, _) = gfx_dev_and_queue!(); |
| |
| let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() }; |
| let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() }; |
| |
| let result = GraphicsPipeline::new( |
| &device, |
| GraphicsPipelineParams { |
| vertex_input: SingleBufferDefinition::<()>::new(), |
| vertex_shader: unsafe { |
| vs.vertex_shader_entry_point::<(), _, _, _>( |
| &CString::new("main").unwrap(), |
| ShaderInterface::empty(), |
| ShaderInterface::empty(), |
| PipelineLayoutDesc::empty(), |
| ) |
| }, |
| input_assembly: InputAssembly::triangle_list(), |
| tessellation: None, |
| geometry_shader: None, |
| viewport: ViewportsState::Dynamic { num: 1 }, |
| raster: Default::default(), |
| multisample: Multisample::disabled(), |
| fragment_shader: unsafe { |
| fs.fragment_shader_entry_point::<(), _, _, _>( |
| &CString::new("main").unwrap(), |
| ShaderInterface::empty(), |
| ShaderInterface::empty(), |
| PipelineLayoutDesc::empty(), |
| ) |
| }, |
| depth_stencil: DepthStencil::simple_depth_test(), |
| blend: Blend::pass_through(), |
| render_pass: Subpass::from( |
| simple_rp::CustomRenderPass::new(&device, &{ |
| simple_rp::Formats { |
| color: (Format::R8G8B8A8Unorm, 1), |
| } |
| }) |
| .unwrap(), |
| 0, |
| ) |
| .unwrap(), |
| }, |
| ); |
| |
| match result { |
| Err(GraphicsPipelineCreationError::NoDepthAttachment) => (), |
| _ => panic!(), |
| } |
| } |
| |
| mod simple_rp { |
| use format::Format; |
| |
| single_pass_renderpass! { |
| attachments: { |
| color: { |
| load: Clear, |
| store: Store, |
| format: Format, |
| } |
| }, |
| pass: { |
| color: [color], |
| depth_stencil: {} |
| } |
| } |
| } |
| |
| /* |
| #version 450 |
| |
| #extension GL_ARB_separate_shader_objects : enable |
| #extension GL_ARB_shading_language_420pack : enable |
| |
| layout(location = 0) in vec2 position; |
| |
| void main() { |
| gl_Position = vec4(position, 0.0, 1.0); |
| } |
| */ |
| const BASIC_VS: [u8; 912] = [ |
| 3, 2, 35, 7, 0, 0, 1, 0, 1, 0, 8, 0, 27, 0, 0, 0, 0, 0, 0, 0, 17, 0, 2, 0, 1, 0, 0, 0, 17, 0, |
| 2, 0, 32, 0, 0, 0, 17, 0, 2, 0, 33, 0, 0, 0, 11, 0, 6, 0, 1, 0, 0, 0, 71, 76, 83, 76, 46, 115, |
| 116, 100, 46, 52, 53, 48, 0, 0, 0, 0, 14, 0, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 15, 0, 7, 0, 0, 0, |
| 0, 0, 4, 0, 0, 0, 109, 97, 105, 110, 0, 0, 0, 0, 13, 0, 0, 0, 18, 0, 0, 0, 3, 0, 3, 0, 2, 0, 0, |
| 0, 194, 1, 0, 0, 4, 0, 9, 0, 71, 76, 95, 65, 82, 66, 95, 115, 101, 112, 97, 114, 97, 116, 101, |
| 95, 115, 104, 97, 100, 101, 114, 95, 111, 98, 106, 101, 99, 116, 115, 0, 0, 4, 0, 9, 0, 71, 76, |
| 95, 65, 82, 66, 95, 115, 104, 97, 100, 105, 110, 103, 95, 108, 97, 110, 103, 117, 97, 103, 101, |
| 95, 52, 50, 48, 112, 97, 99, 107, 0, 5, 0, 4, 0, 4, 0, 0, 0, 109, 97, 105, 110, 0, 0, 0, 0, 5, |
| 0, 6, 0, 11, 0, 0, 0, 103, 108, 95, 80, 101, 114, 86, 101, 114, 116, 101, 120, 0, 0, 0, 0, 6, |
| 0, 6, 0, 11, 0, 0, 0, 0, 0, 0, 0, 103, 108, 95, 80, 111, 115, 105, 116, 105, 111, 110, 0, 6, 0, |
| 7, 0, 11, 0, 0, 0, 1, 0, 0, 0, 103, 108, 95, 80, 111, 105, 110, 116, 83, 105, 122, 101, 0, 0, |
| 0, 0, 6, 0, 7, 0, 11, 0, 0, 0, 2, 0, 0, 0, 103, 108, 95, 67, 108, 105, 112, 68, 105, 115, 116, |
| 97, 110, 99, 101, 0, 6, 0, 7, 0, 11, 0, 0, 0, 3, 0, 0, 0, 103, 108, 95, 67, 117, 108, 108, 68, |
| 105, 115, 116, 97, 110, 99, 101, 0, 5, 0, 3, 0, 13, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 0, 18, 0, 0, |
| 0, 112, 111, 115, 105, 116, 105, 111, 110, 0, 0, 0, 0, 72, 0, 5, 0, 11, 0, 0, 0, 0, 0, 0, 0, |
| 11, 0, 0, 0, 0, 0, 0, 0, 72, 0, 5, 0, 11, 0, 0, 0, 1, 0, 0, 0, 11, 0, 0, 0, 1, 0, 0, 0, 72, 0, |
| 5, 0, 11, 0, 0, 0, 2, 0, 0, 0, 11, 0, 0, 0, 3, 0, 0, 0, 72, 0, 5, 0, 11, 0, 0, 0, 3, 0, 0, 0, |
| 11, 0, 0, 0, 4, 0, 0, 0, 71, 0, 3, 0, 11, 0, 0, 0, 2, 0, 0, 0, 71, 0, 4, 0, 18, 0, 0, 0, 30, 0, |
| 0, 0, 0, 0, 0, 0, 19, 0, 2, 0, 2, 0, 0, 0, 33, 0, 3, 0, 3, 0, 0, 0, 2, 0, 0, 0, 22, 0, 3, 0, 6, |
| 0, 0, 0, 32, 0, 0, 0, 23, 0, 4, 0, 7, 0, 0, 0, 6, 0, 0, 0, 4, 0, 0, 0, 21, 0, 4, 0, 8, 0, 0, 0, |
| 32, 0, 0, 0, 0, 0, 0, 0, 43, 0, 4, 0, 8, 0, 0, 0, 9, 0, 0, 0, 1, 0, 0, 0, 28, 0, 4, 0, 10, 0, |
| 0, 0, 6, 0, 0, 0, 9, 0, 0, 0, 30, 0, 6, 0, 11, 0, 0, 0, 7, 0, 0, 0, 6, 0, 0, 0, 10, 0, 0, 0, |
| 10, 0, 0, 0, 32, 0, 4, 0, 12, 0, 0, 0, 3, 0, 0, 0, 11, 0, 0, 0, 59, 0, 4, 0, 12, 0, 0, 0, 13, |
| 0, 0, 0, 3, 0, 0, 0, 21, 0, 4, 0, 14, 0, 0, 0, 32, 0, 0, 0, 1, 0, 0, 0, 43, 0, 4, 0, 14, 0, 0, |
| 0, 15, 0, 0, 0, 0, 0, 0, 0, 23, 0, 4, 0, 16, 0, 0, 0, 6, 0, 0, 0, 2, 0, 0, 0, 32, 0, 4, 0, 17, |
| 0, 0, 0, 1, 0, 0, 0, 16, 0, 0, 0, 59, 0, 4, 0, 17, 0, 0, 0, 18, 0, 0, 0, 1, 0, 0, 0, 43, 0, 4, |
| 0, 6, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 43, 0, 4, 0, 6, 0, 0, 0, 21, 0, 0, 0, 0, 0, 128, 63, |
| 32, 0, 4, 0, 25, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0, 54, 0, 5, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, |
| 0, 3, 0, 0, 0, 248, 0, 2, 0, 5, 0, 0, 0, 61, 0, 4, 0, 16, 0, 0, 0, 19, 0, 0, 0, 18, 0, 0, 0, |
| 81, 0, 5, 0, 6, 0, 0, 0, 22, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 81, 0, 5, 0, 6, 0, 0, 0, 23, 0, |
| 0, 0, 19, 0, 0, 0, 1, 0, 0, 0, 80, 0, 7, 0, 7, 0, 0, 0, 24, 0, 0, 0, 22, 0, 0, 0, 23, 0, 0, 0, |
| 20, 0, 0, 0, 21, 0, 0, 0, 65, 0, 5, 0, 25, 0, 0, 0, 26, 0, 0, 0, 13, 0, 0, 0, 15, 0, 0, 0, 62, |
| 0, 3, 0, 26, 0, 0, 0, 24, 0, 0, 0, 253, 0, 1, 0, 56, 0, 1, 0, |
| ]; |
| |
| /* |
| #version 450 |
| |
| #extension GL_ARB_separate_shader_objects : enable |
| #extension GL_ARB_shading_language_420pack : enable |
| |
| layout(location = 0) out vec4 f_color; |
| |
| void main() { |
| f_color = vec4(1.0, 0.0, 0.0, 1.0); |
| } |
| */ |
| const BASIC_FS: [u8; 420] = [ |
| 3, 2, 35, 7, 0, 0, 1, 0, 1, 0, 8, 0, 13, 0, 0, 0, 0, 0, 0, 0, 17, 0, 2, 0, 1, 0, 0, 0, 11, 0, |
| 6, 0, 1, 0, 0, 0, 71, 76, 83, 76, 46, 115, 116, 100, 46, 52, 53, 48, 0, 0, 0, 0, 14, 0, 3, 0, |
| 0, 0, 0, 0, 1, 0, 0, 0, 15, 0, 6, 0, 4, 0, 0, 0, 4, 0, 0, 0, 109, 97, 105, 110, 0, 0, 0, 0, 9, |
| 0, 0, 0, 16, 0, 3, 0, 4, 0, 0, 0, 7, 0, 0, 0, 3, 0, 3, 0, 2, 0, 0, 0, 194, 1, 0, 0, 4, 0, 9, 0, |
| 71, 76, 95, 65, 82, 66, 95, 115, 101, 112, 97, 114, 97, 116, 101, 95, 115, 104, 97, 100, 101, |
| 114, 95, 111, 98, 106, 101, 99, 116, 115, 0, 0, 4, 0, 9, 0, 71, 76, 95, 65, 82, 66, 95, 115, |
| 104, 97, 100, 105, 110, 103, 95, 108, 97, 110, 103, 117, 97, 103, 101, 95, 52, 50, 48, 112, 97, |
| 99, 107, 0, 5, 0, 4, 0, 4, 0, 0, 0, 109, 97, 105, 110, 0, 0, 0, 0, 5, 0, 4, 0, 9, 0, 0, 0, 102, |
| 95, 99, 111, 108, 111, 114, 0, 71, 0, 4, 0, 9, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 19, 0, 2, 0, |
| 2, 0, 0, 0, 33, 0, 3, 0, 3, 0, 0, 0, 2, 0, 0, 0, 22, 0, 3, 0, 6, 0, 0, 0, 32, 0, 0, 0, 23, 0, |
| 4, 0, 7, 0, 0, 0, 6, 0, 0, 0, 4, 0, 0, 0, 32, 0, 4, 0, 8, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0, 59, |
| 0, 4, 0, 8, 0, 0, 0, 9, 0, 0, 0, 3, 0, 0, 0, 43, 0, 4, 0, 6, 0, 0, 0, 10, 0, 0, 0, 0, 0, 128, |
| 63, 43, 0, 4, 0, 6, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 44, 0, 7, 0, 7, 0, 0, 0, 12, 0, 0, 0, 10, |
| 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 10, 0, 0, 0, 54, 0, 5, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, |
| 0, 3, 0, 0, 0, 248, 0, 2, 0, 5, 0, 0, 0, 62, 0, 3, 0, 9, 0, 0, 0, 12, 0, 0, 0, 253, 0, 1, 0, |
| 56, 0, 1, 0, |
| ]; |