mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-03 14:09:33 +03:00
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:
committed by
Angle LUCI CQ
parent
ea9a2dbeac
commit
e0dd196a0e
49
BUILD.gn
49
BUILD.gn
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
|
||||
103
src/libANGLE/renderer/vulkan/linux/wayland/DisplayVkWayland.cpp
Normal file
103
src/libANGLE/renderer/vulkan/linux/wayland/DisplayVkWayland.cpp
Normal 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
|
||||
@@ -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" ]
|
||||
|
||||
|
||||
154
src/tests/egl_tests/EGLWaylandTest.cpp
Normal file
154
src/tests/egl_tests/EGLWaylandTest.cpp
Normal 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()));
|
||||
@@ -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();
|
||||
|
||||
40
util/linux/LinuxWindow.cpp
Normal file
40
util/linux/LinuxWindow.cpp
Normal 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
|
||||
182
util/linux/wayland/WaylandWindow.cpp
Normal file
182
util/linux/wayland/WaylandWindow.cpp
Normal 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, ®istryListener, 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;
|
||||
}
|
||||
64
util/linux/wayland/WaylandWindow.h
Normal file
64
util/linux/wayland/WaylandWindow.h
Normal 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
|
||||
@@ -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:
|
||||
Reference in New Issue
Block a user