diff --git a/intern/ghost/intern/GHOST_ContextVK.cc b/intern/ghost/intern/GHOST_ContextVK.cc index ec404493adc..e476d249858 100644 --- a/intern/ghost/intern/GHOST_ContextVK.cc +++ b/intern/ghost/intern/GHOST_ContextVK.cc @@ -395,6 +395,7 @@ GHOST_ContextVK::GHOST_ContextVK(bool stereoVisual, /* Wayland */ wl_surface *wayland_surface, wl_display *wayland_display, + const GHOST_ContextVK_WindowInfo *wayland_window_info, #endif int contextMajorVersion, int contextMinorVersion, @@ -412,6 +413,7 @@ GHOST_ContextVK::GHOST_ContextVK(bool stereoVisual, /* Wayland */ m_wayland_surface(wayland_surface), m_wayland_display(wayland_display), + m_wayland_window_info(wayland_window_info), #endif m_context_major_version(contextMajorVersion), m_context_minor_version(contextMinorVersion), @@ -471,6 +473,25 @@ GHOST_TSuccess GHOST_ContextVK::swapBuffers() return GHOST_kFailure; } +#ifdef WITH_GHOST_WAYLAND + /* Wayland doesn't provide a WSI with windowing capabilities, therefore cannot detect whether the + * swap-chain needs to be recreated. But as a side effect we can recreate the swap chain before + * presenting. */ + if (m_wayland_window_info) { + const bool recreate_swapchain = + ((m_wayland_window_info->size[0] != + std::max(m_render_extent.width, m_render_extent_min.width)) || + (m_wayland_window_info->size[1] != + std::max(m_render_extent.height, m_render_extent_min.height))); + + if (recreate_swapchain) { + /* Swap-chain is out of date. Recreate swap-chain and skip this frame. */ + destroySwapchain(); + createSwapchain(); + } + } +#endif + assert(vulkan_device.has_value() && vulkan_device->device != VK_NULL_HANDLE); VkDevice device = vulkan_device->device; vkAcquireNextImageKHR(device, m_swapchain, UINT64_MAX, VK_NULL_HANDLE, m_fence, &m_currentImage); @@ -790,11 +811,29 @@ GHOST_TSuccess GHOST_ContextVK::createSwapchain() vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, m_surface, &capabilities); m_render_extent = capabilities.currentExtent; + m_render_extent_min = capabilities.minImageExtent; if (m_render_extent.width == UINT32_MAX) { /* Window Manager is going to set the surface size based on the given size. * Choose something between minImageExtent and maxImageExtent. */ - m_render_extent.width = 1280; - m_render_extent.height = 720; + int width = 0; + int height = 0; + +#if WITH_GHOST_WAYLAND + /* Wayland doesn't provide a windowing API via WSI. */ + if (m_wayland_window_info) { + width = m_wayland_window_info->size[0]; + height = m_wayland_window_info->size[1]; + } +#endif + + if (width == 0 || height == 0) { + width = 1280; + height = 720; + } + + m_render_extent.width = width; + m_render_extent.height = height; + if (capabilities.minImageExtent.width > m_render_extent.width) { m_render_extent.width = capabilities.minImageExtent.width; } diff --git a/intern/ghost/intern/GHOST_ContextVK.hh b/intern/ghost/intern/GHOST_ContextVK.hh index e0d5a4a3ef8..8946f90f228 100644 --- a/intern/ghost/intern/GHOST_ContextVK.hh +++ b/intern/ghost/intern/GHOST_ContextVK.hh @@ -42,6 +42,10 @@ typedef enum { #endif } GHOST_TVulkanPlatformType; +struct GHOST_ContextVK_WindowInfo { + int size[2]; +}; + class GHOST_ContextVK : public GHOST_Context { public: /** @@ -61,6 +65,7 @@ class GHOST_ContextVK : public GHOST_Context { /* Wayland */ wl_surface *wayland_surface, wl_display *wayland_display, + const GHOST_ContextVK_WindowInfo *wayland_window_info, #endif int contextMajorVersion, int contextMinorVersion, @@ -151,6 +156,7 @@ class GHOST_ContextVK : public GHOST_Context { /* Wayland */ wl_surface *m_wayland_surface; wl_display *m_wayland_display; + const GHOST_ContextVK_WindowInfo *m_wayland_window_info; #endif const int m_context_major_version; @@ -169,6 +175,7 @@ class GHOST_ContextVK : public GHOST_Context { std::vector m_swapchain_images; VkExtent2D m_render_extent; + VkExtent2D m_render_extent_min; VkSurfaceFormatKHR m_surface_format; VkFence m_fence; diff --git a/intern/ghost/intern/GHOST_SystemWayland.cc b/intern/ghost/intern/GHOST_SystemWayland.cc index 72aa85b522e..20c20918f65 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cc +++ b/intern/ghost/intern/GHOST_SystemWayland.cc @@ -6339,9 +6339,7 @@ GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GPUSettings gp std::lock_guard lock_server_guard{*server_mutex}; #endif -#ifdef WITH_VULKAN_BACKEND const bool debug_context = (gpuSettings.flags & GHOST_gpuDebugContext) != 0; -#endif switch (gpuSettings.context_type) { @@ -6356,6 +6354,7 @@ GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GPUSettings gp nullptr, wl_surface, display_->wl.display, + nullptr, 1, 2, debug_context); @@ -6381,16 +6380,18 @@ GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GPUSettings gp for (int minor = 6; minor >= 3; --minor) { /* Caller must lock `system->server_mutex`. */ - GHOST_Context *context = new GHOST_ContextEGL(this, - false, - EGLNativeWindowType(egl_window), - EGLNativeDisplayType(display_->wl.display), - EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, - 4, - minor, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); + GHOST_Context *context = new GHOST_ContextEGL( + this, + false, + EGLNativeWindowType(egl_window), + EGLNativeDisplayType(display_->wl.display), + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + 4, + minor, + GHOST_OPENGL_EGL_CONTEXT_FLAGS | + (debug_context ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0), + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_API); if (context->initializeDrawingContext()) { wl_surface_set_user_data(wl_surface, egl_window); @@ -6466,7 +6467,8 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title, gpuSettings.context_type, is_dialog, ((gpuSettings.flags & GHOST_gpuStereoVisual) != 0), - exclusive); + exclusive, + (gpuSettings.flags & GHOST_gpuDebugContext) != 0); if (window) { if (window->getValid()) { diff --git a/intern/ghost/intern/GHOST_SystemX11.cc b/intern/ghost/intern/GHOST_SystemX11.cc index 91ea997fd8c..cb43ac7ad3b 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cc +++ b/intern/ghost/intern/GHOST_SystemX11.cc @@ -358,8 +358,16 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GPUSettings gpuSet switch (gpuSettings.context_type) { #ifdef WITH_VULKAN_BACKEND case GHOST_kDrawingContextTypeVulkan: { - GHOST_Context *context = new GHOST_ContextVK( - false, GHOST_kVulkanPlatformX11, 0, m_display, nullptr, nullptr, 1, 2, debug_context); + GHOST_Context *context = new GHOST_ContextVK(false, + GHOST_kVulkanPlatformX11, + 0, + m_display, + nullptr, + nullptr, + nullptr, + 1, + 2, + debug_context); if (context->initializeDrawingContext()) { return context; } diff --git a/intern/ghost/intern/GHOST_WindowWayland.cc b/intern/ghost/intern/GHOST_WindowWayland.cc index 0b506d10503..2cbe2c41ab3 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.cc +++ b/intern/ghost/intern/GHOST_WindowWayland.cc @@ -24,10 +24,12 @@ #include -#ifdef WITH_GHOST_WAYLAND_DYNLOAD -# include +#ifdef WITH_OPENGL_BACKEND +# ifdef WITH_GHOST_WAYLAND_DYNLOAD +# include +# endif +# include #endif -#include #include /* For `std::find`. */ @@ -221,8 +223,6 @@ struct GWL_Window { /** Wayland core types. */ struct { wl_surface *surface = nullptr; - - wl_egl_window *egl_window = nullptr; } wl; /** Wayland native types. */ @@ -242,8 +242,19 @@ struct GWL_Window { xdg_activation_token_v1 *activation_token = nullptr; } xdg; + struct { +#ifdef WITH_OPENGL_BACKEND + wl_egl_window *egl_window = nullptr; +#endif +#ifdef WITH_VULKAN_BACKEND + GHOST_ContextVK_WindowInfo *vulkan_window_info = nullptr; +#endif + } backend; + GHOST_WindowWayland *ghost_window = nullptr; GHOST_SystemWayland *ghost_system = nullptr; + GHOST_TDrawingContextType ghost_context_type = GHOST_kDrawingContextTypeNone; + /** * Outputs on which the window is currently shown on. * @@ -288,6 +299,21 @@ struct GWL_Window { #endif /* USE_EVENT_BACKGROUND_THREAD */ }; +static void gwl_window_resize_for_backend(GWL_Window *win, const int32_t size[2]) +{ +#ifdef WITH_OPENGL_BACKEND + if (win->ghost_context_type == GHOST_kDrawingContextTypeOpenGL) { + wl_egl_window_resize(win->backend.egl_window, UNPACK2(size), 0, 0); + } +#endif +#ifdef WITH_VULKAN_BACKEND + if (win->ghost_context_type == GHOST_kDrawingContextTypeVulkan) { + win->backend.vulkan_window_info->size[0] = size[0]; + win->backend.vulkan_window_info->size[1] = size[1]; + } +#endif +} + static void gwl_window_title_set(GWL_Window *win, const char *title) { #ifdef WITH_GHOST_WAYLAND_LIBDECOR @@ -648,7 +674,7 @@ static void gwl_window_frame_pending_fractional_scale_set(GWL_Window *win, static void gwl_window_frame_pending_size_set(GWL_Window *win, bool *r_surface_needs_commit, - bool *r_surface_needs_egl_resize, + bool *r_surface_needs_resize_for_backend, bool *r_surface_needs_buffer_scale) { if (win->frame_pending.size[0] == 0 || win->frame_pending.size[1] == 0) { @@ -668,11 +694,11 @@ static void gwl_window_frame_pending_size_set(GWL_Window *win, gwl_window_viewport_size_update(win); } - if (r_surface_needs_egl_resize) { - *r_surface_needs_egl_resize = true; + if (r_surface_needs_resize_for_backend) { + *r_surface_needs_resize_for_backend = true; } else { - wl_egl_window_resize(win->wl.egl_window, UNPACK2(win->frame.size), 0, 0); + gwl_window_resize_for_backend(win, win->frame.size); } win->ghost_window->notify_size(); @@ -741,15 +767,17 @@ static void gwl_window_frame_update_from_pending_no_lock(GWL_Window *win) const bool dpi_changed = win->frame_pending.fractional_scale != win->frame.fractional_scale; bool surface_needs_commit = false; - bool surface_needs_egl_resize = false; + bool surface_needs_resize_for_backend = false; bool surface_needs_buffer_scale = false; if (win->frame_pending.size[0] != 0 && win->frame_pending.size[1] != 0) { if ((win->frame.size[0] != win->frame_pending.size[0]) || (win->frame.size[1] != win->frame_pending.size[1])) { - gwl_window_frame_pending_size_set( - win, &surface_needs_commit, &surface_needs_egl_resize, &surface_needs_buffer_scale); + gwl_window_frame_pending_size_set(win, + &surface_needs_commit, + &surface_needs_resize_for_backend, + &surface_needs_buffer_scale); } } @@ -764,8 +792,8 @@ static void gwl_window_frame_update_from_pending_no_lock(GWL_Window *win) } } - if (surface_needs_egl_resize) { - wl_egl_window_resize(win->wl.egl_window, UNPACK2(win->frame.size), 0, 0); + if (surface_needs_resize_for_backend) { + gwl_window_resize_for_backend(win, win->frame.size); } if (surface_needs_buffer_scale) { @@ -1317,10 +1345,12 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, const GHOST_TDrawingContextType type, const bool is_dialog, const bool stereoVisual, - const bool exclusive) + const bool exclusive, + const bool is_debug) : GHOST_Window(width, height, state, stereoVisual, exclusive), system_(system), - window_(new GWL_Window) + window_(new GWL_Window), + is_debug_context_(is_debug) { #ifdef USE_EVENT_BACKGROUND_THREAD std::lock_guard lock_server_guard{*system->server_mutex}; @@ -1328,6 +1358,7 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, window_->ghost_window = this; window_->ghost_system = system; + window_->ghost_context_type = type; /* NOTE(@ideasman42): The scale set here to avoid flickering on startup. * When all monitors use the same scale (which is quite common) there aren't any problems. @@ -1367,8 +1398,19 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, wl_surface_add_listener(window_->wl.surface, &wl_surface_listener, window_); - window_->wl.egl_window = wl_egl_window_create( - window_->wl.surface, int(window_->frame.size[0]), int(window_->frame.size[1])); +#ifdef WITH_OPENGL_BACKEND + if (type == GHOST_kDrawingContextTypeOpenGL) { + window_->backend.egl_window = wl_egl_window_create( + window_->wl.surface, int(window_->frame.size[0]), int(window_->frame.size[1])); + } +#endif +#ifdef WITH_VULKAN_BACKEND + if (type == GHOST_kDrawingContextTypeVulkan) { + window_->backend.vulkan_window_info = new GHOST_ContextVK_WindowInfo; + window_->backend.vulkan_window_info->size[0] = window_->frame.size[0]; + window_->backend.vulkan_window_info->size[1] = window_->frame.size[1]; + } +#endif wp_fractional_scale_manager_v1 *fractional_scale_manager = system->wp_fractional_scale_manager_get(); @@ -1481,9 +1523,9 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, gwl_window_state_set(window_, state); } - /* EGL context. */ + /* Drawing context. */ if (setDrawingContextType(type) == GHOST_kFailure) { - GHOST_PRINT("Failed to create EGL context" << std::endl); + GHOST_PRINT("Failed to create drawing context" << std::endl); } /* Set swap interval to 0 to prevent blocking. */ @@ -1649,7 +1691,16 @@ GHOST_WindowWayland::~GHOST_WindowWayland() releaseNativeHandles(); - wl_egl_window_destroy(window_->wl.egl_window); +#ifdef WITH_OPENGL_BACKEND + if (window_->ghost_context_type == GHOST_kDrawingContextTypeOpenGL) { + wl_egl_window_destroy(window_->backend.egl_window); + } +#endif +#ifdef WITH_VULKAN_BACKEND + if (window_->ghost_context_type == GHOST_kDrawingContextTypeVulkan) { + delete window_->backend.vulkan_window_info; + } +#endif if (window_->xdg.activation_token) { xdg_activation_token_v1_destroy(window_->xdg.activation_token); @@ -1814,15 +1865,16 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType #ifdef WITH_VULKAN_BACKEND case GHOST_kDrawingContextTypeVulkan: { - GHOST_Context *context = new GHOST_ContextVK(m_wantStereoVisual, - GHOST_kVulkanPlatformWayland, - 0, - nullptr, - window_->wl.surface, - system_->wl_display_get(), - 1, - 2, - true); + GHOST_ContextVK *context = new GHOST_ContextVK(m_wantStereoVisual, + GHOST_kVulkanPlatformWayland, + 0, + nullptr, + window_->wl.surface, + system_->wl_display_get(), + window_->backend.vulkan_window_info, + 1, + 2, + is_debug_context_); if (context->initializeDrawingContext()) { return context; } @@ -1837,12 +1889,13 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType GHOST_Context *context = new GHOST_ContextEGL( system_, m_wantStereoVisual, - EGLNativeWindowType(window_->wl.egl_window), + EGLNativeWindowType(window_->backend.egl_window), EGLNativeDisplayType(system_->wl_display_get()), EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, 4, minor, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, + GHOST_OPENGL_EGL_CONTEXT_FLAGS | + (is_debug_context_ ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0), GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, EGL_OPENGL_API); diff --git a/intern/ghost/intern/GHOST_WindowWayland.hh b/intern/ghost/intern/GHOST_WindowWayland.hh index eee20e0b6e2..4894bd7d2f3 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.hh +++ b/intern/ghost/intern/GHOST_WindowWayland.hh @@ -74,7 +74,8 @@ class GHOST_WindowWayland : public GHOST_Window { GHOST_TDrawingContextType type, const bool is_dialog, const bool stereoVisual, - const bool exclusive); + const bool exclusive, + const bool is_debug); ~GHOST_WindowWayland() override; @@ -176,6 +177,7 @@ class GHOST_WindowWayland : public GHOST_Window { private: GHOST_SystemWayland *system_; struct GWL_Window *window_; + bool is_debug_context_; /** * \param type: The type of rendering context create. diff --git a/intern/ghost/intern/GHOST_WindowX11.cc b/intern/ghost/intern/GHOST_WindowX11.cc index 8e8f17c541c..0c643ca4e3d 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cc +++ b/intern/ghost/intern/GHOST_WindowX11.cc @@ -1185,6 +1185,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type m_display, nullptr, nullptr, + nullptr, 1, 2, m_is_debug_context);