Move swapchain and image recreation to the end of the frame (#5388)

Signed-off-by: jiaweig <jiaweig@amazon.com>
monroegm-disable-blank-issue-2
jiaweig 4 years ago committed by GitHub
parent 68ceb9ed94
commit e3b1c4b7d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -75,6 +75,9 @@ namespace AZ
//! Return True if the swap chain prefers exclusive full screen mode and a transition happened, false otherwise.
virtual bool SetExclusiveFullScreenState([[maybe_unused]]bool fullScreenState) { return false; }
//! Recreate the swapchain if it becomes invalid during presenting. This should happen at the end of the frame
//! due to images being used as attachments in the frame graph.
virtual void ProcessRecreation() {};
protected:
SwapChain();
@ -98,6 +101,14 @@ namespace AZ
//////////////////////////////////////////////////////////////////////////
//! Shutdown and clear all the images.
void ShutdownImages();
//! Initialized all the images.
ResultCode InitImages();
//! Flag indicating if swapchain recreation is needed at the end of the frame.
bool m_pendingRecreation = false;
private:
bool ValidateDescriptor(const SwapChainDescriptor& descriptor) const;

@ -134,7 +134,6 @@ namespace AZ
m_scopeAttachmentLookup.clear();
m_imageAttachments.clear();
m_bufferAttachments.clear();
m_swapChainAttachments.clear();
m_importedImageAttachments.clear();
m_importedBufferAttachments.clear();
m_transientImageAttachments.clear();
@ -153,6 +152,13 @@ namespace AZ
delete attachment;
}
m_attachments.clear();
for (auto swapchainAttachment : m_swapChainAttachments)
{
swapchainAttachment->GetSwapChain()->ProcessRecreation();
}
m_swapChainAttachments.clear();
}
ImageDescriptor FrameGraphAttachmentDatabase::GetImageDescriptor(const AttachmentId& attachmentId) const

@ -58,43 +58,68 @@ namespace AZ
// Overwrite descriptor dimensions with the native ones (the ones assigned by the platform) returned by InitInternal.
m_descriptor.m_dimensions = nativeDimensions;
m_images.reserve(m_descriptor.m_dimensions.m_imageCount);
resultCode = InitImages();
}
for (uint32_t imageIdx = 0; imageIdx < m_descriptor.m_dimensions.m_imageCount; ++imageIdx)
{
m_images.emplace_back(RHI::Factory::Get().CreateImage());
}
return resultCode;
}
InitImageRequest request;
void SwapChain::ShutdownImages()
{
// Shutdown existing set of images.
uint32_t imageSize = aznumeric_cast<uint32_t>(m_images.size());
for (uint32_t imageIdx = 0; imageIdx < imageSize; ++imageIdx)
{
m_images[imageIdx]->Shutdown();
}
RHI::ImageDescriptor& imageDescriptor = request.m_descriptor;
imageDescriptor.m_dimension = RHI::ImageDimension::Image2D;
imageDescriptor.m_bindFlags = RHI::ImageBindFlags::Color;
imageDescriptor.m_size.m_width = m_descriptor.m_dimensions.m_imageWidth;
imageDescriptor.m_size.m_height = m_descriptor.m_dimensions.m_imageHeight;
imageDescriptor.m_format = m_descriptor.m_dimensions.m_imageFormat;
m_images.clear();
}
for (uint32_t imageIdx = 0; imageIdx < m_descriptor.m_dimensions.m_imageCount; ++imageIdx)
{
request.m_image = m_images[imageIdx].get();
request.m_imageIndex = imageIdx;
ResultCode SwapChain::InitImages()
{
ResultCode resultCode = ResultCode::Success;
m_images.reserve(m_descriptor.m_dimensions.m_imageCount);
// If the new display mode has more buffers, add them.
for (uint32_t i = 0; i < m_descriptor.m_dimensions.m_imageCount; ++i)
{
m_images.emplace_back(RHI::Factory::Get().CreateImage());
}
InitImageRequest request;
RHI::ImageDescriptor& imageDescriptor = request.m_descriptor;
imageDescriptor.m_dimension = RHI::ImageDimension::Image2D;
imageDescriptor.m_bindFlags = RHI::ImageBindFlags::Color;
imageDescriptor.m_size.m_width = m_descriptor.m_dimensions.m_imageWidth;
imageDescriptor.m_size.m_height = m_descriptor.m_dimensions.m_imageHeight;
imageDescriptor.m_format = m_descriptor.m_dimensions.m_imageFormat;
resultCode = ImagePoolBase::InitImage(
request.m_image,
imageDescriptor,
[this, &request]()
for (uint32_t imageIdx = 0; imageIdx < m_descriptor.m_dimensions.m_imageCount; ++imageIdx)
{
request.m_image = m_images[imageIdx].get();
request.m_imageIndex = imageIdx;
resultCode = ImagePoolBase::InitImage(
request.m_image, imageDescriptor,
[this, &request]()
{
return InitImageInternal(request);
});
if (resultCode != ResultCode::Success)
{
Shutdown();
break;
}
if (resultCode != ResultCode::Success)
{
AZ_Error("Swapchain", false, "Failed to initialize images.");
Shutdown();
break;
}
}
// Reset the current index back to 0 so we match the platform swap chain.
m_currentImageIndex = 0;
return resultCode;
}
@ -105,63 +130,15 @@ namespace AZ
}
ResultCode SwapChain::Resize(const RHI::SwapChainDimensions& dimensions)
{
// Shutdown existing set of images.
for (uint32_t imageIdx = 0; imageIdx < GetImageCount(); ++imageIdx)
{
m_images[imageIdx]->Shutdown();
}
{
ShutdownImages();
SwapChainDimensions nativeDimensions = dimensions;
ResultCode resultCode = ResizeInternal(dimensions, &nativeDimensions);
if (resultCode == ResultCode::Success)
{
m_descriptor.m_dimensions = nativeDimensions;
m_images.reserve(m_descriptor.m_dimensions.m_imageCount);
// If the new display mode has more buffers, add them.
while (m_images.size() < static_cast<size_t>(m_descriptor.m_dimensions.m_imageCount))
{
m_images.emplace_back(RHI::Factory::Get().CreateImage());
}
// If it has fewer, trim down.
while (m_images.size() > static_cast<size_t>(m_descriptor.m_dimensions.m_imageCount))
{
m_images.pop_back();
}
InitImageRequest request;
RHI::ImageDescriptor& imageDescriptor = request.m_descriptor;
imageDescriptor.m_dimension = RHI::ImageDimension::Image2D;
imageDescriptor.m_bindFlags = RHI::ImageBindFlags::Color;
imageDescriptor.m_size.m_width = m_descriptor.m_dimensions.m_imageWidth;
imageDescriptor.m_size.m_height = m_descriptor.m_dimensions.m_imageHeight;
imageDescriptor.m_format = m_descriptor.m_dimensions.m_imageFormat;
for (uint32_t imageIdx = 0; imageIdx < GetImageCount(); ++imageIdx)
{
request.m_image = m_images[imageIdx].get();
request.m_imageIndex = imageIdx;
resultCode = ImagePoolBase::InitImage(
request.m_image,
imageDescriptor,
[this, &request]()
{
return InitImageInternal(request);
});
if (resultCode != ResultCode::Success)
{
Shutdown();
break;
}
}
// Reset the current index back to 0 so we match the platform swap chain.
m_currentImageIndex = 0;
resultCode = InitImages();
}
return resultCode;
@ -188,7 +165,7 @@ namespace AZ
uint32_t SwapChain::GetImageCount() const
{
return static_cast<uint32_t>(m_images.size());
return aznumeric_cast<uint32_t>(m_images.size());
}
uint32_t SwapChain::GetCurrentImageIndex() const
@ -209,8 +186,18 @@ namespace AZ
void SwapChain::Present()
{
AZ_TRACE_METHOD();
m_currentImageIndex = PresentInternal();
AZ_Assert(m_currentImageIndex < m_images.size(), "Invalid image index");
// Due to swapchain recreation, the images are refreshed.
// There is no need to present swapchain for this frame.
const uint32_t imageCount = aznumeric_cast<uint32_t>(m_images.size());
if (imageCount == 0)
{
return;
}
else
{
m_currentImageIndex = PresentInternal();
AZ_Assert(m_currentImageIndex < imageCount, "Invalid image index");
}
}
}
}

@ -59,6 +59,19 @@ namespace AZ
m_swapChainBarrier.m_isValid = true;
}
void SwapChain::ProcessRecreation()
{
if (m_pendingRecreation)
{
ShutdownImages();
InvalidateNativeSwapChain();
CreateSwapchain();
InitImages();
m_pendingRecreation = false;
}
}
void SwapChain::SetVerticalSyncIntervalInternal(uint32_t previousVsyncInterval)
{
if (GetDescriptor().m_verticalSyncInterval == 0 || previousVsyncInterval == 0)
@ -231,8 +244,7 @@ namespace AZ
// VK_SUBOPTIMAL_KHR is treated as success, but we better update the surface info as well.
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
{
InvalidateNativeSwapChain();
CreateSwapchain();
m_pendingRecreation = true;
}
else
{
@ -246,18 +258,16 @@ namespace AZ
}
};
m_presentationQueue->QueueCommand(AZStd::move(presentCommand));
uint32_t acquiredImageIndex = GetCurrentImageIndex();
RHI::ResultCode result = AcquireNewImage(&acquiredImageIndex);
if (result == RHI::ResultCode::Fail)
{
InvalidateNativeSwapChain();
CreateSwapchain();
m_pendingRecreation = true;
return 0;
}
else
{
m_presentationQueue->QueueCommand(AZStd::move(presentCommand));
return acquiredImageIndex;
}
}

@ -51,6 +51,7 @@ namespace AZ
void QueueBarrier(const VkPipelineStageFlags src, const VkPipelineStageFlags dst, const VkImageMemoryBarrier& imageBarrier);
void ProcessRecreation() override;
private:
SwapChain() = default;

Loading…
Cancel
Save