Re-land: "Vulkan: Support Wayland"

Implement DisplayVkWayland and WindowSurfaceVkWayland. Get window size
from native window and check egl config is just empty. An EGL wayland
test is added for testing rendering and buffers swapping.

Re-land fixes link failure in systems with no libwayland installed.

Bug: angleproject:6902
Change-Id: I4f091d4f479a537d0390caedce88a5d39f8b356f
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3608088
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Antonio Caggiano
2021-12-09 16:52:35 +01:00
committed by Angle LUCI CQ
parent ea9a2dbeac
commit e0dd196a0e
23 changed files with 814 additions and 13 deletions

View File

@@ -153,6 +153,15 @@ config("internal_config") {
if (!angle_use_x11) {
defines += [ "EGL_NO_X11" ]
}
# These two are needed here to correctly select OSWindow::New
if (angle_use_x11) {
defines += [ "ANGLE_USE_X11" ]
}
if (angle_use_wayland) {
defines += [ "ANGLE_USE_WAYLAND" ]
}
if (angle_vulkan_display_mode == "simple") {
defines += [ "ANGLE_VULKAN_DISPLAY_MODE_SIMPLE" ]
} else if (angle_vulkan_display_mode == "headless") {
@@ -513,6 +522,10 @@ angle_static_library("angle_gpu_info_util") {
"Xext",
]
}
if (angle_use_wayland && angle_has_build) {
public_deps += [ ":angle_wayland" ]
}
}
if (use_libpci) {
@@ -824,6 +837,10 @@ config("libANGLE_config") {
defines += [ "ANGLE_USE_X11" ]
}
if (angle_use_wayland) {
defines += [ "ANGLE_USE_WAYLAND" ]
}
if (angle_enable_overlay) {
defines += [ "ANGLE_ENABLE_OVERLAY=1" ]
}
@@ -1013,6 +1030,38 @@ angle_source_set("angle_gl_enum_utils") {
]
}
if (angle_use_wayland) {
config("angle_wayland_config") {
if (!defined(use_system_libwayland) || use_system_libwayland) {
libs = [
"wayland-client",
"wayland-egl",
]
}
include_dirs = [
"$angle_wayland_dir/egl",
"$angle_wayland_dir/src",
# In case we are building with chromium, we need to take into account the case
# where wayland-egl-backend.h is not installed in the system include directories
"//third_party/wayland/src/egl",
]
}
group("angle_wayland") {
public_configs = [ ":angle_wayland_config" ]
if (defined(use_system_libwayland) && !use_system_libwayland) {
# Use chromium third-party targets
public_deps = [
"//third_party/wayland:wayland_client",
"//third_party/wayland:wayland_egl",
]
}
}
}
if (!defined(angle_abseil_cpp_dir)) {
angle_abseil_cpp_dir = "//third_party/abseil-cpp"
}

View File

@@ -210,6 +210,7 @@ IGNORED_INCLUDES = {
b'libANGLE/renderer/vulkan/mac/DisplayVkMac.h',
b'libANGLE/renderer/vulkan/win32/DisplayVkWin32.h',
b'libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h',
b'libANGLE/renderer/vulkan/wayland/DisplayVkWayland.h',
b'loader_cmake_config.h',
b'loader_linux.h',
b'loader_windows.h',

View File

@@ -280,6 +280,8 @@ EGLAttrib GetPlatformTypeFromEnvironment()
return 0;
#elif defined(ANGLE_USE_X11)
return EGL_PLATFORM_X11_EXT;
#elif defined(ANGLE_USE_WAYLAND)
return EGL_PLATFORM_WAYLAND_EXT;
#elif defined(ANGLE_USE_VULKAN_DISPLAY) && defined(ANGLE_VULKAN_DISPLAY_MODE_SIMPLE)
return EGL_PLATFORM_VULKAN_DISPLAY_MODE_SIMPLE_ANGLE;
#elif defined(ANGLE_USE_VULKAN_DISPLAY) && defined(ANGLE_VULKAN_DISPLAY_MODE_HEADLESS)
@@ -432,6 +434,13 @@ rx::DisplayImpl *CreateDisplayFromAttribs(EGLAttrib displayType,
break;
}
# endif
# if defined(ANGLE_USE_WAYLAND)
if (platformType == EGL_PLATFORM_WAYLAND_EXT && rx::IsVulkanWaylandDisplayAvailable())
{
impl = rx::CreateVulkanWaylandDisplay(state);
break;
}
# endif
# if defined(ANGLE_USE_VULKAN_DISPLAY)
if (platformType == EGL_PLATFORM_VULKAN_DISPLAY_MODE_SIMPLE_ANGLE &&
rx::IsVulkanSimpleDisplayAvailable())

View File

@@ -197,6 +197,15 @@ if (angle_use_x11) {
]
}
if (angle_use_wayland) {
_vulkan_backend_sources += [
"linux/wayland/DisplayVkWayland.cpp",
"linux/wayland/DisplayVkWayland.h",
"linux/wayland/WindowSurfaceVkWayland.cpp",
"linux/wayland/WindowSurfaceVkWayland.h",
]
}
if (is_fuchsia) {
_vulkan_backend_sources += [
"fuchsia/DisplayVkFuchsia.cpp",
@@ -292,6 +301,10 @@ angle_source_set("angle_vulkan_backend") {
]
public_configs = [ ":angle_vulkan_backend_config" ]
if (angle_use_wayland) {
public_configs += [ "$angle_root:angle_wayland_config" ]
}
data_deps = []
defines = []

View File

@@ -24,6 +24,9 @@ DisplayImpl *CreateVulkanWin32Display(const egl::DisplayState &state);
#endif // defined(ANGLE_PLATFORM_WINDOWS)
#if defined(ANGLE_PLATFORM_LINUX)
bool IsVulkanWaylandDisplayAvailable();
DisplayImpl *CreateVulkanWaylandDisplay(const egl::DisplayState &state);
bool IsVulkanXcbDisplayAvailable();
DisplayImpl *CreateVulkanXcbDisplay(const egl::DisplayState &state);

View File

@@ -5,8 +5,8 @@
//
// DisplayVkLinux.h:
// Defines the class interface for DisplayVkLinux, which is the base of DisplayVkSimple,
// DisplayVkHeadless and DisplayVkXcb. This base class implements the common functionality of
// handling Linux dma-bufs.
// DisplayVkHeadless, DisplayVkXcb and DisplayVkWayland. This base class implements the
// common functionality of handling Linux dma-bufs.
//
#ifndef LIBANGLE_RENDERER_VULKAN_DISPLAY_DISPLAYVKLINUX_H_

View File

@@ -0,0 +1,103 @@
//
// Copyright 2021-2022 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// DisplayVkWayland.cpp:
// Implements the class methods for DisplayVkWayland.
//
#include "libANGLE/renderer/vulkan/linux/wayland/DisplayVkWayland.h"
#include <wayland-client.h>
#include "common/system_utils.h"
#include "libANGLE/Display.h"
#include "libANGLE/renderer/vulkan/linux/wayland/WindowSurfaceVkWayland.h"
#include "libANGLE/renderer/vulkan/vk_caps_utils.h"
namespace rx
{
DisplayVkWayland::DisplayVkWayland(const egl::DisplayState &state)
: DisplayVkLinux(state), mWaylandDisplay(nullptr)
{}
egl::Error DisplayVkWayland::initialize(egl::Display *display)
{
mWaylandDisplay = reinterpret_cast<wl_display *>(display->getNativeDisplayId());
if (!mWaylandDisplay)
{
ERR() << "Failed to retrieve wayland display";
return egl::EglNotInitialized();
}
return DisplayVk::initialize(display);
}
void DisplayVkWayland::terminate()
{
mWaylandDisplay = nullptr;
DisplayVk::terminate();
}
bool DisplayVkWayland::isValidNativeWindow(EGLNativeWindowType window) const
{
// Wayland display Errors are fatal.
// If this function returns non-zero, the display is not valid anymore.
int error = wl_display_get_error(mWaylandDisplay);
if (error)
{
WARN() << "Wayland window is not valid: " << error << " " << strerror(error);
}
return error == 0;
}
SurfaceImpl *DisplayVkWayland::createWindowSurfaceVk(const egl::SurfaceState &state,
EGLNativeWindowType window)
{
return new WindowSurfaceVkWayland(state, window, mWaylandDisplay);
}
egl::ConfigSet DisplayVkWayland::generateConfigs()
{
const std::array<GLenum, 1> kColorFormats = {GL_BGRA8_EXT};
std::vector<GLenum> depthStencilFormats(
egl_vk::kConfigDepthStencilFormats,
egl_vk::kConfigDepthStencilFormats + ArraySize(egl_vk::kConfigDepthStencilFormats));
if (getCaps().stencil8)
{
depthStencilFormats.push_back(GL_STENCIL_INDEX8);
}
return egl_vk::GenerateConfigs(kColorFormats.data(), kColorFormats.size(),
depthStencilFormats.data(), depthStencilFormats.size(), this);
}
void DisplayVkWayland::checkConfigSupport(egl::Config *config)
{
// In wayland there is no native visual ID or type
}
const char *DisplayVkWayland::getWSIExtension() const
{
return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
}
bool IsVulkanWaylandDisplayAvailable()
{
wl_display *display = wl_display_connect(nullptr);
if (!display)
{
return false;
}
wl_display_disconnect(display);
return true;
}
DisplayImpl *CreateVulkanWaylandDisplay(const egl::DisplayState &state)
{
return new DisplayVkWayland(state);
}
} // namespace rx

View File

@@ -0,0 +1,44 @@
//
// Copyright 2021-2022 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// DisplayVkWayland.h:
// Defines the class interface for DisplayVkWayland, implementing DisplayVk for Wayland.
//
#ifndef LIBANGLE_RENDERER_VULKAN_WAYLAND_DISPLAYVKWAYLAND_H_
#define LIBANGLE_RENDERER_VULKAN_WAYLAND_DISPLAYVKWAYLAND_H_
#include "libANGLE/renderer/vulkan/linux/DisplayVkLinux.h"
struct wl_display;
namespace rx
{
class DisplayVkWayland : public DisplayVkLinux
{
public:
DisplayVkWayland(const egl::DisplayState &state);
egl::Error initialize(egl::Display *display) override;
void terminate() override;
bool isValidNativeWindow(EGLNativeWindowType window) const override;
SurfaceImpl *createWindowSurfaceVk(const egl::SurfaceState &state,
EGLNativeWindowType window) override;
egl::ConfigSet generateConfigs() override;
void checkConfigSupport(egl::Config *config) override;
const char *getWSIExtension() const override;
private:
wl_display *mWaylandDisplay;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_WAYLAND_DISPLAYVKWAYLAND_H_

View File

@@ -0,0 +1,67 @@
//
// Copyright 2021-2022 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// WindowSurfaceVkWayland.cpp:
// Implements the class methods for WindowSurfaceVkWayland.
//
#include "libANGLE/renderer/vulkan/linux/wayland/WindowSurfaceVkWayland.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include <wayland-egl-backend.h>
namespace rx
{
void WindowSurfaceVkWayland::ResizeCallback(wl_egl_window *eglWindow, void *payload)
{
WindowSurfaceVkWayland *windowSurface = reinterpret_cast<WindowSurfaceVkWayland *>(payload);
windowSurface->mExtents.width = eglWindow->width;
windowSurface->mExtents.height = eglWindow->height;
}
WindowSurfaceVkWayland::WindowSurfaceVkWayland(const egl::SurfaceState &surfaceState,
EGLNativeWindowType window,
wl_display *display)
: WindowSurfaceVk(surfaceState, window), mWaylandDisplay(display)
{
wl_egl_window *eglWindow = reinterpret_cast<wl_egl_window *>(window);
eglWindow->resize_callback = WindowSurfaceVkWayland::ResizeCallback;
eglWindow->driver_private = this;
mExtents = gl::Extents(eglWindow->width, eglWindow->height, 1);
}
angle::Result WindowSurfaceVkWayland::createSurfaceVk(vk::Context *context, gl::Extents *extentsOut)
{
ANGLE_VK_CHECK(context,
vkGetPhysicalDeviceWaylandPresentationSupportKHR(
context->getRenderer()->getPhysicalDevice(), 0, mWaylandDisplay),
VK_ERROR_INITIALIZATION_FAILED);
wl_egl_window *eglWindow = reinterpret_cast<wl_egl_window *>(mNativeWindowType);
VkWaylandSurfaceCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
createInfo.flags = 0;
createInfo.display = mWaylandDisplay;
createInfo.surface = eglWindow->surface;
ANGLE_VK_TRY(context, vkCreateWaylandSurfaceKHR(context->getRenderer()->getInstance(),
&createInfo, nullptr, &mSurface));
return getCurrentWindowSize(context, extentsOut);
}
angle::Result WindowSurfaceVkWayland::getCurrentWindowSize(vk::Context *context,
gl::Extents *extentsOut)
{
*extentsOut = mExtents;
return angle::Result::Continue;
}
} // namespace rx

View File

@@ -0,0 +1,40 @@
//
// Copyright 2021-2022 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// WindowSurfaceVkWayland.h:
// Defines the class interface for WindowSurfaceVkWayland, implementing WindowSurfaceVk.
//
#ifndef LIBANGLE_RENDERER_VULKAN_WAYLAND_WINDOWSURFACEVKWAYLAND_H_
#define LIBANGLE_RENDERER_VULKAN_WAYLAND_WINDOWSURFACEVKWAYLAND_H_
#include "libANGLE/renderer/vulkan/SurfaceVk.h"
struct wl_display;
struct wl_egl_window;
namespace rx
{
class WindowSurfaceVkWayland : public WindowSurfaceVk
{
public:
static void ResizeCallback(wl_egl_window *window, void *payload);
WindowSurfaceVkWayland(const egl::SurfaceState &surfaceState,
EGLNativeWindowType window,
wl_display *display);
private:
angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override;
angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) override;
wl_display *mWaylandDisplay;
gl::Extents mExtents;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_WAYLAND_WINDOWSURFACEVKWAYLAND_H_

View File

@@ -147,6 +147,12 @@ const char *DisplayVkXcb::getWSIExtension() const
bool IsVulkanXcbDisplayAvailable()
{
Display *display = XOpenDisplay(nullptr);
if (!display)
{
return false;
}
XCloseDisplay(display);
return true;
}

View File

@@ -243,6 +243,9 @@ if (is_win || is_linux || is_chromeos || is_android || is_fuchsia || is_apple) {
if (angle_use_x11) {
sources += [ "egl_tests/EGLX11VisualTest.cpp" ]
}
if (angle_use_wayland) {
sources += [ "egl_tests/EGLWaylandTest.cpp" ]
}
configs += [ "${angle_root}:libANGLE_config" ]

View File

@@ -0,0 +1,154 @@
//
// Copyright 2022 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// EGLWaylandTest.cpp: tests for EGL_EXT_platform_wayland
#include <gtest/gtest.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <wayland-client.h>
#include <wayland-egl-backend.h>
#include "test_utils/ANGLETest.h"
#include "util/linux/wayland/WaylandWindow.h"
using namespace angle;
namespace
{
const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
}
class EGLWaylandTest : public ANGLETest
{
public:
std::vector<EGLint> getDisplayAttributes() const
{
std::vector<EGLint> attribs;
attribs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
attribs.push_back(GetParam().getRenderer());
attribs.push_back(EGL_NONE);
return attribs;
}
void testSetUp() override
{
mOsWindow = WaylandWindow::New();
ASSERT_TRUE(mOsWindow->initialize("EGLWaylandTest", 500, 500));
setWindowVisible(mOsWindow, true);
EGLNativeDisplayType waylandDisplay = mOsWindow->getNativeDisplay();
std::vector<EGLint> attribs = getDisplayAttributes();
mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, (void *)waylandDisplay,
attribs.data());
ASSERT_NE(EGL_NO_DISPLAY, mDisplay);
ASSERT_TRUE(EGL_TRUE == eglInitialize(mDisplay, nullptr, nullptr));
int nConfigs = 0;
ASSERT_TRUE(EGL_TRUE == eglGetConfigs(mDisplay, nullptr, 0, &nConfigs));
ASSERT_GE(nConfigs, 1);
int nReturnedConfigs = 0;
mConfigs.resize(nConfigs);
ASSERT_TRUE(EGL_TRUE ==
eglGetConfigs(mDisplay, mConfigs.data(), nConfigs, &nReturnedConfigs));
ASSERT_EQ(nConfigs, nReturnedConfigs);
}
void testTearDown() override
{
mConfigs.clear();
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(mDisplay);
OSWindow::Delete(&mOsWindow);
}
OSWindow *mOsWindow;
EGLDisplay mDisplay;
std::vector<EGLConfig> mConfigs;
};
// Test that a Wayland window can be created and used for rendering
TEST_P(EGLWaylandTest, WaylandWindowRendering)
{
for (EGLConfig config : mConfigs)
{
// Finally, try to do a clear on the window.
EGLContext context = eglCreateContext(mDisplay, config, EGL_NO_CONTEXT, contextAttribs);
ASSERT_NE(EGL_NO_CONTEXT, context);
EGLSurface window =
eglCreateWindowSurface(mDisplay, config, mOsWindow->getNativeWindow(), nullptr);
ASSERT_EGL_SUCCESS();
eglMakeCurrent(mDisplay, window, window, context);
ASSERT_EGL_SUCCESS();
glViewport(0, 0, 500, 500);
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(250, 250, 0, 0, 255, 255);
// Teardown
eglDestroySurface(mDisplay, window);
ASSERT_EGL_SUCCESS();
eglDestroyContext(mDisplay, context);
ASSERT_EGL_SUCCESS();
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
ASSERT_EGL_SUCCESS();
}
}
// Test that a Wayland window can swap buffers multiple times with no issues
TEST_P(EGLWaylandTest, SwapBuffers)
{
for (EGLConfig config : mConfigs)
{
EGLContext context = eglCreateContext(mDisplay, config, EGL_NO_CONTEXT, contextAttribs);
ASSERT_NE(EGL_NO_CONTEXT, context);
EGLSurface surface =
eglCreateWindowSurface(mDisplay, config, mOsWindow->getNativeWindow(), nullptr);
ASSERT_EGL_SUCCESS();
eglMakeCurrent(mDisplay, surface, surface, context);
ASSERT_EGL_SUCCESS();
const uint32_t loopcount = 16;
for (uint32_t i = 0; i < loopcount; i++)
{
mOsWindow->messageLoop();
glViewport(0, 0, 500, 500);
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR() << "glClear failed";
EXPECT_PIXEL_EQ(250, 250, 0, 0, 255, 255);
eglSwapBuffers(mDisplay, surface);
ASSERT_EGL_SUCCESS() << "eglSwapBuffers failed.";
}
// Teardown
eglDestroySurface(mDisplay, surface);
ASSERT_EGL_SUCCESS();
eglDestroyContext(mDisplay, context);
ASSERT_EGL_SUCCESS();
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
ASSERT_EGL_SUCCESS();
}
}
ANGLE_INSTANTIATE_TEST(EGLWaylandTest, WithNoFixture(ES2_VULKAN()));

View File

@@ -14,7 +14,7 @@
#include "test_utils/ANGLETest.h"
#include "util/OSWindow.h"
#include "util/x11/X11Window.h"
#include "util/linux/x11/X11Window.h"
using namespace angle;

View File

@@ -51,13 +51,24 @@ if (is_linux) {
if (angle_use_x11) {
_util_sources += [
"x11/X11Pixmap.cpp",
"x11/X11Pixmap.h",
"x11/X11Window.cpp",
"x11/X11Window.h",
"linux/x11/X11Pixmap.cpp",
"linux/x11/X11Pixmap.h",
"linux/x11/X11Window.cpp",
"linux/x11/X11Window.h",
]
}
if (angle_use_wayland) {
_util_sources += [
"linux/wayland/WaylandWindow.cpp",
"linux/wayland/WaylandWindow.h",
]
}
if (angle_use_x11 || angle_use_wayland) {
_util_sources += [ "linux/LinuxWindow.cpp" ]
}
if (is_fuchsia) {
_util_sources += [
"fuchsia/FuchsiaPixmap.cpp",
@@ -309,7 +320,12 @@ config("angle_test_util_config") {
angle_source_set("angle_test_utils") {
public_configs = [ ":angle_test_util_config" ]
public_deps = [ "$angle_root:angle_common" ]
if (angle_use_wayland) {
public_deps += [ "$angle_root:angle_wayland" ]
}
deps = []
sources = [
"Timer.cpp",

View File

@@ -79,7 +79,7 @@ void DisplayWindow::signalTestEvent()
}
// static
#if defined(ANGLE_USE_VULKAN_DISPLAY) && defined(EGL_NO_X11)
#if defined(ANGLE_USE_VULKAN_DISPLAY) && defined(EGL_NO_X11) && !defined(ANGLE_USE_WAYLAND)
OSWindow *OSWindow::New()
{
return new DisplayWindow();

View File

@@ -0,0 +1,40 @@
//
// Copyright 2022 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// LinuxWindow.cpp: Implementation of OSWindow::New for Linux
#include "util/OSWindow.h"
#if defined(ANGLE_USE_WAYLAND)
# include "wayland/WaylandWindow.h"
#endif
#if defined(ANGLE_USE_X11)
# include "x11/X11Window.h"
#endif
// static
#if defined(ANGLE_USE_X11) || defined(ANGLE_USE_WAYLAND)
OSWindow *OSWindow::New()
{
# if defined(ANGLE_USE_X11)
// Prefer X11
if (IsX11WindowAvailable())
{
return new X11Window();
}
# endif
# if defined(ANGLE_USE_WAYLAND)
if (IsWaylandWindowAvailable())
{
return new WaylandWindow();
}
# endif
return nullptr;
}
#endif

View File

@@ -0,0 +1,182 @@
//
// Copyright 2022 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// WaylandWindow.cpp: Implementation of OSWindow for Wayland
#include "util/linux/wayland/WaylandWindow.h"
WaylandWindow::WaylandWindow()
: mDisplay{nullptr}, mCompositor{nullptr}, mSurface{nullptr}, mWindow{nullptr}
{}
WaylandWindow::~WaylandWindow()
{
destroy();
}
void WaylandWindow::RegistryHandleGlobal(void *data,
struct wl_registry *registry,
uint32_t name,
const char *interface,
uint32_t version)
{
WaylandWindow *vc = reinterpret_cast<WaylandWindow *>(data);
if (strcmp(interface, "wl_compositor") == 0)
{
void *compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
vc->mCompositor = reinterpret_cast<wl_compositor *>(compositor);
}
}
void WaylandWindow::RegistryHandleGlobalRemove(void *data,
struct wl_registry *registry,
uint32_t name)
{}
const struct wl_registry_listener WaylandWindow::registryListener = {
WaylandWindow::RegistryHandleGlobal, WaylandWindow::RegistryHandleGlobalRemove};
bool WaylandWindow::initializeImpl(const std::string &name, int width, int height)
{
destroy();
if (!mDisplay)
{
mDisplay = wl_display_connect(nullptr);
if (!mDisplay)
{
return false;
}
}
// Not get a window
struct wl_registry *registry = wl_display_get_registry(mDisplay);
wl_registry_add_listener(registry, &registryListener, this);
// Round-trip to get globals
wl_display_roundtrip(mDisplay);
if (!mCompositor)
{
return false;
}
// We don't need this anymore
wl_registry_destroy(registry);
mSurface = wl_compositor_create_surface(mCompositor);
if (!mSurface)
{
return false;
}
mWindow = wl_egl_window_create(mSurface, width, height);
if (!mWindow)
{
return false;
}
fds[0] = {wl_display_get_fd(mDisplay), POLLIN, 0};
mY = 0;
mX = 0;
mWidth = width;
mHeight = height;
return true;
}
void WaylandWindow::disableErrorMessageDialog() {}
void WaylandWindow::destroy()
{
if (mWindow)
{
wl_egl_window_destroy(mWindow);
mWindow = nullptr;
}
if (mSurface)
{
wl_surface_destroy(mSurface);
mSurface = nullptr;
}
if (mCompositor)
{
wl_compositor_destroy(mCompositor);
mCompositor = nullptr;
}
}
void WaylandWindow::resetNativeWindow() {}
EGLNativeWindowType WaylandWindow::getNativeWindow() const
{
return reinterpret_cast<EGLNativeWindowType>(mWindow);
}
EGLNativeDisplayType WaylandWindow::getNativeDisplay() const
{
return reinterpret_cast<EGLNativeDisplayType>(mDisplay);
}
void WaylandWindow::messageLoop()
{
while (wl_display_prepare_read(mDisplay) != 0)
wl_display_dispatch_pending(mDisplay);
if (wl_display_flush(mDisplay) < 0 && errno != EAGAIN)
{
wl_display_cancel_read(mDisplay);
return;
}
if (poll(fds, 1, 0) > 0)
{
wl_display_read_events(mDisplay);
wl_display_dispatch_pending(mDisplay);
}
else
{
wl_display_cancel_read(mDisplay);
}
}
void WaylandWindow::setMousePosition(int x, int y) {}
bool WaylandWindow::setOrientation(int width, int height)
{
return true;
}
bool WaylandWindow::setPosition(int x, int y)
{
return true;
}
bool WaylandWindow::resize(int width, int height)
{
wl_egl_window_resize(mWindow, width, height, 0, 0);
mWidth = width;
mHeight = height;
return true;
}
void WaylandWindow::setVisible(bool isVisible) {}
void WaylandWindow::signalTestEvent() {}
bool IsWaylandWindowAvailable()
{
wl_display *display = wl_display_connect(nullptr);
if (!display)
{
return false;
}
wl_display_disconnect(display);
return true;
}

View File

@@ -0,0 +1,64 @@
//
// Copyright 2022 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// WaylandWindow.h: Definition of the implementation of OSWindow for Wayland
#ifndef UTIL_WAYLAND_WINDOW_H
#define UTIL_WAYLAND_WINDOW_H
#include <poll.h>
#include <wayland-client.h>
#include <wayland-egl-core.h>
#include "util/OSWindow.h"
#include "util/util_export.h"
bool IsWaylandWindowAvailable();
class ANGLE_UTIL_EXPORT WaylandWindow : public OSWindow
{
public:
WaylandWindow();
~WaylandWindow() override;
void disableErrorMessageDialog() override;
void destroy() override;
void resetNativeWindow() override;
EGLNativeWindowType getNativeWindow() const override;
EGLNativeDisplayType getNativeDisplay() const override;
void messageLoop() override;
void setMousePosition(int x, int y) override;
bool setOrientation(int width, int height) override;
bool setPosition(int x, int y) override;
bool resize(int width, int height) override;
void setVisible(bool isVisible) override;
void signalTestEvent() override;
private:
static void RegistryHandleGlobal(void *data,
struct wl_registry *registry,
uint32_t name,
const char *interface,
uint32_t version);
static void RegistryHandleGlobalRemove(void *data, struct wl_registry *registry, uint32_t name);
bool initializeImpl(const std::string &name, int width, int height) override;
static const struct wl_registry_listener registryListener;
struct wl_display *mDisplay;
struct wl_compositor *mCompositor;
struct wl_surface *mSurface;
struct wl_egl_window *mWindow;
struct pollfd fds[1];
};
#endif // UTIL_WAYLAND_WINDOW_H

View File

@@ -6,7 +6,7 @@
// X11Pixmap.cpp: Implementation of OSPixmap for X11
#include "util/x11/X11Pixmap.h"
#include "util/linux/x11/X11Pixmap.h"
X11Pixmap::X11Pixmap() : mPixmap(0), mDisplay(nullptr) {}

View File

@@ -6,7 +6,7 @@
// X11Window.cpp: Implementation of OSWindow for X11
#include "util/x11/X11Window.h"
#include "util/linux/x11/X11Window.h"
#include "common/debug.h"
#include "util/Timer.h"
@@ -722,8 +722,13 @@ void X11Window::processEvent(const XEvent &xEvent)
}
}
// static
OSWindow *OSWindow::New()
bool IsX11WindowAvailable()
{
return new X11Window();
Display *display = XOpenDisplay(nullptr);
if (!display)
{
return false;
}
XCloseDisplay(display);
return true;
}

View File

@@ -17,6 +17,8 @@
#include "util/OSWindow.h"
#include "util/util_export.h"
bool IsX11WindowAvailable();
class ANGLE_UTIL_EXPORT X11Window : public OSWindow
{
public: