Implement DisplayVkWayland and WindowSurfaceVkWayland. Get window size
from native window and check egl config is just empty.

Then add an EGL wayland test for testing rendering and buffers swapping.

Bug: angleproject:6902
Change-Id: I8204a5cc99f26330b74caba241bebf14c5650c2d
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3395898
Reviewed-by: mohan maiya <m.maiya@samsung.com>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Auto-Submit: Antonio Caggiano <antonio.caggiano@collabora.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Antonio Caggiano 2021-12-09 16:52:35 +01:00 коммит произвёл Angle LUCI CQ
Родитель ea86cfd2e3
Коммит 510351f200
23 изменённых файлов: 794 добавлений и 13 удалений

Просмотреть файл

@ -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" ]
}
@ -1018,6 +1035,27 @@ angle_source_set("angle_gl_enum_utils") {
]
}
if (angle_use_wayland) {
config("angle_wayland_config") {
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(angle_abseil_cpp_dir)) {
angle_abseil_cpp_dir = "//third_party/abseil-cpp"
}

Просмотреть файл

@ -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',

Просмотреть файл

@ -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())

Просмотреть файл

@ -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 = []

Просмотреть файл

@ -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);

Просмотреть файл

@ -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_

Просмотреть файл

@ -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

Просмотреть файл

@ -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_

Просмотреть файл

@ -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

Просмотреть файл

@ -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_

Просмотреть файл

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

Просмотреть файл

@ -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" ]

Просмотреть файл

@ -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()));

Просмотреть файл

@ -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;

Просмотреть файл

@ -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",

Просмотреть файл

@ -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();

Просмотреть файл

@ -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

Просмотреть файл

@ -0,0 +1,173 @@
//
// 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};
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);
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;
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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) {}

Просмотреть файл

Просмотреть файл

@ -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;
}

Просмотреть файл

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