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