From b12410f1e80b31bc9ddc878ca6ebc59d12951d8a Mon Sep 17 00:00:00 2001 From: Marius Pelegrin Date: Wed, 29 May 2024 13:26:30 +0200 Subject: [PATCH] Fix crash when window cannot be opened with same resolution Fix a crash on VK_ERROR_OUT_OF_DATE_KHR when the window of the replayer cannot be resized to the size of the swapchain at capture time and that the replayer uses virtual swapchain. The idea is to store the actual size of the window that could be opened at replay time in the virtual swapchain so that the virtual swapchain has the same size as at capture time, and the actual swapchain is the size of the window. When the image is copied from the virtual image to the actual image, only a sub-part of the image is copied. Change-Id: I9609fc524b0faf0f6aed3f1efe570fc5fed86225 --- framework/application/android_window.cpp | 5 + framework/application/android_window.h | 2 + framework/application/display_window.cpp | 16 ++- framework/application/display_window.h | 9 +- framework/application/headless_window.cpp | 18 ++- framework/application/headless_window.h | 5 + framework/application/metal_window.h | 22 ++-- framework/application/metal_window.mm | 118 +++++++++++------- framework/application/wayland_window.cpp | 5 + framework/application/wayland_window.h | 2 + framework/application/win32_window.cpp | 5 + framework/application/win32_window.h | 2 + framework/application/xcb_window.cpp | 5 + framework/application/xcb_window.h | 2 + framework/application/xlib_window.cpp | 5 + framework/application/xlib_window.h | 2 + .../decode/vulkan_replay_consumer_base.cpp | 26 +++- framework/decode/vulkan_virtual_swapchain.cpp | 6 +- framework/decode/vulkan_virtual_swapchain.h | 2 + framework/decode/window.h | 2 + 20 files changed, 192 insertions(+), 67 deletions(-) diff --git a/framework/application/android_window.cpp b/framework/application/android_window.cpp index 1f39f5b7e8..c346e2eb9a 100644 --- a/framework/application/android_window.cpp +++ b/framework/application/android_window.cpp @@ -117,6 +117,11 @@ std::string AndroidWindow::GetWsiExtension() const return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; } +VkExtent2D AndroidWindow::GetSize() const +{ + return { width_, height_ }; +} + VkResult AndroidWindow::CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, diff --git a/framework/application/android_window.h b/framework/application/android_window.h index e36fa5b9c1..ecbbde3445 100644 --- a/framework/application/android_window.h +++ b/framework/application/android_window.h @@ -71,6 +71,8 @@ class AndroidWindow : public decode::Window virtual std::string GetWsiExtension() const override; + virtual VkExtent2D GetSize() const override; + virtual VkResult CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, diff --git a/framework/application/display_window.cpp b/framework/application/display_window.cpp index 4fdf9389c1..c3a2e71cb7 100644 --- a/framework/application/display_window.cpp +++ b/framework/application/display_window.cpp @@ -30,7 +30,7 @@ GFXRECON_BEGIN_NAMESPACE(gfxrecon) GFXRECON_BEGIN_NAMESPACE(application) -DisplayWindow::DisplayWindow(DisplayContext* display_context) : display_context_(display_context) +DisplayWindow::DisplayWindow(DisplayContext* display_context) : display_context_(display_context), width_(0), height_(0) { assert(display_context_ != nullptr); } @@ -195,11 +195,22 @@ VkResult DisplayWindow::SelectPlane(const encode::VulkanInstanceTable* table, return VK_ERROR_INITIALIZATION_FAILED; } +void DisplayWindow::SetSize(const uint32_t width, const uint32_t height) +{ + width_ = width; + height_ = height; +} + std::string DisplayWindow::GetWsiExtension() const { return VK_KHR_DISPLAY_EXTENSION_NAME; } +VkExtent2D DisplayWindow::GetSize() const +{ + return { width_, height_ }; +} + VkResult DisplayWindow::CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, @@ -241,6 +252,9 @@ VkResult DisplayWindow::CreateSurface(const encode::VulkanInstanceTable* table, return error; } + width_ = mode_props.parameters.visibleRegion.width; + height_ = mode_props.parameters.visibleRegion.height; + VkExtent2D image_extent; image_extent.width = mode_props.parameters.visibleRegion.width; image_extent.height = mode_props.parameters.visibleRegion.height; diff --git a/framework/application/display_window.h b/framework/application/display_window.h index f22a0b5f0c..3322e58238 100644 --- a/framework/application/display_window.h +++ b/framework/application/display_window.h @@ -55,9 +55,9 @@ class DisplayWindow : public decode::Window virtual void SetPosition(const int32_t, const int32_t) override {} - virtual void SetSize(const uint32_t, const uint32_t) override{}; + virtual void SetSize(const uint32_t width, const uint32_t height) override; - virtual void SetSizePreTransform(const uint32_t, const uint32_t, const uint32_t) override{}; + virtual void SetSizePreTransform(const uint32_t, const uint32_t, const uint32_t) override {} virtual void SetVisibility(bool) override {} @@ -67,6 +67,8 @@ class DisplayWindow : public decode::Window virtual std::string GetWsiExtension() const override; + virtual VkExtent2D GetSize() const override; + virtual VkResult CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, @@ -94,6 +96,9 @@ class DisplayWindow : public decode::Window private: DisplayContext* display_context_; + + uint32_t width_; + uint32_t height_; }; class DisplayWindowFactory : public decode::WindowFactory diff --git a/framework/application/headless_window.cpp b/framework/application/headless_window.cpp index 8420336b2a..e575578bb2 100644 --- a/framework/application/headless_window.cpp +++ b/framework/application/headless_window.cpp @@ -47,10 +47,11 @@ bool HeadlessWindow::Create(const std::string& title, GFXRECON_UNREFERENCED_PARAMETER(title); GFXRECON_UNREFERENCED_PARAMETER(xpos); GFXRECON_UNREFERENCED_PARAMETER(ypos); - GFXRECON_UNREFERENCED_PARAMETER(width); - GFXRECON_UNREFERENCED_PARAMETER(height); GFXRECON_UNREFERENCED_PARAMETER(force_windowed); + width_ = width; + height_ = height; + return true; } @@ -72,14 +73,14 @@ void HeadlessWindow::SetPosition(const int32_t x, const int32_t y) void HeadlessWindow::SetSize(const uint32_t width, const uint32_t height) { - GFXRECON_UNREFERENCED_PARAMETER(width); - GFXRECON_UNREFERENCED_PARAMETER(height); + width_ = width; + height_ = height; } void HeadlessWindow::SetSizePreTransform(const uint32_t width, const uint32_t height, const uint32_t pre_transform) { - GFXRECON_UNREFERENCED_PARAMETER(width); - GFXRECON_UNREFERENCED_PARAMETER(height); + width_ = width; + height_ = height; GFXRECON_UNREFERENCED_PARAMETER(pre_transform); } @@ -102,6 +103,11 @@ std::string HeadlessWindow::GetWsiExtension() const return VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME; } +VkExtent2D HeadlessWindow::GetSize() const +{ + return { width_, height_ }; +} + VkResult HeadlessWindow::CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, diff --git a/framework/application/headless_window.h b/framework/application/headless_window.h index b5b421c115..61512fdee4 100644 --- a/framework/application/headless_window.h +++ b/framework/application/headless_window.h @@ -65,6 +65,8 @@ class HeadlessWindow : public decode::Window virtual std::string GetWsiExtension() const override; + virtual VkExtent2D GetSize() const override; + virtual VkResult CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, @@ -75,6 +77,9 @@ class HeadlessWindow : public decode::Window private: HeadlessContext* headless_context_; + + uint32_t width_; + uint32_t height_; }; class HeadlessWindowFactory : public decode::WindowFactory diff --git a/framework/application/metal_window.h b/framework/application/metal_window.h index 507baa17c8..f13c63ca50 100644 --- a/framework/application/metal_window.h +++ b/framework/application/metal_window.h @@ -36,7 +36,7 @@ GFXRECON_BEGIN_NAMESPACE(application) class MetalContext; class MetalWindow : public decode::Window { -public: + public: MetalWindow(MetalContext* metal_context); ~MetalWindow() override; @@ -66,6 +66,8 @@ class MetalWindow : public decode::Window std::string GetWsiExtension() const override; + VkExtent2D GetSize() const override; + VkResult CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, @@ -75,21 +77,25 @@ class MetalWindow : public decode::Window private: GFXReconWindowDelegate* window_delegate_; - MetalContext* metal_context_; - NSWindow* window_; - CAMetalLayer* layer_; - uint32_t width_; - uint32_t height_; + MetalContext* metal_context_; + NSWindow* window_; + CAMetalLayer* layer_; + uint32_t width_; + uint32_t height_; }; class MetalWindowFactory : public decode::WindowFactory { -public: + public: MetalWindowFactory(MetalContext* metal_context); const char* GetSurfaceExtensionName() const override { return VK_EXT_METAL_SURFACE_EXTENSION_NAME; } - decode::Window* Create(const int32_t x, const int32_t y, const uint32_t width, const uint32_t height, bool force_windowed = false) override; + decode::Window* Create(const int32_t x, + const int32_t y, + const uint32_t width, + const uint32_t height, + bool force_windowed = false) override; void Destroy(decode::Window* window) override; diff --git a/framework/application/metal_window.mm b/framework/application/metal_window.mm index 6814245798..f19f594a44 100644 --- a/framework/application/metal_window.mm +++ b/framework/application/metal_window.mm @@ -29,41 +29,46 @@ #include #if !__has_feature(objc_arc) - #error "Compile this with -fobjc-arc" +#error "Compile this with -fobjc-arc" #endif -typedef void(^GFXReconKeyCallback)(gfxrecon::application::Application*); +typedef void (^GFXReconKeyCallback)(gfxrecon::application::Application*); -@interface GFXReconWindowDelegate : NSObject +@interface GFXReconWindowDelegate : NSObject - (void)windowWillClose:(NSNotification*)notification; @end @implementation GFXReconWindowDelegate -- (void)windowWillClose:(NSNotification*)notification { +- (void)windowWillClose:(NSNotification*)notification +{ GFXRECON_LOG_DEBUG_ONCE("User closed window"); [NSApp terminate:self]; } @end -@interface GFXReconView : NSView -@property (nonatomic) gfxrecon::application::Application* app; +@interface GFXReconView : NSView +@property(nonatomic) gfxrecon::application::Application* app; - (instancetype)initWithFrame:(NSRect)frame app:(gfxrecon::application::Application*)app; @end @implementation GFXReconView -- (instancetype)initWithFrame:(NSRect)frame app:(gfxrecon::application::Application *)app { +- (instancetype)initWithFrame:(NSRect)frame app:(gfxrecon::application::Application*)app +{ self = [super initWithFrame:frame]; - if (self) { + if (self) + { _app = app; } return self; } -- (void)keyDown:(NSEvent *)event { +- (void)keyDown:(NSEvent*)event +{ if (!_app) return; - switch ([event keyCode]) { + switch ([event keyCode]) + { case kVK_Space: case kVK_ANSI_P: _app->SetPaused(!_app->GetPaused()); @@ -81,7 +86,8 @@ - (void)keyDown:(NSEvent *)event { } } -- (BOOL)acceptsFirstResponder { +- (BOOL)acceptsFirstResponder +{ return YES; } @@ -95,30 +101,37 @@ - (BOOL)acceptsFirstResponder { return [[NSString alloc] initWithBytes:std_string.data() length:std_string.size() encoding:NSUTF8StringEncoding]; } -MetalWindow::MetalWindow(MetalContext* metal_context) - : metal_context_(metal_context), window_(nil), window_delegate_(nil), layer_(nil), width_(0), height_(0) -{ -} +MetalWindow::MetalWindow(MetalContext* metal_context) : + metal_context_(metal_context), window_(nil), window_delegate_(nil), layer_(nil), width_(0), height_(0) +{} MetalWindow::~MetalWindow() = default; -bool MetalWindow::Create(const std::string& title, const int32_t xpos, const int32_t ypos, const uint32_t width, const uint32_t height, bool force_windowed) +bool MetalWindow::Create(const std::string& title, + const int32_t xpos, + const int32_t ypos, + const uint32_t width, + const uint32_t height, + bool force_windowed) { @autoreleasepool { - window_delegate_ = [GFXReconWindowDelegate new]; - NSScreen* screen = [NSScreen mainScreen]; - NSRect screen_frame = [screen convertRectToBacking:[screen frame]]; - NSWindowStyleMask style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; + window_delegate_ = [GFXReconWindowDelegate new]; + NSScreen* screen = [NSScreen mainScreen]; + NSRect screen_frame = [screen convertRectToBacking:[screen frame]]; + NSWindowStyleMask style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | + NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; if (width >= screen_frame.size.width && height >= screen_frame.size.height) style |= NSWindowStyleMaskFullScreen; - window_ = [[NSWindow alloc] initWithContentRect:[screen convertRectFromBacking:NSMakeRect(xpos, ypos, width, height)] - styleMask:style - backing:NSBackingStoreBuffered - defer:NO]; + window_ = + [[NSWindow alloc] initWithContentRect:[screen convertRectFromBacking:NSMakeRect(xpos, ypos, width, height)] + styleMask:style + backing:NSBackingStoreBuffered + defer:NO]; [window_ setDelegate:window_delegate_]; - [window_ setCollectionBehavior:NSWindowCollectionBehaviorManaged | NSWindowCollectionBehaviorFullScreenPrimary | NSWindowCollectionBehaviorFullScreenAllowsTiling]; - layer_ = [CAMetalLayer layer]; + [window_ setCollectionBehavior:NSWindowCollectionBehaviorManaged | NSWindowCollectionBehaviorFullScreenPrimary | + NSWindowCollectionBehaviorFullScreenAllowsTiling]; + layer_ = [CAMetalLayer layer]; NSView* content = [[GFXReconView alloc] initWithFrame:[window_ contentRectForFrameRect:[window_ frame]] app:metal_context_->GetApplication()]; [window_ setContentView:content]; @@ -147,7 +160,7 @@ - (BOOL)acceptsFirstResponder { [window_ close]; metal_context_->UnregisterWindow(this); } - layer_ = nil; + layer_ = nil; window_ = nil; return true; } @@ -166,11 +179,13 @@ - (BOOL)acceptsFirstResponder { { if ([window_ styleMask] & NSWindowStyleMaskFullScreen) return; - NSScreen* screen = [window_ screen]; - NSRect screen_frame = [screen convertRectToBacking:[window_ contentRectForFrameRect:[screen frame]]]; - NSRect window_frame = [screen convertRectToBacking:[window_ contentRectForFrameRect:[window_ frame]]]; - window_frame.origin.x = std::max(0, std::min(x, screen_frame.size.width - window_frame.size.width)); - window_frame.origin.y = std::max(0, std::min(y, screen_frame.size.height - window_frame.size.height)); + NSScreen* screen = [window_ screen]; + NSRect screen_frame = [screen convertRectToBacking:[window_ contentRectForFrameRect:[screen frame]]]; + NSRect window_frame = [screen convertRectToBacking:[window_ contentRectForFrameRect:[window_ frame]]]; + window_frame.origin.x = + std::max(0, std::min(x, screen_frame.size.width - window_frame.size.width)); + window_frame.origin.y = + std::max(0, std::min(y, screen_frame.size.height - window_frame.size.height)); [window_ setFrameOrigin:[window_ frameRectForContentRect:[screen convertRectFromBacking:window_frame]].origin]; } } @@ -181,12 +196,12 @@ - (BOOL)acceptsFirstResponder { return; @autoreleasepool { - width_ = width; - height_ = height; - NSScreen* screen = [window_ screen]; - NSRect screen_frame = [screen convertRectToBacking:[window_ contentRectForFrameRect:[screen frame]]]; - bool fullscreen = width >= screen_frame.size.width && height >= screen_frame.size.height; - NSWindowStyleMask style = [window_ styleMask]; + width_ = width; + height_ = height; + NSScreen* screen = [window_ screen]; + NSRect screen_frame = [screen convertRectToBacking:[window_ contentRectForFrameRect:[screen frame]]]; + bool fullscreen = width >= screen_frame.size.width && height >= screen_frame.size.height; + NSWindowStyleMask style = [window_ styleMask]; if (fullscreen) { if (!(style & NSWindowStyleMaskFullScreen)) @@ -196,12 +211,15 @@ - (BOOL)acceptsFirstResponder { { if (style & NSWindowStyleMaskFullScreen) [window_ toggleFullScreen:nil]; - NSRect window_frame = [screen convertRectToBacking:[window_ contentRectForFrameRect:[window_ frame]]]; - window_frame.size.width = std::min(screen_frame.size.width, width); + NSRect window_frame = [screen convertRectToBacking:[window_ contentRectForFrameRect:[window_ frame]]]; + window_frame.size.width = std::min(screen_frame.size.width, width); window_frame.size.height = std::min(screen_frame.size.height, height); - window_frame.origin.x = std::max(0, std::min(window_frame.origin.x, screen_frame.size.width - window_frame.size.width)); - window_frame.origin.y = std::max(0, std::min(window_frame.origin.y, screen_frame.size.height - window_frame.size.height)); - [window_ setFrame:[window_ frameRectForContentRect:[screen convertRectFromBacking:window_frame]] display:YES]; + window_frame.origin.x = std::max( + 0, std::min(window_frame.origin.x, screen_frame.size.width - window_frame.size.width)); + window_frame.origin.y = std::max( + 0, std::min(window_frame.origin.y, screen_frame.size.height - window_frame.size.height)); + [window_ setFrame:[window_ frameRectForContentRect:[screen convertRectFromBacking:window_frame]] + display:YES]; } } } @@ -239,6 +257,11 @@ - (BOOL)acceptsFirstResponder { return VK_EXT_METAL_SURFACE_EXTENSION_NAME; } +VkExtent2D MetalWindow::GetSize() const +{ + return { width_, height_ }; +} + VkResult MetalWindow::CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, @@ -247,7 +270,7 @@ - (BOOL)acceptsFirstResponder { if (table) { VkMetalSurfaceCreateInfoEXT create_info = { VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT }; - create_info.pLayer = layer_; + create_info.pLayer = layer_; return table->CreateMetalSurfaceEXT(instance, &create_info, nullptr, pSurface); } @@ -266,11 +289,12 @@ - (BOOL)acceptsFirstResponder { assert(metal_context_); } -decode::Window* MetalWindowFactory::Create(const int32_t x, const int32_t y, const uint32_t width, const uint32_t height, bool force_windowed) +decode::Window* MetalWindowFactory::Create( + const int32_t x, const int32_t y, const uint32_t width, const uint32_t height, bool force_windowed) { assert(metal_context_); - decode::Window* window = new MetalWindow(metal_context_); - Application* application = metal_context_->GetApplication(); + decode::Window* window = new MetalWindow(metal_context_); + Application* application = metal_context_->GetApplication(); window->Create(application->GetName(), x, y, width, height, force_windowed); return window; } diff --git a/framework/application/wayland_window.cpp b/framework/application/wayland_window.cpp index 9933da8ac1..8af246e0c9 100644 --- a/framework/application/wayland_window.cpp +++ b/framework/application/wayland_window.cpp @@ -254,6 +254,11 @@ std::string WaylandWindow::GetWsiExtension() const return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME; } +VkExtent2D WaylandWindow::GetSize() const +{ + return { width_, height_ }; +} + VkResult WaylandWindow::CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, diff --git a/framework/application/wayland_window.h b/framework/application/wayland_window.h index 217650f6b0..f07c3d9648 100644 --- a/framework/application/wayland_window.h +++ b/framework/application/wayland_window.h @@ -73,6 +73,8 @@ class WaylandWindow : public decode::Window virtual std::string GetWsiExtension() const override; + virtual VkExtent2D GetSize() const override; + virtual VkResult CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, diff --git a/framework/application/win32_window.cpp b/framework/application/win32_window.cpp index a52da0c09c..a1de5b2f25 100644 --- a/framework/application/win32_window.cpp +++ b/framework/application/win32_window.cpp @@ -286,6 +286,11 @@ std::string Win32Window::GetWsiExtension() const return VK_KHR_WIN32_SURFACE_EXTENSION_NAME; } +VkExtent2D Win32Window::GetSize() const +{ + return { width_, height_ }; +} + VkResult Win32Window::CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, diff --git a/framework/application/win32_window.h b/framework/application/win32_window.h index c5226f3f29..a7c258d8ad 100644 --- a/framework/application/win32_window.h +++ b/framework/application/win32_window.h @@ -68,6 +68,8 @@ class Win32Window : public decode::Window virtual std::string GetWsiExtension() const override; + virtual VkExtent2D GetSize() const override; + virtual VkResult CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, diff --git a/framework/application/xcb_window.cpp b/framework/application/xcb_window.cpp index 396ba48c44..cab635a7d5 100644 --- a/framework/application/xcb_window.cpp +++ b/framework/application/xcb_window.cpp @@ -409,6 +409,11 @@ std::string XcbWindow::GetWsiExtension() const return VK_KHR_XCB_SURFACE_EXTENSION_NAME; } +VkExtent2D XcbWindow::GetSize() const +{ + return { width_, height_ }; +} + VkResult XcbWindow::CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, diff --git a/framework/application/xcb_window.h b/framework/application/xcb_window.h index 81c1037f02..93fd3d035e 100644 --- a/framework/application/xcb_window.h +++ b/framework/application/xcb_window.h @@ -86,6 +86,8 @@ class XcbWindow : public decode::Window virtual std::string GetWsiExtension() const override; + virtual VkExtent2D GetSize() const override; + virtual VkResult CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, diff --git a/framework/application/xlib_window.cpp b/framework/application/xlib_window.cpp index 44e8e14471..b0a29a65f3 100644 --- a/framework/application/xlib_window.cpp +++ b/framework/application/xlib_window.cpp @@ -300,6 +300,11 @@ std::string XlibWindow::GetWsiExtension() const return VK_KHR_XLIB_SURFACE_EXTENSION_NAME; } +VkExtent2D XlibWindow::GetSize() const +{ + return { width_, height_ }; +} + VkResult XlibWindow::CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, diff --git a/framework/application/xlib_window.h b/framework/application/xlib_window.h index 4bc63dbc4b..12a0b66512 100644 --- a/framework/application/xlib_window.h +++ b/framework/application/xlib_window.h @@ -64,6 +64,8 @@ class XlibWindow : public decode::Window virtual std::string GetWsiExtension() const override; + virtual VkExtent2D GetSize() const override; + virtual VkResult CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags, diff --git a/framework/decode/vulkan_replay_consumer_base.cpp b/framework/decode/vulkan_replay_consumer_base.cpp index 93fa842a0a..8186a0d736 100644 --- a/framework/decode/vulkan_replay_consumer_base.cpp +++ b/framework/decode/vulkan_replay_consumer_base.cpp @@ -5322,6 +5322,8 @@ VkResult VulkanReplayConsumerBase::OverrideCreateSwapchainKHR( // Ignore swapchain creation if surface creation was skipped when rendering is restricted to a specific surface. if (replay_create_info->surface != VK_NULL_HANDLE) { + VkSwapchainCreateInfoKHR modified_create_info = (*replay_create_info); + // Ensure that the window has been resized properly. For Android, this ensures that we will set the proper // screen orientation when the swapchain pre-transform specifies a 90 or 270 degree rotation for older files // that do not include a ResizeWindowCmd2 command. @@ -5329,12 +5331,32 @@ VkResult VulkanReplayConsumerBase::OverrideCreateSwapchainKHR( if (meta_info != nullptr) { SetSwapchainWindowSize(meta_info); + + const auto surface_info = object_info_table_.GetSurfaceKHRInfo(meta_info->surface); + + if (surface_info && (surface_info->window != nullptr)) + { + VkExtent2D window_size = surface_info->window->GetSize(); + + if (window_size.width != modified_create_info.imageExtent.width || + window_size.height != modified_create_info.imageExtent.height) + { + GFXRECON_LOG_WARNING( + "Could not resize window to (%u, %u). Instead, window was resized to (%u, %u). Swapchain will " + "be resized accordingly, but bugs might occur. Using virtual swapchain should mitigate those " + "bugs.", + modified_create_info.imageExtent.width, + modified_create_info.imageExtent.height, + window_size.width, + window_size.height); + + modified_create_info.imageExtent = window_size; + } + } } ProcessSwapchainFullScreenExclusiveInfo(pCreateInfo->GetMetaStructPointer()); - VkSwapchainCreateInfoKHR modified_create_info = (*replay_create_info); - if (screenshot_handler_ != nullptr) { // Screenshots are active, so ensure that swapchain images can be used as a transfer source. diff --git a/framework/decode/vulkan_virtual_swapchain.cpp b/framework/decode/vulkan_virtual_swapchain.cpp index 2507a0d369..aea7049993 100644 --- a/framework/decode/vulkan_virtual_swapchain.cpp +++ b/framework/decode/vulkan_virtual_swapchain.cpp @@ -85,6 +85,8 @@ VkResult VulkanVirtualSwapchain::CreateSwapchainKHR(VkResult { return VK_ERROR_OUT_OF_HOST_MEMORY; } + + swapchain_resources_[*replay_swapchain]->actual_extent = modified_create_info.imageExtent; } return result; } @@ -828,7 +830,9 @@ VkResult VulkanVirtualSwapchain::QueuePresentKHR(VkResult &initial_barrier_swapchain_image); subresource.layerCount = swapchain_info->image_array_layers; - VkExtent3D image_extent = { swapchain_info->width, swapchain_info->height, 1 }; + VkExtent3D image_extent = { std::min(swapchain_resources->actual_extent.width, swapchain_info->width), + std::min(swapchain_resources->actual_extent.height, swapchain_info->height), + 1 }; VkImageCopy image_copy = { subresource, offset, subresource, offset, image_extent }; // NOTE: vkCmdCopyImage works on Queues of types including Graphics, Compute diff --git a/framework/decode/vulkan_virtual_swapchain.h b/framework/decode/vulkan_virtual_swapchain.h index b174bef7f9..4e9f396dfc 100644 --- a/framework/decode/vulkan_virtual_swapchain.h +++ b/framework/decode/vulkan_virtual_swapchain.h @@ -144,6 +144,8 @@ class VulkanVirtualSwapchain : public VulkanSwapchain // as a vector of the actual hardware ones used during replay. std::vector virtual_swapchain_images; std::vector replay_swapchain_images; + + VkExtent2D actual_extent; }; bool AddSwapchainResourceData(VkSwapchainKHR swapchain); diff --git a/framework/decode/window.h b/framework/decode/window.h index 0fcb2733fb..65c5278821 100644 --- a/framework/decode/window.h +++ b/framework/decode/window.h @@ -82,6 +82,8 @@ class Window virtual std::string GetWsiExtension() const = 0; + virtual VkExtent2D GetSize() const = 0; + virtual VkResult CreateSurface(const encode::VulkanInstanceTable* table, VkInstance instance, VkFlags flags,