mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-22 14:56:42 +00:00
Fix image layout transitions (#1171)
This commit is contained in:
parent
45e71894af
commit
e7a03b0e1e
@ -510,7 +510,7 @@ impl<P> SyncCommandBufferBuilder<P> {
|
|||||||
// collision. But since the pipeline barrier is going to be submitted before
|
// collision. But since the pipeline barrier is going to be submitted before
|
||||||
// the flushed commands, it would be a mistake if `collision_cmd_id` hasn't
|
// the flushed commands, it would be a mistake if `collision_cmd_id` hasn't
|
||||||
// been flushed yet.
|
// been flushed yet.
|
||||||
if collision_cmd_id >= first_unflushed_cmd_id {
|
if collision_cmd_id >= first_unflushed_cmd_id || entry.current_layout != start_layout {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Flush the pending barrier.
|
// Flush the pending barrier.
|
||||||
self.inner.pipeline_barrier(&self.pending_barrier);
|
self.inner.pipeline_barrier(&self.pending_barrier);
|
||||||
@ -625,6 +625,7 @@ impl<P> SyncCommandBufferBuilder<P> {
|
|||||||
let mut actually_exclusive = exclusive;
|
let mut actually_exclusive = exclusive;
|
||||||
let mut actual_start_layout = start_layout;
|
let mut actual_start_layout = start_layout;
|
||||||
|
|
||||||
|
|
||||||
if !self.is_secondary && resource_ty == KeyTy::Image &&
|
if !self.is_secondary && resource_ty == KeyTy::Image &&
|
||||||
start_layout != ImageLayout::Undefined &&
|
start_layout != ImageLayout::Undefined &&
|
||||||
start_layout != ImageLayout::Preinitialized
|
start_layout != ImageLayout::Preinitialized
|
||||||
@ -633,9 +634,11 @@ impl<P> SyncCommandBufferBuilder<P> {
|
|||||||
let img = commands_lock.commands[latest_command_id].image(resource_index);
|
let img = commands_lock.commands[latest_command_id].image(resource_index);
|
||||||
let initial_layout_requirement = img.initial_layout_requirement();
|
let initial_layout_requirement = img.initial_layout_requirement();
|
||||||
|
|
||||||
if initial_layout_requirement != start_layout {
|
// Checks if the image is initialized and transitions it
|
||||||
actually_exclusive = true;
|
// if it isn't
|
||||||
actual_start_layout = initial_layout_requirement;
|
let is_layout_initialized = img.is_layout_initialized();
|
||||||
|
|
||||||
|
if initial_layout_requirement != start_layout || !is_layout_initialized {
|
||||||
|
|
||||||
// Note that we transition from `bottom_of_pipe`, which means that we
|
// Note that we transition from `bottom_of_pipe`, which means that we
|
||||||
// wait for all the previous commands to be entirely finished. This is
|
// wait for all the previous commands to be entirely finished. This is
|
||||||
@ -648,6 +651,19 @@ impl<P> SyncCommandBufferBuilder<P> {
|
|||||||
// suboptimal in some cases, in the general situation it will be ok.
|
// suboptimal in some cases, in the general situation it will be ok.
|
||||||
//
|
//
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let from_layout = if is_layout_initialized {
|
||||||
|
actually_exclusive = true;
|
||||||
|
initial_layout_requirement
|
||||||
|
} else {
|
||||||
|
if img.preinitialized_layout() {
|
||||||
|
ImageLayout::Preinitialized
|
||||||
|
} else {
|
||||||
|
ImageLayout::Undefined
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if initial_layout_requirement != start_layout {
|
||||||
|
actual_start_layout = initial_layout_requirement;
|
||||||
|
}
|
||||||
let b = &mut self.pending_barrier;
|
let b = &mut self.pending_barrier;
|
||||||
b.add_image_memory_barrier(img,
|
b.add_image_memory_barrier(img,
|
||||||
0 .. img.mipmap_levels(),
|
0 .. img.mipmap_levels(),
|
||||||
@ -661,8 +677,9 @@ impl<P> SyncCommandBufferBuilder<P> {
|
|||||||
access,
|
access,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
initial_layout_requirement,
|
from_layout,
|
||||||
start_layout);
|
start_layout);
|
||||||
|
img.layout_initialized();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -312,18 +312,6 @@ macro_rules! ordered_passes_renderpass {
|
|||||||
})*
|
})*
|
||||||
|
|
||||||
$(if $atch_name == num {
|
$(if $atch_name == num {
|
||||||
// If the clear OP is Clear or DontCare, default to the Undefined layout.
|
|
||||||
if initial_layout == Some(ImageLayout::DepthStencilAttachmentOptimal) ||
|
|
||||||
initial_layout == Some(ImageLayout::ColorAttachmentOptimal) ||
|
|
||||||
initial_layout == Some(ImageLayout::TransferDstOptimal)
|
|
||||||
{
|
|
||||||
if $crate::framebuffer::LoadOp::$load == $crate::framebuffer::LoadOp::Clear ||
|
|
||||||
$crate::framebuffer::LoadOp::$load == $crate::framebuffer::LoadOp::DontCare
|
|
||||||
{
|
|
||||||
initial_layout = Some(ImageLayout::Undefined);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$(initial_layout = Some($init_layout);)*
|
$(initial_layout = Some($init_layout);)*
|
||||||
$(final_layout = Some($final_layout);)*
|
$(final_layout = Some($final_layout);)*
|
||||||
})*
|
})*
|
||||||
|
@ -497,6 +497,16 @@ unsafe impl<F, A> ImageAccess for AttachmentImage<F, A>
|
|||||||
let prev_val = self.gpu_lock.fetch_sub(1, Ordering::SeqCst);
|
let prev_val = self.gpu_lock.fetch_sub(1, Ordering::SeqCst);
|
||||||
debug_assert!(prev_val >= 1);
|
debug_assert!(prev_val >= 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn layout_initialized(&self) {
|
||||||
|
self.initialized.store(true, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_layout_initialized(&self) -> bool {
|
||||||
|
self.initialized.load(Ordering::SeqCst)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<F, A> ImageClearValue<F::ClearValue> for Arc<AttachmentImage<F, A>>
|
unsafe impl<F, A> ImageClearValue<F::ClearValue> for Arc<AttachmentImage<F, A>>
|
||||||
|
@ -82,6 +82,16 @@ impl<W> SwapchainImage<W> {
|
|||||||
fn my_image(&self) -> ImageInner {
|
fn my_image(&self) -> ImageInner {
|
||||||
self.swapchain.raw_image(self.image_offset).unwrap()
|
self.swapchain.raw_image(self.image_offset).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn layout_initialized(&self) {
|
||||||
|
self.swapchain.image_layout_initialized(self.image_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_layout_initialized(&self) -> bool {
|
||||||
|
self.swapchain.is_image_layout_initialized(self.image_offset)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<W> ImageAccess for SwapchainImage<W> {
|
unsafe impl<W> ImageAccess for SwapchainImage<W> {
|
||||||
@ -121,6 +131,16 @@ unsafe impl<W> ImageAccess for SwapchainImage<W> {
|
|||||||
Err(AccessError::SwapchainImageAcquireOnly)
|
Err(AccessError::SwapchainImageAcquireOnly)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn layout_initialized(&self) {
|
||||||
|
self.layout_initialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_layout_initialized(&self) -> bool{
|
||||||
|
self.is_layout_initialized()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn increase_gpu_lock(&self) {
|
unsafe fn increase_gpu_lock(&self) {
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,7 @@ pub struct UnsafeImage {
|
|||||||
|
|
||||||
// `vkDestroyImage` is called only if `needs_destruction` is true.
|
// `vkDestroyImage` is called only if `needs_destruction` is true.
|
||||||
needs_destruction: bool,
|
needs_destruction: bool,
|
||||||
|
preinitialized_layout: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnsafeImage {
|
impl UnsafeImage {
|
||||||
@ -551,6 +552,7 @@ impl UnsafeImage {
|
|||||||
mipmaps: mipmaps,
|
mipmaps: mipmaps,
|
||||||
format_features: format_features,
|
format_features: format_features,
|
||||||
needs_destruction: true,
|
needs_destruction: true,
|
||||||
|
preinitialized_layout,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((image, mem_reqs))
|
Ok((image, mem_reqs))
|
||||||
@ -580,6 +582,7 @@ impl UnsafeImage {
|
|||||||
mipmaps: mipmaps,
|
mipmaps: mipmaps,
|
||||||
format_features: output.optimalTilingFeatures,
|
format_features: output.optimalTilingFeatures,
|
||||||
needs_destruction: false, // TODO: pass as parameter
|
needs_destruction: false, // TODO: pass as parameter
|
||||||
|
preinitialized_layout: false, // TODO: Maybe this should be passed in?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -778,6 +781,11 @@ impl UnsafeImage {
|
|||||||
pub fn usage_input_attachment(&self) -> bool {
|
pub fn usage_input_attachment(&self) -> bool {
|
||||||
(self.usage & vk::IMAGE_USAGE_INPUT_ATTACHMENT_BIT) != 0
|
(self.usage & vk::IMAGE_USAGE_INPUT_ATTACHMENT_BIT) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn preinitialized_layout(&self) -> bool {
|
||||||
|
self.preinitialized_layout
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl VulkanObject for UnsafeImage {
|
unsafe impl VulkanObject for UnsafeImage {
|
||||||
|
@ -92,6 +92,27 @@ pub unsafe trait ImageAccess {
|
|||||||
self.inner().image.supports_blit_destination()
|
self.inner().image.supports_blit_destination()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// When images are created their memory layout is initially `Undefined` or `Preinitialized`.
|
||||||
|
/// This method allows the image memory barrier creation process to signal when an image
|
||||||
|
/// has been transitioned out of its initial `Undefined` or `Preinitialized` state. This
|
||||||
|
/// allows vulkano to avoid creating unnecessary image memory barriers between future
|
||||||
|
/// uses of the image.
|
||||||
|
///
|
||||||
|
/// ## Unsafe
|
||||||
|
///
|
||||||
|
/// If a user calls this method outside of the intended context and signals that the layout
|
||||||
|
/// is no longer `Undefined` or `Preinitialized` when it is still in an `Undefined` or
|
||||||
|
/// `Preinitialized` state, this may result in the vulkan implementation attempting to use
|
||||||
|
/// an image in an invalid layout. The same problem must be considered by the implementer
|
||||||
|
/// of the method.
|
||||||
|
unsafe fn layout_initialized(&self) {}
|
||||||
|
|
||||||
|
fn is_layout_initialized(&self) -> bool {false}
|
||||||
|
|
||||||
|
unsafe fn preinitialized_layout(&self) -> bool {
|
||||||
|
self.inner().image.preinitialized_layout()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the layout that the image has when it is first used in a primary command buffer.
|
/// Returns the layout that the image has when it is first used in a primary command buffer.
|
||||||
///
|
///
|
||||||
/// The first time you use an image in an `AutoCommandBufferBuilder`, vulkano will suppose that
|
/// The first time you use an image in an `AutoCommandBufferBuilder`, vulkano will suppose that
|
||||||
@ -277,6 +298,16 @@ unsafe impl<T> ImageAccess for T
|
|||||||
unsafe fn unlock(&self, transitioned_layout: Option<ImageLayout>) {
|
unsafe fn unlock(&self, transitioned_layout: Option<ImageLayout>) {
|
||||||
(**self).unlock(transitioned_layout)
|
(**self).unlock(transitioned_layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn layout_initialized(&self) {
|
||||||
|
(**self).layout_initialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_layout_initialized(&self) -> bool {
|
||||||
|
(**self).is_layout_initialized()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps around an object that implements `ImageAccess` and modifies the initial layout
|
/// Wraps around an object that implements `ImageAccess` and modifies the initial layout
|
||||||
|
@ -555,6 +555,24 @@ impl <W> Swapchain<W> {
|
|||||||
pub fn clipped(&self) -> bool {
|
pub fn clipped(&self) -> bool {
|
||||||
self.clipped
|
self.clipped
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This method is necessary to allow `SwapchainImage`s to signal when they have been
|
||||||
|
// transitioned out of their initial `undefined` image layout.
|
||||||
|
//
|
||||||
|
// See the `ImageAccess::layout_initialized` method documentation for more details.
|
||||||
|
pub(crate) fn image_layout_initialized(&self, image_offset: usize) {
|
||||||
|
let image_entry = self.images.get(image_offset);
|
||||||
|
if let Some(ref image_entry) = image_entry {
|
||||||
|
image_entry.undefined_layout.store(false, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_image_layout_initialized(&self, image_offset: usize) -> bool {
|
||||||
|
let image_entry = self.images.get(image_offset);
|
||||||
|
if let Some(ref image_entry) = image_entry {
|
||||||
|
!image_entry.undefined_layout.load(Ordering::SeqCst)
|
||||||
|
} else { false }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<W> VulkanObject for Swapchain<W> {
|
unsafe impl<W> VulkanObject for Swapchain<W> {
|
||||||
|
Loading…
Reference in New Issue
Block a user