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 use crate::format::ClearValue; 11 use crate::format::Format; 12 use crate::format::FormatTy; 13 use crate::image::sys::UnsafeImage; 14 use crate::image::ImageDescriptorLayouts; 15 use crate::image::ImageDimensions; 16 use crate::image::ImageLayout; 17 use crate::image::SampleCount; 18 use crate::sync::AccessError; 19 use crate::SafeDeref; 20 use std::hash::Hash; 21 use std::hash::Hasher; 22 23 /// Trait for types that represent the way a GPU can access an image. 24 pub unsafe trait ImageAccess { 25 /// Returns the inner unsafe image object used by this image. inner(&self) -> ImageInner26 fn inner(&self) -> ImageInner; 27 28 /// Returns the format of this image. 29 #[inline] format(&self) -> Format30 fn format(&self) -> Format { 31 self.inner().image.format() 32 } 33 34 /// Returns true if the image is a color image. 35 #[inline] has_color(&self) -> bool36 fn has_color(&self) -> bool { 37 matches!( 38 self.format().ty(), 39 FormatTy::Float | FormatTy::Uint | FormatTy::Sint | FormatTy::Compressed 40 ) 41 } 42 43 /// Returns true if the image has a depth component. In other words, if it is a depth or a 44 /// depth-stencil format. 45 #[inline] has_depth(&self) -> bool46 fn has_depth(&self) -> bool { 47 matches!(self.format().ty(), FormatTy::Depth | FormatTy::DepthStencil) 48 } 49 50 /// Returns true if the image has a stencil component. In other words, if it is a stencil or a 51 /// depth-stencil format. 52 #[inline] has_stencil(&self) -> bool53 fn has_stencil(&self) -> bool { 54 matches!( 55 self.format().ty(), 56 FormatTy::Stencil | FormatTy::DepthStencil 57 ) 58 } 59 60 /// Returns the number of mipmap levels of this image. 61 #[inline] mipmap_levels(&self) -> u3262 fn mipmap_levels(&self) -> u32 { 63 // TODO: not necessarily correct because of the new inner() design? 64 self.inner().image.mipmap_levels() 65 } 66 67 /// Returns the number of samples of this image. 68 #[inline] samples(&self) -> SampleCount69 fn samples(&self) -> SampleCount { 70 self.inner().image.samples() 71 } 72 73 /// Returns the dimensions of the image. 74 #[inline] dimensions(&self) -> ImageDimensions75 fn dimensions(&self) -> ImageDimensions { 76 // TODO: not necessarily correct because of the new inner() design? 77 self.inner().image.dimensions() 78 } 79 80 /// Returns true if the image can be used as a source for blits. 81 #[inline] supports_blit_source(&self) -> bool82 fn supports_blit_source(&self) -> bool { 83 self.inner().image.format_features().blit_src 84 } 85 86 /// Returns true if the image can be used as a destination for blits. 87 #[inline] supports_blit_destination(&self) -> bool88 fn supports_blit_destination(&self) -> bool { 89 self.inner().image.format_features().blit_dst 90 } 91 92 /// When images are created their memory layout is initially `Undefined` or `Preinitialized`. 93 /// This method allows the image memory barrier creation process to signal when an image 94 /// has been transitioned out of its initial `Undefined` or `Preinitialized` state. This 95 /// allows vulkano to avoid creating unnecessary image memory barriers between future 96 /// uses of the image. 97 /// 98 /// ## Unsafe 99 /// 100 /// If a user calls this method outside of the intended context and signals that the layout 101 /// is no longer `Undefined` or `Preinitialized` when it is still in an `Undefined` or 102 /// `Preinitialized` state, this may result in the vulkan implementation attempting to use 103 /// an image in an invalid layout. The same problem must be considered by the implementer 104 /// of the method. layout_initialized(&self)105 unsafe fn layout_initialized(&self) {} 106 is_layout_initialized(&self) -> bool107 fn is_layout_initialized(&self) -> bool { 108 false 109 } 110 preinitialized_layout(&self) -> bool111 unsafe fn preinitialized_layout(&self) -> bool { 112 self.inner().image.preinitialized_layout() 113 } 114 115 /// Returns the layout that the image has when it is first used in a primary command buffer. 116 /// 117 /// The first time you use an image in an `AutoCommandBufferBuilder`, vulkano will suppose that 118 /// the image is in the layout returned by this function. Later when the command buffer is 119 /// submitted vulkano will check whether the image is actually in this layout, and if it is not 120 /// the case then an error will be returned. 121 /// TODO: ^ that check is not yet implemented initial_layout_requirement(&self) -> ImageLayout122 fn initial_layout_requirement(&self) -> ImageLayout; 123 124 /// Returns the layout that the image must be returned to before the end of the command buffer. 125 /// 126 /// When an image is used in an `AutoCommandBufferBuilder` vulkano will automatically 127 /// transition this image to the layout returned by this function at the end of the command 128 /// buffer, if necessary. 129 /// 130 /// Except for special cases, this value should likely be the same as the one returned by 131 /// `initial_layout_requirement` so that the user can submit multiple command buffers that use 132 /// this image one after the other. final_layout_requirement(&self) -> ImageLayout133 fn final_layout_requirement(&self) -> ImageLayout; 134 135 /// Wraps around this `ImageAccess` and returns an identical `ImageAccess` but whose initial 136 /// layout requirement is either `Undefined` or `Preinitialized`. 137 #[inline] forced_undefined_initial_layout( self, preinitialized: bool, ) -> ImageAccessFromUndefinedLayout<Self> where Self: Sized,138 unsafe fn forced_undefined_initial_layout( 139 self, 140 preinitialized: bool, 141 ) -> ImageAccessFromUndefinedLayout<Self> 142 where 143 Self: Sized, 144 { 145 ImageAccessFromUndefinedLayout { 146 image: self, 147 preinitialized, 148 } 149 } 150 151 /// Returns an [`ImageDescriptorLayouts`] structure specifying the image layout to use 152 /// in descriptors of various kinds. 153 /// 154 /// This must return `Some` if the image is to be used to create an image view. descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>155 fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>; 156 157 /// Returns a key that uniquely identifies the memory content of the image. 158 /// Two ranges that potentially overlap in memory must return the same key. 159 /// 160 /// The key is shared amongst all buffers and images, which means that you can make several 161 /// different image objects share the same memory, or make some image objects share memory 162 /// with buffers, as long as they return the same key. 163 /// 164 /// Since it is possible to accidentally return the same key for memory ranges that don't 165 /// overlap, the `conflicts_image` or `conflicts_buffer` function should always be called to 166 /// verify whether they actually overlap. conflict_key(&self) -> u64167 fn conflict_key(&self) -> u64; 168 169 /// Returns the current mip level that is accessed by the gpu current_miplevels_access(&self) -> std::ops::Range<u32>170 fn current_miplevels_access(&self) -> std::ops::Range<u32>; 171 172 /// Returns the current layer level that is accessed by the gpu current_layer_levels_access(&self) -> std::ops::Range<u32>173 fn current_layer_levels_access(&self) -> std::ops::Range<u32>; 174 175 /// Locks the resource for usage on the GPU. Returns an error if the lock can't be acquired. 176 /// 177 /// After this function returns `Ok`, you are authorized to use the image on the GPU. If the 178 /// GPU operation requires an exclusive access to the image (which includes image layout 179 /// transitions) then `exclusive_access` should be true. 180 /// 181 /// The `expected_layout` is the layout we expect the image to be in when we lock it. If the 182 /// actual layout doesn't match this expected layout, then an error should be returned. If 183 /// `Undefined` is passed, that means that the caller doesn't care about the actual layout, 184 /// and that a layout mismatch shouldn't return an error. 185 /// 186 /// This function exists to prevent the user from causing a data race by reading and writing 187 /// to the same resource at the same time. 188 /// 189 /// If you call this function, you should call `unlock()` once the resource is no longer in use 190 /// by the GPU. The implementation is not expected to automatically perform any unlocking and 191 /// can rely on the fact that `unlock()` is going to be called. try_gpu_lock( &self, exclusive_access: bool, uninitialized_safe: bool, expected_layout: ImageLayout, ) -> Result<(), AccessError>192 fn try_gpu_lock( 193 &self, 194 exclusive_access: bool, 195 uninitialized_safe: bool, 196 expected_layout: ImageLayout, 197 ) -> Result<(), AccessError>; 198 199 /// Locks the resource for usage on the GPU. Supposes that the resource is already locked, and 200 /// simply increases the lock by one. 201 /// 202 /// Must only be called after `try_gpu_lock()` succeeded. 203 /// 204 /// If you call this function, you should call `unlock()` once the resource is no longer in use 205 /// by the GPU. The implementation is not expected to automatically perform any unlocking and 206 /// can rely on the fact that `unlock()` is going to be called. increase_gpu_lock(&self)207 unsafe fn increase_gpu_lock(&self); 208 209 /// Unlocks the resource previously acquired with `try_gpu_lock` or `increase_gpu_lock`. 210 /// 211 /// If the GPU operation that we unlock from transitioned the image to another layout, then 212 /// it should be passed as parameter. 213 /// 214 /// A layout transition requires exclusive access to the image, which means two things: 215 /// 216 /// - The implementation can panic if it finds out that the layout is not the same as it 217 /// currently is and that it is not locked in exclusive mode. 218 /// - There shouldn't be any possible race between `unlock` and `try_gpu_lock`, since 219 /// `try_gpu_lock` should fail if the image is already locked in exclusive mode. 220 /// 221 /// # Safety 222 /// 223 /// - Must only be called once per previous lock. 224 /// - The transitioned layout must be supported by the image (eg. the layout shouldn't be 225 /// `ColorAttachmentOptimal` if the image wasn't created with the `color_attachment` usage). 226 /// - The transitioned layout must not be `Undefined`. 227 /// unlock(&self, transitioned_layout: Option<ImageLayout>)228 unsafe fn unlock(&self, transitioned_layout: Option<ImageLayout>); 229 } 230 231 /// Inner information about an image. 232 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 233 pub struct ImageInner<'a> { 234 /// The underlying image object. 235 pub image: &'a UnsafeImage, 236 237 /// The first layer of `image` to consider. 238 pub first_layer: usize, 239 240 /// The number of layers of `image` to consider. 241 pub num_layers: usize, 242 243 /// The first mipmap level of `image` to consider. 244 pub first_mipmap_level: usize, 245 246 /// The number of mipmap levels of `image` to consider. 247 pub num_mipmap_levels: usize, 248 } 249 250 unsafe impl<T> ImageAccess for T 251 where 252 T: SafeDeref, 253 T::Target: ImageAccess, 254 { 255 #[inline] inner(&self) -> ImageInner256 fn inner(&self) -> ImageInner { 257 (**self).inner() 258 } 259 260 #[inline] initial_layout_requirement(&self) -> ImageLayout261 fn initial_layout_requirement(&self) -> ImageLayout { 262 (**self).initial_layout_requirement() 263 } 264 265 #[inline] final_layout_requirement(&self) -> ImageLayout266 fn final_layout_requirement(&self) -> ImageLayout { 267 (**self).final_layout_requirement() 268 } 269 270 #[inline] descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>271 fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> { 272 (**self).descriptor_layouts() 273 } 274 275 #[inline] conflict_key(&self) -> u64276 fn conflict_key(&self) -> u64 { 277 (**self).conflict_key() 278 } 279 280 #[inline] try_gpu_lock( &self, exclusive_access: bool, uninitialized_safe: bool, expected_layout: ImageLayout, ) -> Result<(), AccessError>281 fn try_gpu_lock( 282 &self, 283 exclusive_access: bool, 284 uninitialized_safe: bool, 285 expected_layout: ImageLayout, 286 ) -> Result<(), AccessError> { 287 (**self).try_gpu_lock(exclusive_access, uninitialized_safe, expected_layout) 288 } 289 290 #[inline] increase_gpu_lock(&self)291 unsafe fn increase_gpu_lock(&self) { 292 (**self).increase_gpu_lock() 293 } 294 295 #[inline] unlock(&self, transitioned_layout: Option<ImageLayout>)296 unsafe fn unlock(&self, transitioned_layout: Option<ImageLayout>) { 297 (**self).unlock(transitioned_layout) 298 } 299 300 #[inline] layout_initialized(&self)301 unsafe fn layout_initialized(&self) { 302 (**self).layout_initialized(); 303 } 304 305 #[inline] is_layout_initialized(&self) -> bool306 fn is_layout_initialized(&self) -> bool { 307 (**self).is_layout_initialized() 308 } 309 current_miplevels_access(&self) -> std::ops::Range<u32>310 fn current_miplevels_access(&self) -> std::ops::Range<u32> { 311 (**self).current_miplevels_access() 312 } 313 current_layer_levels_access(&self) -> std::ops::Range<u32>314 fn current_layer_levels_access(&self) -> std::ops::Range<u32> { 315 (**self).current_layer_levels_access() 316 } 317 } 318 319 impl PartialEq for dyn ImageAccess + Send + Sync { 320 #[inline] eq(&self, other: &Self) -> bool321 fn eq(&self, other: &Self) -> bool { 322 self.inner() == other.inner() 323 } 324 } 325 326 impl Eq for dyn ImageAccess + Send + Sync {} 327 328 impl Hash for dyn ImageAccess + Send + Sync { 329 #[inline] hash<H: Hasher>(&self, state: &mut H)330 fn hash<H: Hasher>(&self, state: &mut H) { 331 self.inner().hash(state); 332 } 333 } 334 335 /// Wraps around an object that implements `ImageAccess` and modifies the initial layout 336 /// requirement to be either `Undefined` or `Preinitialized`. 337 #[derive(Debug, Copy, Clone)] 338 pub struct ImageAccessFromUndefinedLayout<I> { 339 image: I, 340 preinitialized: bool, 341 } 342 343 unsafe impl<I> ImageAccess for ImageAccessFromUndefinedLayout<I> 344 where 345 I: ImageAccess, 346 { 347 #[inline] inner(&self) -> ImageInner348 fn inner(&self) -> ImageInner { 349 self.image.inner() 350 } 351 352 #[inline] initial_layout_requirement(&self) -> ImageLayout353 fn initial_layout_requirement(&self) -> ImageLayout { 354 if self.preinitialized { 355 ImageLayout::Preinitialized 356 } else { 357 ImageLayout::Undefined 358 } 359 } 360 361 #[inline] final_layout_requirement(&self) -> ImageLayout362 fn final_layout_requirement(&self) -> ImageLayout { 363 self.image.final_layout_requirement() 364 } 365 366 #[inline] descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>367 fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> { 368 self.image.descriptor_layouts() 369 } 370 371 #[inline] conflict_key(&self) -> u64372 fn conflict_key(&self) -> u64 { 373 self.image.conflict_key() 374 } 375 376 #[inline] try_gpu_lock( &self, exclusive_access: bool, uninitialized_safe: bool, expected_layout: ImageLayout, ) -> Result<(), AccessError>377 fn try_gpu_lock( 378 &self, 379 exclusive_access: bool, 380 uninitialized_safe: bool, 381 expected_layout: ImageLayout, 382 ) -> Result<(), AccessError> { 383 self.image 384 .try_gpu_lock(exclusive_access, uninitialized_safe, expected_layout) 385 } 386 387 #[inline] increase_gpu_lock(&self)388 unsafe fn increase_gpu_lock(&self) { 389 self.image.increase_gpu_lock() 390 } 391 392 #[inline] unlock(&self, new_layout: Option<ImageLayout>)393 unsafe fn unlock(&self, new_layout: Option<ImageLayout>) { 394 self.image.unlock(new_layout) 395 } 396 current_miplevels_access(&self) -> std::ops::Range<u32>397 fn current_miplevels_access(&self) -> std::ops::Range<u32> { 398 self.image.current_miplevels_access() 399 } 400 current_layer_levels_access(&self) -> std::ops::Range<u32>401 fn current_layer_levels_access(&self) -> std::ops::Range<u32> { 402 self.image.current_layer_levels_access() 403 } 404 } 405 406 impl<I> PartialEq for ImageAccessFromUndefinedLayout<I> 407 where 408 I: ImageAccess, 409 { 410 #[inline] eq(&self, other: &Self) -> bool411 fn eq(&self, other: &Self) -> bool { 412 self.inner() == other.inner() 413 } 414 } 415 416 impl<I> Eq for ImageAccessFromUndefinedLayout<I> where I: ImageAccess {} 417 418 impl<I> Hash for ImageAccessFromUndefinedLayout<I> 419 where 420 I: ImageAccess, 421 { 422 #[inline] hash<H: Hasher>(&self, state: &mut H)423 fn hash<H: Hasher>(&self, state: &mut H) { 424 self.inner().hash(state); 425 } 426 } 427 428 /// Extension trait for images. Checks whether the value `T` can be used as a clear value for the 429 /// given image. 430 // TODO: isn't that for image views instead? 431 pub unsafe trait ImageClearValue<T>: ImageAccess { decode(&self, value: T) -> Option<ClearValue>432 fn decode(&self, value: T) -> Option<ClearValue>; 433 } 434 435 pub unsafe trait ImageContent<P>: ImageAccess { 436 /// Checks whether pixels of type `P` match the format of the image. matches_format(&self) -> bool437 fn matches_format(&self) -> bool; 438 } 439