• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //! Viewports and scissor boxes.
11 //!
12 //! There are two different concepts to determine where things will be drawn:
13 //!
14 //! - The viewport is the region of the image which corresponds to the
15 //!   vertex coordinates `-1.0` to `1.0`.
16 //! - Any pixel outside of the scissor box will be discarded.
17 //!
18 //! In other words modifying the viewport will stretch the image, while modifying the scissor
19 //! box acts like a filter.
20 //!
21 //! It is legal and sensible to use a viewport that is larger than the target image or that
22 //! only partially overlaps the target image.
23 //!
24 //! # Multiple viewports
25 //!
26 //! In most situations, you only need a single viewport and a single scissor box.
27 //!
28 //! If, however, you use a geometry shader, you can specify multiple viewports and scissor boxes.
29 //! Then in your geometry shader you can specify in which viewport and scissor box the primitive
30 //! should be written to. In GLSL this is done by writing to the special variable
31 //! `gl_ViewportIndex`.
32 //!
33 //! If you don't use a geometry shader or use a geometry shader where don't set which viewport to
34 //! use, then the first viewport and scissor box will be used.
35 //!
36 //! # Dynamic and fixed
37 //!
38 //! Vulkan allows four different setups:
39 //!
40 //! - The state of both the viewports and scissor boxes is known at pipeline creation.
41 //! - The state of viewports is known at pipeline creation, but the state of scissor boxes is
42 //!   only known when submitting the draw command.
43 //! - The state of scissor boxes is known at pipeline creation, but the state of viewports is
44 //!   only known when submitting the draw command.
45 //! - The state of both the viewports and scissor boxes is only known when submitting the
46 //!   draw command.
47 //!
48 //! In all cases the number of viewports and scissor boxes must be the same.
49 //!
50 
51 use std::ops::Range;
52 
53 /// List of viewports and scissors that are used when creating a graphics pipeline object.
54 ///
55 /// Note that the number of viewports and scissors must be the same.
56 #[derive(Debug, Clone)]
57 pub enum ViewportsState {
58     /// The state is known in advance.
59     Fixed {
60         /// State of the viewports and scissors.
61         data: Vec<(Viewport, Scissor)>,
62     },
63 
64     /// The state of scissors is known in advance, but the state of viewports is dynamic and will
65     /// bet set when drawing.
66     ///
67     /// Note that the number of viewports and scissors must be the same.
68     DynamicViewports {
69         /// State of the scissors.
70         scissors: Vec<Scissor>,
71     },
72 
73     /// The state of viewports is known in advance, but the state of scissors is dynamic and will
74     /// bet set when drawing.
75     ///
76     /// Note that the number of viewports and scissors must be the same.
77     DynamicScissors {
78         /// State of the viewports
79         viewports: Vec<Viewport>,
80     },
81 
82     /// The state of both the viewports and scissors is dynamic and will be set when drawing.
83     Dynamic {
84         /// Number of viewports and scissors.
85         num: u32,
86     },
87 }
88 
89 impl ViewportsState {
90     /// Returns true if the state of the viewports is dynamic.
dynamic_viewports(&self) -> bool91     pub fn dynamic_viewports(&self) -> bool {
92         match *self {
93             ViewportsState::Fixed { .. } => false,
94             ViewportsState::DynamicViewports { .. } => true,
95             ViewportsState::DynamicScissors { .. } => false,
96             ViewportsState::Dynamic { .. } => true,
97         }
98     }
99 
100     /// Returns true if the state of the scissors is dynamic.
dynamic_scissors(&self) -> bool101     pub fn dynamic_scissors(&self) -> bool {
102         match *self {
103             ViewportsState::Fixed { .. } => false,
104             ViewportsState::DynamicViewports { .. } => false,
105             ViewportsState::DynamicScissors { .. } => true,
106             ViewportsState::Dynamic { .. } => true,
107         }
108     }
109 
110     /// Returns the number of viewports and scissors.
num_viewports(&self) -> u32111     pub fn num_viewports(&self) -> u32 {
112         match *self {
113             ViewportsState::Fixed { ref data } => data.len() as u32,
114             ViewportsState::DynamicViewports { ref scissors } => scissors.len() as u32,
115             ViewportsState::DynamicScissors { ref viewports } => viewports.len() as u32,
116             ViewportsState::Dynamic { num } => num,
117         }
118     }
119 }
120 
121 /// State of a single viewport.
122 // FIXME: check that:
123 //        x + width must be less than or equal to viewportBoundsRange[0]
124 //        y + height must be less than or equal to viewportBoundsRange[1]
125 #[derive(Debug, Clone, PartialEq)]
126 pub struct Viewport {
127     /// Coordinates in pixels of the top-left hand corner of the viewport.
128     pub origin: [f32; 2],
129 
130     /// Dimensions in pixels of the viewport.
131     pub dimensions: [f32; 2],
132 
133     /// Minimum and maximum values of the depth.
134     ///
135     /// The values `0.0` to `1.0` of each vertex's Z coordinate will be mapped to this
136     /// `depth_range` before being compared to the existing depth value.
137     ///
138     /// This is equivalents to `glDepthRange` in OpenGL, except that OpenGL uses the Z coordinate
139     /// range from `-1.0` to `1.0` instead.
140     pub depth_range: Range<f32>,
141 }
142 
143 impl From<Viewport> for ash::vk::Viewport {
144     #[inline]
from(val: Viewport) -> Self145     fn from(val: Viewport) -> Self {
146         ash::vk::Viewport {
147             x: val.origin[0],
148             y: val.origin[1],
149             width: val.dimensions[0],
150             height: val.dimensions[1],
151             min_depth: val.depth_range.start,
152             max_depth: val.depth_range.end,
153         }
154     }
155 }
156 
157 /// State of a single scissor box.
158 // FIXME: add a check:
159 //      Evaluation of (offset.x + extent.width) must not cause a signed integer addition overflow
160 //      Evaluation of (offset.y + extent.height) must not cause a signed integer addition overflow
161 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
162 pub struct Scissor {
163     /// Coordinates in pixels of the top-left hand corner of the box.
164     pub origin: [i32; 2],
165 
166     /// Dimensions in pixels of the box.
167     pub dimensions: [u32; 2],
168 }
169 
170 impl Scissor {
171     /// Returns a scissor that, when used, will instruct the pipeline to draw to the entire framebuffer.
172     #[inline]
irrelevant() -> Scissor173     pub fn irrelevant() -> Scissor {
174         Scissor {
175             origin: [0, 0],
176             dimensions: [0x7fffffff, 0x7fffffff],
177         }
178     }
179 }
180 
181 impl Default for Scissor {
182     #[inline]
default() -> Scissor183     fn default() -> Scissor {
184         Scissor::irrelevant()
185     }
186 }
187 
188 impl From<Scissor> for ash::vk::Rect2D {
189     #[inline]
from(val: Scissor) -> Self190     fn from(val: Scissor) -> Self {
191         ash::vk::Rect2D {
192             offset: ash::vk::Offset2D {
193                 x: val.origin[0],
194                 y: val.origin[1],
195             },
196             extent: ash::vk::Extent2D {
197                 width: val.dimensions[0],
198                 height: val.dimensions[1],
199             },
200         }
201     }
202 }
203