Vulkan: Wayland Windowing
Wayland WSI would crash the system when used. The reason is that the wayland vulkan WSI doesn't provide windowing support. Vulkan gets full access to the desktop of the OS and it is the responsibilty of the application to do the right thing. For OpenGL Wayland proved basic windowing support using `wayland-egl.h`. Which essentially is a tiny wrapper that keeps track of the window position and size. This PR changes a few things to make the Wayland surface usable: - Do not load debug extensions when blender isn't started with `--debug-gpu`. - Recreate swapchain images when surface size changes. Pull Request: https://projects.blender.org/blender/blender/pulls/113007
This commit is contained in:
parent
44882ceb7b
commit
9a654c04de
|
@ -400,6 +400,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,
|
||||
|
@ -417,6 +418,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),
|
||||
|
@ -476,6 +478,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. */
|
||||
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);
|
||||
|
@ -795,11 +816,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;
|
||||
|
||||
#ifdef 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;
|
||||
}
|
||||
|
|
|
@ -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<VkImage> m_swapchain_images;
|
||||
|
||||
VkExtent2D m_render_extent;
|
||||
VkExtent2D m_render_extent_min;
|
||||
VkSurfaceFormatKHR m_surface_format;
|
||||
VkFence m_fence;
|
||||
|
||||
|
|
|
@ -6337,9 +6337,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) {
|
||||
|
||||
|
@ -6354,6 +6352,7 @@ GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GPUSettings gp
|
|||
nullptr,
|
||||
wl_surface,
|
||||
display_->wl.display,
|
||||
nullptr,
|
||||
1,
|
||||
2,
|
||||
debug_context);
|
||||
|
@ -6379,16 +6378,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);
|
||||
|
@ -6480,7 +6481,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()) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -24,10 +24,12 @@
|
|||
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
#ifdef WITH_GHOST_WAYLAND_DYNLOAD
|
||||
# include <wayland_dynload_egl.h>
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
# ifdef WITH_GHOST_WAYLAND_DYNLOAD
|
||||
# include <wayland_dynload_egl.h>
|
||||
# endif
|
||||
# include <wayland-egl.h>
|
||||
#endif
|
||||
#include <wayland-egl.h>
|
||||
|
||||
#include <algorithm> /* 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) {
|
||||
|
@ -1337,10 +1365,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};
|
||||
|
@ -1348,6 +1378,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.
|
||||
|
@ -1387,8 +1418,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();
|
||||
|
@ -1501,9 +1543,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. */
|
||||
|
@ -1669,7 +1711,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);
|
||||
|
@ -1834,15 +1885,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;
|
||||
}
|
||||
|
@ -1857,12 +1909,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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -189,6 +190,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.
|
||||
|
|
|
@ -1185,6 +1185,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
|
|||
m_display,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
1,
|
||||
2,
|
||||
m_is_debug_context);
|
||||
|
|
Loading…
Reference in New Issue