1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://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 //! This module contains the unit tests of `GraphicsPipeline`.
11 
12 #![cfg(test)]
13 
14 use format::Format;
15 use framebuffer::Subpass;
16 use pipeline::blend::Blend;
17 use pipeline::depth_stencil::DepthStencil;
18 use pipeline::input_assembly::InputAssembly;
19 use pipeline::input_assembly::PrimitiveTopology;
20 use pipeline::layout::PipelineLayoutDesc;
21 use pipeline::multisample::Multisample;
22 use pipeline::shader::ShaderInterface;
23 use pipeline::shader::ShaderModule;
24 use pipeline::vertex::SingleBufferDefinition;
25 use pipeline::viewport::ViewportsState;
26 use pipeline::GraphicsPipeline;
27 use pipeline::GraphicsPipelineCreationError;
28 use pipeline::GraphicsPipelineParams;
29 use std::ffi::CString;
30 
31 #[test]
create()32 fn create() {
33     let (device, _) = gfx_dev_and_queue!();
34 
35     let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() };
36     let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() };
37 
38     let _ = GraphicsPipeline::new(
39         &device,
40         GraphicsPipelineParams {
41             vertex_input: SingleBufferDefinition::<()>::new(),
42             vertex_shader: unsafe {
43                 vs.vertex_shader_entry_point::<(), _, _, _>(
44                     &CString::new("main").unwrap(),
45                     ShaderInterface::empty(),
46                     ShaderInterface::empty(),
47                     PipelineLayoutDesc::empty(),
48                 )
49             },
50             input_assembly: InputAssembly::triangle_list(),
51             tessellation: None,
52             geometry_shader: None,
53             viewport: ViewportsState::Dynamic { num: 1 },
54             raster: Default::default(),
55             multisample: Multisample::disabled(),
56             fragment_shader: unsafe {
57                 fs.fragment_shader_entry_point::<(), _, _, _>(
58                     &CString::new("main").unwrap(),
59                     ShaderInterface::empty(),
60                     ShaderInterface::empty(),
61                     PipelineLayoutDesc::empty(),
62                 )
63             },
64             depth_stencil: DepthStencil::disabled(),
65             blend: Blend::pass_through(),
66             render_pass: Subpass::from(
67                 simple_rp::CustomRenderPass::new(&device, &{
68                     simple_rp::Formats {
69                         color: (Format::R8G8B8A8_UNORM, 1),
70                     }
71                 })
72                 .unwrap(),
73                 0,
74             )
75             .unwrap(),
76         },
77     )
78     .unwrap();
79 }
80 
81 #[test]
bad_primitive_restart()82 fn bad_primitive_restart() {
83     let (device, _) = gfx_dev_and_queue!();
84 
85     let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() };
86     let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() };
87 
88     let result = GraphicsPipeline::new(
89         &device,
90         GraphicsPipelineParams {
91             vertex_input: SingleBufferDefinition::<()>::new(),
92             vertex_shader: unsafe {
93                 vs.vertex_shader_entry_point::<(), _, _, _>(
94                     &CString::new("main").unwrap(),
95                     ShaderInterface::empty(),
96                     ShaderInterface::empty(),
97                     PipelineLayoutDesc::empty(),
98                 )
99             },
100             input_assembly: InputAssembly {
101                 topology: PrimitiveTopology::TriangleList,
102                 primitive_restart_enable: true,
103             },
104             tessellation: None,
105             geometry_shader: None,
106             viewport: ViewportsState::Dynamic { num: 1 },
107             raster: Default::default(),
108             multisample: Multisample::disabled(),
109             fragment_shader: unsafe {
110                 fs.fragment_shader_entry_point::<(), _, _, _>(
111                     &CString::new("main").unwrap(),
112                     ShaderInterface::empty(),
113                     ShaderInterface::empty(),
114                     PipelineLayoutDesc::empty(),
115                 )
116             },
117             depth_stencil: DepthStencil::disabled(),
118             blend: Blend::pass_through(),
119             render_pass: Subpass::from(
120                 simple_rp::CustomRenderPass::new(&device, &{
121                     simple_rp::Formats {
122                         color: (Format::R8G8B8A8_UNORM, 1),
123                     }
124                 })
125                 .unwrap(),
126                 0,
127             )
128             .unwrap(),
129         },
130     );
131 
132     match result {
133         Err(GraphicsPipelineCreationError::RequirementNotMet { .. }) => (),
134         _ => panic!(),
135     }
136 }
137 
138 #[test]
multi_viewport_feature()139 fn multi_viewport_feature() {
140     let (device, _) = gfx_dev_and_queue!();
141 
142     let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() };
143     let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() };
144 
145     let result = GraphicsPipeline::new(
146         &device,
147         GraphicsPipelineParams {
148             vertex_input: SingleBufferDefinition::<()>::new(),
149             vertex_shader: unsafe {
150                 vs.vertex_shader_entry_point::<(), _, _, _>(
151                     &CString::new("main").unwrap(),
152                     ShaderInterface::empty(),
153                     ShaderInterface::empty(),
154                     PipelineLayoutDesc::empty(),
155                 )
156             },
157             input_assembly: InputAssembly::triangle_list(),
158             tessellation: None,
159             geometry_shader: None,
160             viewport: ViewportsState::Dynamic { num: 2 },
161             raster: Default::default(),
162             multisample: Multisample::disabled(),
163             fragment_shader: unsafe {
164                 fs.fragment_shader_entry_point::<(), _, _, _>(
165                     &CString::new("main").unwrap(),
166                     ShaderInterface::empty(),
167                     ShaderInterface::empty(),
168                     PipelineLayoutDesc::empty(),
169                 )
170             },
171             depth_stencil: DepthStencil::disabled(),
172             blend: Blend::pass_through(),
173             render_pass: Subpass::from(
174                 simple_rp::CustomRenderPass::new(&device, &{
175                     simple_rp::Formats {
176                         color: (Format::R8G8B8A8_UNORM, 1),
177                     }
178                 })
179                 .unwrap(),
180                 0,
181             )
182             .unwrap(),
183         },
184     );
185 
186     match result {
187         Err(GraphicsPipelineCreationError::MultiViewportFeatureNotEnabled) => (),
188         _ => panic!(),
189     }
190 }
191 
192 #[test]
max_viewports()193 fn max_viewports() {
194     let (device, _) = gfx_dev_and_queue!(multi_viewport);
195 
196     let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() };
197     let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() };
198 
199     let result = GraphicsPipeline::new(
200         &device,
201         GraphicsPipelineParams {
202             vertex_input: SingleBufferDefinition::<()>::new(),
203             vertex_shader: unsafe {
204                 vs.vertex_shader_entry_point::<(), _, _, _>(
205                     &CString::new("main").unwrap(),
206                     ShaderInterface::empty(),
207                     ShaderInterface::empty(),
208                     PipelineLayoutDesc::empty(),
209                 )
210             },
211             input_assembly: InputAssembly::triangle_list(),
212             tessellation: None,
213             geometry_shader: None,
214             viewport: ViewportsState::Dynamic { num: !0 },
215             raster: Default::default(),
216             multisample: Multisample::disabled(),
217             fragment_shader: unsafe {
218                 fs.fragment_shader_entry_point::<(), _, _, _>(
219                     &CString::new("main").unwrap(),
220                     ShaderInterface::empty(),
221                     ShaderInterface::empty(),
222                     PipelineLayoutDesc::empty(),
223                 )
224             },
225             depth_stencil: DepthStencil::disabled(),
226             blend: Blend::pass_through(),
227             render_pass: Subpass::from(
228                 simple_rp::CustomRenderPass::new(&device, &{
229                     simple_rp::Formats {
230                         color: (Format::R8G8B8A8_UNORM, 1),
231                     }
232                 })
233                 .unwrap(),
234                 0,
235             )
236             .unwrap(),
237         },
238     );
239 
240     match result {
241         Err(GraphicsPipelineCreationError::MaxViewportsExceeded { .. }) => (),
242         _ => panic!(),
243     }
244 }
245 
246 #[test]
no_depth_attachment()247 fn no_depth_attachment() {
248     let (device, _) = gfx_dev_and_queue!();
249 
250     let vs = unsafe { ShaderModule::new(device.clone(), &BASIC_VS).unwrap() };
251     let fs = unsafe { ShaderModule::new(device.clone(), &BASIC_FS).unwrap() };
252 
253     let result = GraphicsPipeline::new(
254         &device,
255         GraphicsPipelineParams {
256             vertex_input: SingleBufferDefinition::<()>::new(),
257             vertex_shader: unsafe {
258                 vs.vertex_shader_entry_point::<(), _, _, _>(
259                     &CString::new("main").unwrap(),
260                     ShaderInterface::empty(),
261                     ShaderInterface::empty(),
262                     PipelineLayoutDesc::empty(),
263                 )
264             },
265             input_assembly: InputAssembly::triangle_list(),
266             tessellation: None,
267             geometry_shader: None,
268             viewport: ViewportsState::Dynamic { num: 1 },
269             raster: Default::default(),
270             multisample: Multisample::disabled(),
271             fragment_shader: unsafe {
272                 fs.fragment_shader_entry_point::<(), _, _, _>(
273                     &CString::new("main").unwrap(),
274                     ShaderInterface::empty(),
275                     ShaderInterface::empty(),
276                     PipelineLayoutDesc::empty(),
277                 )
278             },
279             depth_stencil: DepthStencil::simple_depth_test(),
280             blend: Blend::pass_through(),
281             render_pass: Subpass::from(
282                 simple_rp::CustomRenderPass::new(&device, &{
283                     simple_rp::Formats {
284                         color: (Format::R8G8B8A8_UNORM, 1),
285                     }
286                 })
287                 .unwrap(),
288                 0,
289             )
290             .unwrap(),
291         },
292     );
293 
294     match result {
295         Err(GraphicsPipelineCreationError::NoDepthAttachment) => (),
296         _ => panic!(),
297     }
298 }
299 
300 mod simple_rp {
301     use format::Format;
302 
303     single_pass_renderpass! {
304         attachments: {
305             color: {
306                 load: Clear,
307                 store: Store,
308                 format: Format,
309             },
310         },
311         pass: {
312             color: [color],
313             depth_stencil: {},
314         },
315     }
316 }
317 
318 /*
319     #version 450
320 
321     #extension GL_ARB_separate_shader_objects : enable
322     #extension GL_ARB_shading_language_420pack : enable
323 
324     layout(location = 0) in vec2 position;
325 
326     void main() {
327         gl_Position = vec4(position, 0.0, 1.0);
328     }
329 */
330 const BASIC_VS: [u8; 912] = [
331     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,
332     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,
333     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,
334     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,
335     0, 194, 1, 0, 0, 4, 0, 9, 0, 71, 76, 95, 65, 82, 66, 95, 115, 101, 112, 97, 114, 97, 116, 101,
336     95, 115, 104, 97, 100, 101, 114, 95, 111, 98, 106, 101, 99, 116, 115, 0, 0, 4, 0, 9, 0, 71, 76,
337     95, 65, 82, 66, 95, 115, 104, 97, 100, 105, 110, 103, 95, 108, 97, 110, 103, 117, 97, 103, 101,
338     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,
339     0, 6, 0, 11, 0, 0, 0, 103, 108, 95, 80, 101, 114, 86, 101, 114, 116, 101, 120, 0, 0, 0, 0, 6,
340     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,
341     7, 0, 11, 0, 0, 0, 1, 0, 0, 0, 103, 108, 95, 80, 111, 105, 110, 116, 83, 105, 122, 101, 0, 0,
342     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,
343     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,
344     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,
345     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,
346     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,
347     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,
348     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,
349     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,
350     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,
351     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,
352     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,
353     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,
354     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,
355     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,
356     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,
357     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,
358     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,
359     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,
360     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,
361     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,
362     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,
363     0, 3, 0, 26, 0, 0, 0, 24, 0, 0, 0, 253, 0, 1, 0, 56, 0, 1, 0,
364 ];
365 
366 /*
367     #version 450
368 
369     #extension GL_ARB_separate_shader_objects : enable
370     #extension GL_ARB_shading_language_420pack : enable
371 
372     layout(location = 0) out vec4 f_color;
373 
374     void main() {
375         f_color = vec4(1.0, 0.0, 0.0, 1.0);
376     }
377 */
378 const BASIC_FS: [u8; 420] = [
379     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,
380     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,
381     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,
382     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,
383     71, 76, 95, 65, 82, 66, 95, 115, 101, 112, 97, 114, 97, 116, 101, 95, 115, 104, 97, 100, 101,
384     114, 95, 111, 98, 106, 101, 99, 116, 115, 0, 0, 4, 0, 9, 0, 71, 76, 95, 65, 82, 66, 95, 115,
385     104, 97, 100, 105, 110, 103, 95, 108, 97, 110, 103, 117, 97, 103, 101, 95, 52, 50, 48, 112, 97,
386     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,
387     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,
388     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,
389     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,
390     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,
391     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,
392     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,
393     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,
394     56, 0, 1, 0,
395 ];
396