mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 22:34:43 +00:00
Support for VK_KHR_incremental_present (#729)
* Implement support for VK_KHR_incremental_present The public interface is mainly extended by a new function: swapchain::present_incremental * Fix nits from PR * Remove PresentRegion::to_vk * Fix more nitpicks
This commit is contained in:
parent
5e110ae981
commit
3eb2d7a168
@ -181,6 +181,7 @@ pub const STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR: u32 = 1000059007;
|
||||
pub const STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR: u32 = 1000059008;
|
||||
pub const STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN: u32 = 1000062000;
|
||||
pub const STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: u32 = 1000080000;
|
||||
pub const STRUCTURE_TYPE_PRESENT_REGIONS_KHR: u32 = 1000084000;
|
||||
pub const STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR: u32 = 1000085000;
|
||||
pub const STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR: u32 = 1000127000;
|
||||
pub const STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR: u32 = 1000127001;
|
||||
@ -2621,6 +2622,27 @@ pub struct MemoryRequirements2KHR {
|
||||
pub memoryRequirements: MemoryRequirements,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RectLayerKHR {
|
||||
pub offset: Offset2D,
|
||||
pub extent: Extent2D,
|
||||
pub layer: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct PresentRegionKHR {
|
||||
pub rectangleCount: u32,
|
||||
pub pRectangles: *const RectLayerKHR,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct PresentRegionsKHR {
|
||||
pub sType: StructureType,
|
||||
pub pNext: *const c_void,
|
||||
pub swapchainCount: u32,
|
||||
pub pRegions: *const PresentRegionKHR,
|
||||
}
|
||||
|
||||
macro_rules! ptrs {
|
||||
($struct_name:ident, { $($name:ident => ($($param_n:ident: $param_ty:ty),*) -> $ret:ty,)+ }) => (
|
||||
pub struct $struct_name {
|
||||
|
@ -14,7 +14,9 @@ use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
|
||||
use device::DeviceOwned;
|
||||
use device::Queue;
|
||||
use swapchain::PresentRegion;
|
||||
use swapchain::Swapchain;
|
||||
use sync::Semaphore;
|
||||
|
||||
@ -27,11 +29,12 @@ use vk;
|
||||
|
||||
/// Prototype for a submission that presents a swapchain on the screen.
|
||||
// TODO: example here
|
||||
#[derive(Debug)]
|
||||
pub struct SubmitPresentBuilder<'a> {
|
||||
wait_semaphores: SmallVec<[vk::Semaphore; 8]>,
|
||||
swapchains: SmallVec<[vk::SwapchainKHR; 4]>,
|
||||
image_indices: SmallVec<[u32; 4]>,
|
||||
present_regions: SmallVec<[vk::PresentRegionKHR; 4]>,
|
||||
rect_layers: SmallVec<[vk::RectLayerKHR; 4]>,
|
||||
marker: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
@ -43,6 +46,8 @@ impl<'a> SubmitPresentBuilder<'a> {
|
||||
wait_semaphores: SmallVec::new(),
|
||||
swapchains: SmallVec::new(),
|
||||
image_indices: SmallVec::new(),
|
||||
present_regions: SmallVec::new(),
|
||||
rect_layers: SmallVec::new(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -71,6 +76,12 @@ impl<'a> SubmitPresentBuilder<'a> {
|
||||
|
||||
/// Adds an image of a swapchain to be presented.
|
||||
///
|
||||
/// Allows to specify a present region.
|
||||
/// Areas outside the present region *can* be ignored by the Vulkan implementation for
|
||||
/// optimizations purposes.
|
||||
///
|
||||
/// If `VK_KHR_incremental_present` is not enabled, the `present_region` parameter is ignored.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - If you submit this builder, the swapchain must be kept alive until you are
|
||||
@ -79,32 +90,85 @@ impl<'a> SubmitPresentBuilder<'a> {
|
||||
/// - The swapchains and semaphores must all belong to the same device.
|
||||
///
|
||||
#[inline]
|
||||
pub unsafe fn add_swapchain(&mut self, swapchain: &'a Swapchain, image_num: u32) {
|
||||
pub unsafe fn add_swapchain(&mut self, swapchain: &'a Swapchain, image_num: u32,
|
||||
present_region: Option<&'a PresentRegion>) {
|
||||
debug_assert!(image_num < swapchain.num_images());
|
||||
|
||||
if swapchain
|
||||
.device()
|
||||
.loaded_extensions()
|
||||
.khr_incremental_present
|
||||
{
|
||||
let vk_present_region = match present_region {
|
||||
Some(present_region) => {
|
||||
assert!(present_region.is_compatible_with(swapchain));
|
||||
for rectangle in &present_region.rectangles {
|
||||
self.rect_layers.push(rectangle.to_vk());
|
||||
}
|
||||
vk::PresentRegionKHR {
|
||||
rectangleCount: present_region.rectangles.len() as u32,
|
||||
// Set this to null for now; in submit fill it with self.rect_layers
|
||||
pRectangles: ptr::null(),
|
||||
}
|
||||
},
|
||||
None => {
|
||||
vk::PresentRegionKHR {
|
||||
rectangleCount: 0,
|
||||
pRectangles: ptr::null(),
|
||||
}
|
||||
},
|
||||
};
|
||||
self.present_regions.push(vk_present_region);
|
||||
}
|
||||
|
||||
self.swapchains.push(swapchain.internal_object());
|
||||
self.image_indices.push(image_num);
|
||||
}
|
||||
|
||||
|
||||
/// Submits the command. Calls `vkQueuePresentKHR`.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if no swapchain image has been added to the builder.
|
||||
///
|
||||
pub fn submit(self, queue: &Queue) -> Result<(), SubmitPresentError> {
|
||||
pub fn submit(mut self, queue: &Queue) -> Result<(), SubmitPresentError> {
|
||||
unsafe {
|
||||
debug_assert_eq!(self.swapchains.len(), self.image_indices.len());
|
||||
assert!(!self.swapchains.is_empty(),
|
||||
"Tried to submit a present command without any swapchain");
|
||||
|
||||
let vk = queue.device().pointers();
|
||||
let queue = queue.internal_object_guard();
|
||||
let present_regions = {
|
||||
if !self.present_regions.is_empty() {
|
||||
debug_assert!(queue.device().loaded_extensions().khr_incremental_present);
|
||||
debug_assert_eq!(self.swapchains.len(), self.present_regions.len());
|
||||
let mut current_index = 0;
|
||||
for present_region in &mut self.present_regions {
|
||||
present_region.pRectangles = self.rect_layers[current_index ..].as_ptr();
|
||||
current_index += present_region.rectangleCount as usize;
|
||||
}
|
||||
Some(vk::PresentRegionsKHR {
|
||||
sType: vk::STRUCTURE_TYPE_PRESENT_REGIONS_KHR,
|
||||
pNext: ptr::null(),
|
||||
swapchainCount: self.present_regions.len() as u32,
|
||||
pRegions: self.present_regions.as_ptr(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let mut results = vec![mem::uninitialized(); self.swapchains.len()]; // TODO: alloca
|
||||
|
||||
let vk = queue.device().pointers();
|
||||
let queue = queue.internal_object_guard();
|
||||
|
||||
let infos = vk::PresentInfoKHR {
|
||||
sType: vk::STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
pNext: ptr::null(),
|
||||
pNext: present_regions
|
||||
.as_ref()
|
||||
.map(|pr| pr as *const vk::PresentRegionsKHR as *const _)
|
||||
.unwrap_or(ptr::null()),
|
||||
waitSemaphoreCount: self.wait_semaphores.len() as u32,
|
||||
pWaitSemaphores: self.wait_semaphores.as_ptr(),
|
||||
swapchainCount: self.swapchains.len() as u32,
|
||||
@ -125,6 +189,16 @@ impl<'a> SubmitPresentBuilder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for SubmitPresentBuilder<'a> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
fmt.debug_struct("SubmitPresentBuilder")
|
||||
.field("wait_semaphores", &self.wait_semaphores)
|
||||
.field("swapchains", &self.swapchains)
|
||||
.field("image_indices", &self.image_indices)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Error that can happen when submitting the present prototype.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(u32)]
|
||||
|
@ -398,6 +398,7 @@ device_extensions! {
|
||||
khr_maintenance1 => b"VK_KHR_maintenance1",
|
||||
khr_get_memory_requirements2 => b"VK_KHR_get_memory_requirements2",
|
||||
khr_dedicated_allocation => b"VK_KHR_dedicated_allocation",
|
||||
khr_incremental_present => b"VK_KHR_incremental_present",
|
||||
}
|
||||
|
||||
/// Error that can happen when loading the list of layers.
|
||||
|
@ -204,6 +204,8 @@ pub use self::capabilities::SupportedPresentModesIter;
|
||||
pub use self::capabilities::SupportedSurfaceTransforms;
|
||||
pub use self::capabilities::SupportedSurfaceTransformsIter;
|
||||
pub use self::capabilities::SurfaceTransform;
|
||||
pub use self::present_region::PresentRegion;
|
||||
pub use self::present_region::RectangleLayer;
|
||||
pub use self::surface::CapabilitiesError;
|
||||
pub use self::surface::Surface;
|
||||
pub use self::surface::SurfaceCreationError;
|
||||
@ -216,9 +218,11 @@ pub use self::swapchain::SwapchainCreationError;
|
||||
pub use self::swapchain::acquire_next_image;
|
||||
pub use self::swapchain::acquire_next_image_raw;
|
||||
pub use self::swapchain::present;
|
||||
pub use self::swapchain::present_incremental;
|
||||
|
||||
mod capabilities;
|
||||
pub mod display;
|
||||
mod present_region;
|
||||
mod surface;
|
||||
mod swapchain;
|
||||
|
||||
|
64
vulkano/src/swapchain/present_region.rs
Normal file
64
vulkano/src/swapchain/present_region.rs
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2017 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or http://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.
|
||||
use swapchain::Swapchain;
|
||||
use vk;
|
||||
|
||||
/// Represents a region on an image.
|
||||
///
|
||||
/// A region consists of an arbitrary amount of rectangles.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PresentRegion {
|
||||
pub rectangles: Vec<RectangleLayer>,
|
||||
}
|
||||
|
||||
impl PresentRegion {
|
||||
/// Returns true if this present region is compatible with swapchain.
|
||||
pub fn is_compatible_with(&self, swapchain: &Swapchain) -> bool {
|
||||
self.rectangles.iter().all(|rect| rect.is_compatible_with(swapchain))
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a rectangular region on an image layer.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct RectangleLayer {
|
||||
/// Coordinates in pixels of the top-left hand corner of the rectangle.
|
||||
pub offset: [i32; 2],
|
||||
|
||||
/// Dimensions in pixels of the rectangle.
|
||||
pub extent: [u32; 2],
|
||||
|
||||
/// The layer of the image. For images with only one layer, the value of layer must be 0.
|
||||
pub layer: u32,
|
||||
}
|
||||
|
||||
impl RectangleLayer {
|
||||
/// Returns true if this rectangle layer is compatible with swapchain.
|
||||
pub fn is_compatible_with(&self, swapchain: &Swapchain) -> bool {
|
||||
// FIXME negative offset is not disallowed by spec, but semantically should not be possible
|
||||
debug_assert!(self.offset[0] >= 0);
|
||||
debug_assert!(self.offset[1] >= 0);
|
||||
self.offset[0] as u32 + self.extent[0] <= swapchain.dimensions()[0] &&
|
||||
self.offset[1] as u32 + self.extent[1] <= swapchain.dimensions()[1] &&
|
||||
self.layer < swapchain.layers()
|
||||
}
|
||||
|
||||
pub(crate) fn to_vk(&self) -> vk::RectLayerKHR {
|
||||
vk::RectLayerKHR {
|
||||
offset: vk::Offset2D {
|
||||
x: self.offset[0],
|
||||
y: self.offset[1],
|
||||
},
|
||||
extent: vk::Extent2D {
|
||||
width: self.extent[0],
|
||||
height: self.extent[1],
|
||||
},
|
||||
layer: self.layer,
|
||||
}
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@ use swapchain::CapabilitiesError;
|
||||
use swapchain::ColorSpace;
|
||||
use swapchain::CompositeAlpha;
|
||||
use swapchain::PresentMode;
|
||||
use swapchain::PresentRegion;
|
||||
use swapchain::Surface;
|
||||
use swapchain::SurfaceSwapchainLock;
|
||||
use swapchain::SurfaceTransform;
|
||||
@ -118,6 +119,38 @@ pub fn present<F>(swapchain: Arc<Swapchain>, before: F, queue: Arc<Queue>, index
|
||||
queue: queue,
|
||||
swapchain: swapchain,
|
||||
image_id: index,
|
||||
present_region: None,
|
||||
flushed: AtomicBool::new(false),
|
||||
finished: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as `swapchain::present`, except it allows specifying a present region.
|
||||
/// Areas outside the present region may be ignored by vulkan in order to optimize presentation.
|
||||
///
|
||||
/// This is just an optimizaion hint, as the vulkan driver is free to ignore the given present region.
|
||||
///
|
||||
/// If `VK_KHR_incremental_present` is not enabled on the device, the parameter will be ignored.
|
||||
pub fn present_incremental<F>(swapchain: Arc<Swapchain>, before: F, queue: Arc<Queue>, index: usize,
|
||||
present_region: PresentRegion)
|
||||
-> PresentFuture<F>
|
||||
where F: GpuFuture
|
||||
{
|
||||
assert!(index < swapchain.images.len());
|
||||
|
||||
// TODO: restore this check with a dummy ImageAccess implementation
|
||||
/*let swapchain_image = me.images.lock().unwrap().get(index).unwrap().0.upgrade().unwrap(); // TODO: return error instead
|
||||
// Normally if `check_image_access` returns false we're supposed to call the `gpu_access`
|
||||
// function on the image instead. But since we know that this method on `SwapchainImage`
|
||||
// always returns false anyway (by design), we don't need to do it.
|
||||
assert!(before.check_image_access(&swapchain_image, ImageLayout::PresentSrc, true, &queue).is_ok()); // TODO: return error instead*/
|
||||
|
||||
PresentFuture {
|
||||
previous: before,
|
||||
queue: queue,
|
||||
swapchain: swapchain,
|
||||
image_id: index,
|
||||
present_region: Some(present_region),
|
||||
flushed: AtomicBool::new(false),
|
||||
finished: AtomicBool::new(false),
|
||||
}
|
||||
@ -520,6 +553,12 @@ unsafe impl VulkanObject for Swapchain {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl DeviceOwned for Swapchain {
|
||||
fn device(&self) -> &Arc<Device> {
|
||||
&self.device
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Swapchain {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
@ -896,6 +935,7 @@ pub struct PresentFuture<P>
|
||||
queue: Arc<Queue>,
|
||||
swapchain: Arc<Swapchain>,
|
||||
image_id: usize,
|
||||
present_region: Option<PresentRegion>,
|
||||
// True if `flush()` has been called on the future, which means that the present command has
|
||||
// been submitted.
|
||||
flushed: AtomicBool,
|
||||
@ -942,24 +982,24 @@ unsafe impl<P> GpuFuture for PresentFuture<P>
|
||||
Ok(match self.previous.build_submission()? {
|
||||
SubmitAnyBuilder::Empty => {
|
||||
let mut builder = SubmitPresentBuilder::new();
|
||||
builder.add_swapchain(&self.swapchain, self.image_id as u32);
|
||||
builder.add_swapchain(&self.swapchain, self.image_id as u32, self.present_region.as_ref());
|
||||
SubmitAnyBuilder::QueuePresent(builder)
|
||||
},
|
||||
SubmitAnyBuilder::SemaphoresWait(sem) => {
|
||||
let mut builder: SubmitPresentBuilder = sem.into();
|
||||
builder.add_swapchain(&self.swapchain, self.image_id as u32);
|
||||
builder.add_swapchain(&self.swapchain, self.image_id as u32, self.present_region.as_ref());
|
||||
SubmitAnyBuilder::QueuePresent(builder)
|
||||
},
|
||||
SubmitAnyBuilder::CommandBuffer(cb) => {
|
||||
cb.submit(&queue.unwrap())?; // FIXME: wrong because build_submission can be called multiple times
|
||||
let mut builder = SubmitPresentBuilder::new();
|
||||
builder.add_swapchain(&self.swapchain, self.image_id as u32);
|
||||
builder.add_swapchain(&self.swapchain, self.image_id as u32, self.present_region.as_ref());
|
||||
SubmitAnyBuilder::QueuePresent(builder)
|
||||
},
|
||||
SubmitAnyBuilder::BindSparse(cb) => {
|
||||
cb.submit(&queue.unwrap())?; // FIXME: wrong because build_submission can be called multiple times
|
||||
let mut builder = SubmitPresentBuilder::new();
|
||||
builder.add_swapchain(&self.swapchain, self.image_id as u32);
|
||||
builder.add_swapchain(&self.swapchain, self.image_id as u32, self.present_region.as_ref());
|
||||
SubmitAnyBuilder::QueuePresent(builder)
|
||||
},
|
||||
SubmitAnyBuilder::QueuePresent(present) => {
|
||||
|
@ -26,6 +26,7 @@ use image::ImageAccess;
|
||||
use image::ImageLayout;
|
||||
use swapchain;
|
||||
use swapchain::PresentFuture;
|
||||
use swapchain::PresentRegion;
|
||||
use swapchain::Swapchain;
|
||||
use sync::AccessFlagBits;
|
||||
use sync::FenceWaitError;
|
||||
@ -242,6 +243,18 @@ pub unsafe trait GpuFuture: DeviceOwned {
|
||||
{
|
||||
swapchain::present(swapchain, self, queue, image_index)
|
||||
}
|
||||
|
||||
/// Same as `then_swapchain_present`, except it allows specifying a present region.
|
||||
///
|
||||
/// > **Note**: This is just a shortcut for the `Swapchain::present_incremental()` function.
|
||||
#[inline]
|
||||
fn then_swapchain_present_incremental(self, queue: Arc<Queue>, swapchain: Arc<Swapchain>,
|
||||
image_index: usize, present_region: PresentRegion)
|
||||
-> PresentFuture<Self>
|
||||
where Self: Sized
|
||||
{
|
||||
swapchain::present_incremental(swapchain, self, queue, image_index, present_region)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<F: ?Sized> GpuFuture for Box<F>
|
||||
|
Loading…
Reference in New Issue
Block a user