ATOM-16625 [RHI][Vulkan] Swapchain creation issue on viewports (#4854)

* Refactor Vulkan swapchain so it can recreate when error occurs

Signed-off-by: jiaweig <jiaweig@amazon.com>

* revert the workaround

Signed-off-by: jiaweig <jiaweig@amazon.com>

* Move semaphore. Revert some viewport changes.

Signed-off-by: jiaweig <jiaweig@amazon.com>

* Added comments. Moved recreation out of AcquireNewImage.

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

@ -14,92 +14,86 @@ namespace AZ
{
namespace RHI
{
/**
* The platform-independent swap chain base class. Swap chains contain a "chain" of images which
* map to a platform-specific window, displayed on a physical monitor. The user is allowed
* to adjust the swap chain outside of the current FrameScheduler frame. Doing so within a frame scheduler
* frame results in undefined behavior.
*
* The frame scheduler controls presentation of the swap chain. The user may attach a swap chain to a scope
* in order to render to the current image.
*/
//! The platform-independent swap chain base class. Swap chains contain a "chain" of images which
//! map to a platform-specific window, displayed on a physical monitor. The user is allowed
//! to adjust the swap chain outside of the current FrameScheduler frame. Doing so within a frame scheduler
//! frame results in undefined behavior.
//!
//! The frame scheduler controls presentation of the swap chain. The user may attach a swap chain to a scope
//! in order to render to the current image.
class SwapChain
: public ImagePoolBase
{
public:
AZ_RTTI(SwapChain, "{888B64A5-D956-406F-9C33-CF6A54FC41B0}", Object);
virtual ~SwapChain();
/// Initializes the swap chain, making it ready for attachment.
//! Initializes the swap chain, making it ready for attachment.
ResultCode Init(RHI::Device& device, const SwapChainDescriptor& descriptor);
/// Presents the swap chain to the display, and rotates the images.
//! Presents the swap chain to the display, and rotates the images.
void Present();
/**
* Sets the vertical sync interval for the swap chain.
* 0 - No vsync.
* N - Sync to every N vertical refresh.
*
* A value of 1 syncs to the refresh rate of the monitor.
*/
//! Sets the vertical sync interval for the swap chain.
//! 0 - No vsync.
//! N - Sync to every N vertical refresh.
//!
//! A value of 1 syncs to the refresh rate of the monitor.
void SetVerticalSyncInterval(uint32_t verticalSyncInterval);
/**
* Resizes the display resolution of the swap chain. Ideally, this matches the platform window
* resolution. Typically, the resize operation will occur in reaction to a platform window size
* change. Takes effect immediately and results in a GPU pipeline flush.
*/
//! Resizes the display resolution of the swap chain. Ideally, this matches the platform window
//! resolution. Typically, the resize operation will occur in reaction to a platform window size
//! change. Takes effect immediately and results in a GPU pipeline flush.
ResultCode Resize(const SwapChainDimensions& dimensions);
/// Returns the number of images in the swap chain.
//! Returns the number of images in the swap chain.
uint32_t GetImageCount() const;
/// Returns the current image index of the swap chain.
//! Returns the current image index of the swap chain.
uint32_t GetCurrentImageIndex() const;
/// Returns the current image of the swap chain.
//! Returns the current image of the swap chain.
Image* GetCurrentImage() const;
/// Returns the image associated with the provided index, where the total number of images
/// is given by GetImageCount().
//! Returns the image associated with the provided index, where the total number of images
//! is given by GetImageCount().
Image* GetImage(uint32_t index) const;
/// Returns the ID used for the SwapChain's attachment
//! Returns the ID used for the SwapChain's attachment
const AttachmentId& GetAttachmentId() const;
/// Returns the descriptor provided when initializing the swap chain.
//! Returns the descriptor provided when initializing the swap chain.
const RHI::SwapChainDescriptor& GetDescriptor() const override final;
//! \return True if the swap chain prefers to use exclusive full screen mode.
//! Returns True if the swap chain prefers to use exclusive full screen mode.
virtual bool IsExclusiveFullScreenPreferred() const { return false; }
//! \return True if the swap chain prefers exclusive full screen mode and it is currently true, false otherwise.
//! Returns True if the swap chain prefers exclusive full screen mode and it is currently true, false otherwise.
virtual bool GetExclusiveFullScreenState() const { return false; }
//! \return True if the swap chain prefers exclusive full screen mode and a transition happened, false otherwise.
//! 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; }
AZ_RTTI(SwapChain, "{888B64A5-D956-406F-9C33-CF6A54FC41B0}", Object);
protected:
SwapChain();
struct InitImageRequest
{
/// Pointer to the image to initialize.
//! Pointer to the image to initialize.
Image* m_image = nullptr;
/// Index of the image in the swap chain.
//! Index of the image in the swap chain.
uint32_t m_imageIndex = 0;
/// Descriptor for the image.
//! Descriptor for the image.
ImageDescriptor m_descriptor;
};
//////////////////////////////////////////////////////////////////////////
// ResourcePool Overrides
/// Called when the pool is shutting down.
//! Called when the pool is shutting down.
void ShutdownInternal() override;
//////////////////////////////////////////////////////////////////////////
@ -111,32 +105,29 @@ namespace AZ
//////////////////////////////////////////////////////////////////////////
// Platform API
/// Called when the swap chain is initializing.
//! Called when the swap chain is initializing.
virtual ResultCode InitInternal(RHI::Device& device, const SwapChainDescriptor& descriptor, SwapChainDimensions* nativeDimensions) = 0;
/// called when the swap chain is initializing an image.
//! called when the swap chain is initializing an image.
virtual ResultCode InitImageInternal(const InitImageRequest& request) = 0;
/// Called when the swap chain is resizing.
//! Called when the swap chain is resizing.
virtual ResultCode ResizeInternal(const SwapChainDimensions& dimensions, SwapChainDimensions* nativeDimensions) = 0;
/// Called when the swap chain is presenting the currently swap image.
/// Returns the index of the current image after the swap.
//! Called when the swap chain is presenting the currently swap image.
//! Returns the index of the current image after the swap.
virtual uint32_t PresentInternal() = 0;
virtual void SetVerticalSyncIntervalInternal(uint32_t previousVerticalSyncInterval)
{
AZ_UNUSED(previousVerticalSyncInterval);
}
virtual void SetVerticalSyncIntervalInternal([[maybe_unused]]uint32_t previousVerticalSyncInterval) {}
//////////////////////////////////////////////////////////////////////////
SwapChainDescriptor m_descriptor;
/// Images corresponding to each image in the swap chain.
//! Images corresponding to each image in the swap chain.
AZStd::vector<Ptr<Image>> m_images;
/// The current image index.
//! The current image index.
uint32_t m_currentImageIndex = 0;
};
}

@ -55,7 +55,7 @@ namespace AZ
if (resultCode == ResultCode::Success)
{
m_descriptor = descriptor;
// Ovewrite descriptor dimensions with the native ones (the ones assigned by the platform) returned by InitInternal.
// 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);

@ -61,13 +61,12 @@ namespace AZ
void SwapChain::SetVerticalSyncIntervalInternal(uint32_t previousVsyncInterval)
{
uint32_t verticalSyncInterval = GetDescriptor().m_verticalSyncInterval;
if (verticalSyncInterval == 0 || previousVsyncInterval == 0)
if (GetDescriptor().m_verticalSyncInterval == 0 || previousVsyncInterval == 0)
{
// The presentation mode may change when transitioning to or from a vsynced presentation mode
// In this case, the swapchain must be recreated.
InvalidateNativeSwapChain();
BuildNativeSwapChain(GetDescriptor().m_dimensions, verticalSyncInterval);
CreateSwapchain();
}
}
@ -85,46 +84,21 @@ namespace AZ
RHI::DeviceObject::Init(baseDevice);
auto& device = static_cast<Device&>(GetDevice());
RHI::SwapChainDimensions swapchainDimensions = descriptor.m_dimensions;
m_dimensions = descriptor.m_dimensions;
result = BuildSurface(descriptor);
RETURN_RESULT_IF_UNSUCCESSFUL(result);
if (!ValidateSurfaceDimensions(swapchainDimensions))
{
swapchainDimensions.m_imageHeight = AZStd::clamp(swapchainDimensions.m_imageHeight, m_surfaceCapabilities.minImageExtent.height, m_surfaceCapabilities.maxImageExtent.height);
swapchainDimensions.m_imageWidth = AZStd::clamp(swapchainDimensions.m_imageWidth, m_surfaceCapabilities.minImageExtent.width, m_surfaceCapabilities.maxImageExtent.width);
AZ_Printf("Vulkan", "Resizing swapchain from (%d, %d) to (%d, %d).",
static_cast<int>(descriptor.m_dimensions.m_imageWidth), static_cast<int>(descriptor.m_dimensions.m_imageHeight),
static_cast<int>(swapchainDimensions.m_imageWidth), static_cast<int>(swapchainDimensions.m_imageHeight));
}
auto& presentationQueue = device.GetCommandQueueContext().GetOrCreatePresentationCommandQueue(*this);
m_presentationQueue = &presentationQueue;
result = BuildNativeSwapChain(swapchainDimensions, descriptor.m_verticalSyncInterval);
RETURN_RESULT_IF_UNSUCCESSFUL(result);
uint32_t imageCount = 0;
VkResult vkResult = vkGetSwapchainImagesKHR(device.GetNativeDevice(), m_nativeSwapChain, &imageCount, nullptr);
AssertSuccess(vkResult);
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(vkResult));
m_swapchainNativeImages.resize(imageCount);
// Retrieve the native images of the swapchain so they are
// available when we init the Images in InitImageInternal
vkResult = vkGetSwapchainImagesKHR(device.GetNativeDevice(), m_nativeSwapChain, &imageCount, m_swapchainNativeImages.data());
AssertSuccess(vkResult);
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(vkResult));
// Acquire the first image
uint32_t imageIndex = 0;
result = AcquireNewImage(&imageIndex);
result = CreateSwapchain();
RETURN_RESULT_IF_UNSUCCESSFUL(result);
if (nativeDimensions)
{
// Fill out the real swapchain dimensions to return
nativeDimensions->m_imageCount = imageCount;
nativeDimensions->m_imageHeight = swapchainDimensions.m_imageHeight;
nativeDimensions->m_imageWidth = swapchainDimensions.m_imageWidth;
*nativeDimensions = m_dimensions;
nativeDimensions->m_imageFormat = ConvertFormat(m_surfaceFormat.format);
}
@ -165,51 +139,24 @@ namespace AZ
RHI::ResultCode SwapChain::ResizeInternal(const RHI::SwapChainDimensions& dimensions, RHI::SwapChainDimensions* nativeDimensions)
{
auto& device = static_cast<Device&>(GetDevice());
m_dimensions = dimensions;
InvalidateNativeSwapChain();
InvalidateSurface();
RHI::SwapChainDimensions resizeDimensions = dimensions;
BuildSurface(GetDescriptor());
if (!ValidateSurfaceDimensions(dimensions))
{
resizeDimensions.m_imageHeight = AZStd::clamp(dimensions.m_imageHeight, m_surfaceCapabilities.minImageExtent.height, m_surfaceCapabilities.maxImageExtent.height);
resizeDimensions.m_imageWidth = AZStd::clamp(dimensions.m_imageWidth, m_surfaceCapabilities.minImageExtent.width, m_surfaceCapabilities.maxImageExtent.width);
AZ_Printf("Vulkan", "Resizing swapchain from (%d, %d) to (%d, %d).",
static_cast<int>(dimensions.m_imageWidth), static_cast<int>(dimensions.m_imageHeight),
static_cast<int>(resizeDimensions.m_imageWidth), static_cast<int>(resizeDimensions.m_imageHeight));
}
auto& presentationQueue = device.GetCommandQueueContext().GetOrCreatePresentationCommandQueue(*this);
m_presentationQueue = &presentationQueue;
BuildNativeSwapChain(resizeDimensions, GetDescriptor().m_verticalSyncInterval);
resizeDimensions.m_imageCount = 0;
VkResult vkResult = vkGetSwapchainImagesKHR(device.GetNativeDevice(), m_nativeSwapChain, &resizeDimensions.m_imageCount, nullptr);
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(vkResult));
m_swapchainNativeImages.resize(resizeDimensions.m_imageCount);
// Retrieve the native images of the swapchain so they are
// available when we init the Images in InitImageInternal
vkResult = vkGetSwapchainImagesKHR(device.GetNativeDevice(), m_nativeSwapChain, &resizeDimensions.m_imageCount, m_swapchainNativeImages.data());
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(vkResult));
// Do not recycle the semaphore because they may not ever get signaled and since
// we can't recycle Vulkan semaphores we just delete them.
m_currentFrameContext.m_imageAvailableSemaphore->SetRecycleValue(false);
m_currentFrameContext.m_presentableSemaphore->SetRecycleValue(false);
// Acquire the first image
uint32_t imageIndex = 0;
AcquireNewImage(&imageIndex);
CreateSwapchain();
if (nativeDimensions)
{
*nativeDimensions = resizeDimensions;
*nativeDimensions = m_dimensions;
// [ATOM-4840] This is a workaround when the windows is minimized (0x0 size).
// Add proper support to handle this case.
nativeDimensions->m_imageHeight = AZStd::max(resizeDimensions.m_imageHeight, 1u);
nativeDimensions->m_imageWidth = AZStd::max(resizeDimensions.m_imageWidth, 1u);
nativeDimensions->m_imageHeight = AZStd::max(m_dimensions.m_imageHeight, 1u);
nativeDimensions->m_imageWidth = AZStd::max(m_dimensions.m_imageWidth, 1u);
nativeDimensions->m_imageFormat = ConvertFormat(m_surfaceFormat.format);
}
return RHI::ResultCode::Success;
@ -271,21 +218,49 @@ namespace AZ
info.pImageIndices = &imageIndex;
info.pResults = nullptr;
[[maybe_unused]] const VkResult result = vkQueuePresentKHR(vulkanQueue->GetNativeQueue(), &info);
const VkResult result = vkQueuePresentKHR(vulkanQueue->GetNativeQueue(), &info);
// Resizing window cause recreation of SwapChain after calling this method,
// so VK_SUBOPTIMAL_KHR or VK_ERROR_OUT_OF_DATE_KHR should not happen at this point.
AZ_Assert(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR, "Failed to present swapchain %s", GetName().GetCStr());
AZ_Warning("Vulkan", result != VK_SUBOPTIMAL_KHR, "Suboptimal presentation of swapchain %s", GetName().GetCStr());
// Vulkan's definition of the two types of errors.
// VK_ERROR_OUT_OF_DATE_KHR: "A surface has changed in such a way that it is no longer compatible with the swapchain,
// and further presentation requests using the swapchain will fail. Applications must query the new surface
// properties and recreate their swapchain if they wish to continue presenting to the surface."
// VK_SUBOPTIMAL_KHR: "A swapchain no longer matches the surface properties exactly, but can still be used to
// present to the surface successfully."
//
// These result values may occur after resizing or some window operation. We should update the surface info and recreate the swapchain.
// 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();
}
else
{
// Other errors are:
// VK_ERROR_OUT_OF_HOST_MEMORY
// VK_ERROR_OUT_OF_DEVICE_MEMORY
// VK_ERROR_DEVICE_LOST
// VK_ERROR_SURFACE_LOST_KHR
// VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT
AZ_Assert(result == VK_SUCCESS, "Unhandled error for swapchain presentation.");
}
};
m_presentationQueue->QueueCommand(AZStd::move(presentCommand));
uint32_t acquiredImageIndex = GetCurrentImageIndex();
AcquireNewImage(&acquiredImageIndex);
RHI::ResultCode result = AcquireNewImage(&acquiredImageIndex);
if (result == RHI::ResultCode::Fail)
{
InvalidateNativeSwapChain();
CreateSwapchain();
return 0;
}
else
{
return acquiredImageIndex;
}
}
RHI::ResultCode SwapChain::BuildSurface(const RHI::SwapChainDescriptor& descriptor)
{
@ -293,15 +268,8 @@ namespace AZ
surfaceDesc.m_windowHandle = descriptor.m_window;
RHI::Ptr<WSISurface> surface = WSISurface::Create();
const RHI::ResultCode result = surface->Init(surfaceDesc);
if (result == RHI::ResultCode::Success)
{
RETURN_RESULT_IF_UNSUCCESSFUL(result);
m_surface = surface;
auto& device = static_cast<Device&>(GetDevice());
const auto& physicalDevice = static_cast<const PhysicalDevice&>(device.GetPhysicalDevice());
VkResult vkResult = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice.GetNativePhysicalDevice(), m_surface->GetNativeSurface(), &m_surfaceCapabilities);
AssertSuccess(vkResult);
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(vkResult));
}
return result;
}
@ -373,6 +341,21 @@ namespace AZ
return supportedModes[0];
}
VkSurfaceCapabilitiesKHR SwapChain::GetSurfaceCapabilities()
{
AZ_Assert(m_surface, "Surface has not been initialized.");
auto& device = static_cast<Device&>(GetDevice());
const auto& physicalDevice = static_cast<const PhysicalDevice&>(device.GetPhysicalDevice());
VkSurfaceCapabilitiesKHR surfaceCapabilities;
VkResult vkResult = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
physicalDevice.GetNativePhysicalDevice(), m_surface->GetNativeSurface(), &surfaceCapabilities);
AssertSuccess(vkResult);
return surfaceCapabilities;
}
VkCompositeAlphaFlagBitsKHR SwapChain::GetSupportedCompositeAlpha() const
{
VkFlags supportedModesBits = m_surfaceCapabilities.supportedCompositeAlpha;
@ -394,15 +377,9 @@ namespace AZ
return VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
}
RHI::ResultCode SwapChain::BuildNativeSwapChain(const RHI::SwapChainDimensions& dimensions, uint32_t verticalSyncInterval)
RHI::ResultCode SwapChain::BuildNativeSwapChain(const RHI::SwapChainDimensions& dimensions)
{
AZ_Assert(m_nativeSwapChain == VK_NULL_HANDLE, "Vulkan's native SwapChain has been initialized already.");
auto& device = static_cast<Device&>(GetDevice());
auto& queueContext = device.GetCommandQueueContext();
const VkExtent2D extent = {
dimensions.m_imageWidth,
dimensions.m_imageHeight
};
AZ_Assert(m_surface, "Surface is null.");
if (!ValidateSurfaceDimensions(dimensions))
@ -410,7 +387,11 @@ namespace AZ
AZ_Assert(false, "Swapchain dimensions are not supported.");
return RHI::ResultCode::InvalidArgument;
}
m_surfaceFormat = GetSupportedSurfaceFormat(dimensions.m_imageFormat);
auto& device = static_cast<Vulkan::Device&>(GetDevice());
auto& queueContext = device.GetCommandQueueContext();
const VkExtent2D extent = { dimensions.m_imageWidth, dimensions.m_imageHeight };
// If the graphic queue is the same as the presentation queue, then we will always acquire
// 1 image at the same time. If it's another queue, we will have 2 at the same time (while the other queue
// presents the image)
@ -441,11 +422,11 @@ namespace AZ
createInfo.imageArrayLayers = 1; // non-stereoscopic
createInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = static_cast<uint32_t>(familyIndices.size());
createInfo.queueFamilyIndexCount = aznumeric_cast<uint32_t>(familyIndices.size());
createInfo.pQueueFamilyIndices = familyIndices.empty() ? nullptr : familyIndices.data();
createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
createInfo.compositeAlpha = GetSupportedCompositeAlpha();
createInfo.presentMode = GetSupportedPresentMode(verticalSyncInterval);
createInfo.compositeAlpha = m_compositeAlphaFlagBits;
createInfo.presentMode = m_presentMode;
createInfo.clipped = VK_FALSE;
createInfo.oldSwapchain = VK_NULL_HANDLE;
@ -467,9 +448,6 @@ namespace AZ
VK_NULL_HANDLE,
acquiredImageIndex);
// Resizing window cause recreation of SwapChain before calling this method,
// so VK_SUBOPTIMAL_KHR or VK_ERROR_OUT_OF_DATE_KHR should not happen.
AssertSuccess(vkResult);
RHI::ResultCode result = ConvertResult(vkResult);
RETURN_RESULT_IF_UNSUCCESSFUL(result);
@ -484,6 +462,7 @@ namespace AZ
}
m_currentFrameContext.m_imageAvailableSemaphore = imageAvailableSemaphore;
m_currentFrameContext.m_presentableSemaphore = semaphoreAllocator.Allocate();
return result;
}
@ -502,5 +481,70 @@ namespace AZ
m_nativeSwapChain = VK_NULL_HANDLE;
}
}
RHI::ResultCode SwapChain::CreateSwapchain()
{
auto& device = static_cast<Device&>(GetDevice());
m_surfaceCapabilities = GetSurfaceCapabilities();
m_surfaceFormat = GetSupportedSurfaceFormat(GetDescriptor().m_dimensions.m_imageFormat);
m_presentMode = GetSupportedPresentMode(GetDescriptor().m_verticalSyncInterval);
m_compositeAlphaFlagBits = GetSupportedCompositeAlpha();
if (!ValidateSurfaceDimensions(m_dimensions))
{
uint32_t oldHeight = m_dimensions.m_imageHeight;
uint32_t oldWidth = m_dimensions.m_imageWidth;
m_dimensions.m_imageHeight = AZStd::clamp(
m_dimensions.m_imageHeight,
m_surfaceCapabilities.minImageExtent.height,
m_surfaceCapabilities.maxImageExtent.height);
m_dimensions.m_imageWidth = AZStd::clamp(
m_dimensions.m_imageWidth,
m_surfaceCapabilities.minImageExtent.width,
m_surfaceCapabilities.maxImageExtent.width);
AZ_Printf(
"Vulkan", "Resizing swapchain from (%u, %u) to (%u, %u).",
oldWidth, oldHeight, m_dimensions.m_imageWidth, m_dimensions.m_imageHeight);
}
RHI::ResultCode result = BuildNativeSwapChain(m_dimensions);
RETURN_RESULT_IF_UNSUCCESSFUL(result);
AZ_TracePrintf("Swapchain", "Swapchain created. Width: %u, Height: %u.", m_dimensions.m_imageWidth, m_dimensions.m_imageHeight);
// Do not recycle the semaphore because they may not ever get signaled and since
// we can't recycle Vulkan semaphores we just delete them.
if (m_currentFrameContext.m_imageAvailableSemaphore)
{
m_currentFrameContext.m_imageAvailableSemaphore->SetRecycleValue(false);
}
if (m_currentFrameContext.m_presentableSemaphore)
{
m_currentFrameContext.m_presentableSemaphore->SetRecycleValue(false);
}
m_dimensions.m_imageCount = 0;
VkResult vkResult = vkGetSwapchainImagesKHR(device.GetNativeDevice(), m_nativeSwapChain, &m_dimensions.m_imageCount, nullptr);
AssertSuccess(vkResult);
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(vkResult));
m_swapchainNativeImages.resize(m_dimensions.m_imageCount);
// Retrieve the native images of the swapchain so they are
// available when we init the images in InitImageInternal
vkResult = vkGetSwapchainImagesKHR(
device.GetNativeDevice(), m_nativeSwapChain, &m_dimensions.m_imageCount, m_swapchainNativeImages.data());
AssertSuccess(vkResult);
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(vkResult));
AZ_TracePrintf("Swapchain", "Obtained presentable images.");
// Acquire the first image
uint32_t imageIndex = 0;
result = AcquireNewImage(&imageIndex);
RETURN_RESULT_IF_UNSUCCESSFUL(result);
AZ_TracePrintf("Swapchain", "Acquired the first image.");
return RHI::ResultCode::Success;
}
}
}

@ -70,24 +70,48 @@ namespace AZ
//////////////////////////////////////////////////////////////////////
RHI::ResultCode BuildSurface(const RHI::SwapChainDescriptor& descriptor);
//! Returns true is the swapchain dimensions are supported by the current surface.
bool ValidateSurfaceDimensions(const RHI::SwapChainDimensions& dimensions);
//! Returns the corresponding Vulkan format that is supported by the surface.
//! If such format is not found, return the first supported format from the surface.
VkSurfaceFormatKHR GetSupportedSurfaceFormat(const RHI::Format format) const;
//! Returns the correct presentation mode.
//! If verticalSyncInterval is non-zero, returns VK_PRESENT_MODE_FIFO_KHR.
//! Otherwise, choose preferred mode if they are supported.
//! If not, the first supported present mode is returned.
VkPresentModeKHR GetSupportedPresentMode(uint32_t verticalSyncInterval) const;
//! Returns the preferred alpha compositing modes if they are supported.
//! If not, error will be reported.
VkCompositeAlphaFlagBitsKHR GetSupportedCompositeAlpha() const;
RHI::ResultCode BuildNativeSwapChain(const RHI::SwapChainDimensions& dimensions, uint32_t verticalSyncInterval);
//! Returns the current surface capabilities.
VkSurfaceCapabilitiesKHR GetSurfaceCapabilities();
//! Create the swapchain when initializing, or
//! swapchain is no longer compatible or is sub-optimal with the surface.
RHI::ResultCode CreateSwapchain();
//! Build underlying Vulkan swapchain.
RHI::ResultCode BuildNativeSwapChain(const RHI::SwapChainDimensions& dimensions);
//! Retrieve the index of the next available presentable image.
RHI::ResultCode AcquireNewImage(uint32_t* acquiredImageIndex);
//! Destroy the surface.
void InvalidateSurface();
//! Destroy the old swapchain.
void InvalidateNativeSwapChain();
VkSwapchainKHR m_nativeSwapChain = VK_NULL_HANDLE;
RHI::Ptr<WSISurface> m_surface;
VkSwapchainKHR m_nativeSwapChain = VK_NULL_HANDLE;
CommandQueue* m_presentationQueue = nullptr;
VkSurfaceFormatKHR m_surfaceFormat = {};
VkSurfaceCapabilitiesKHR m_surfaceCapabilities;
FrameContext m_currentFrameContext;
//! Swapchain data
VkSurfaceFormatKHR m_surfaceFormat = {};
VkSurfaceCapabilitiesKHR m_surfaceCapabilities = {};
VkPresentModeKHR m_presentMode = {};
VkCompositeAlphaFlagBitsKHR m_compositeAlphaFlagBits = {};
AZStd::vector<VkImage> m_swapchainNativeImages;
RHI::SwapChainDimensions m_dimensions;
struct SwapChainBarrier
{
VkPipelineStageFlags m_srcPipelineStages = 0;
@ -95,8 +119,6 @@ namespace AZ
VkImageMemoryBarrier m_barrier = {};
bool m_isValid = false;
} m_swapChainBarrier;
AZStd::vector<VkImage> m_swapchainNativeImages;
};
}
}

@ -196,12 +196,8 @@ namespace AtomToolsFramework
bool RenderViewportWidget::event(QEvent* event)
{
// On some types of QEvents, a resize event is needed to make sure that the current viewport window
// needs to be updated based on a potential new surface dimensions.
switch (event->type())
{
case QEvent::ScreenChangeInternal:
case QEvent::UpdateLater:
case QEvent::Resize:
SendWindowResizeEvent();
break;

Loading…
Cancel
Save