// // Copyright 2016 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. // // DisplayVkXcb.cpp: // Implements the class methods for DisplayVkXcb. // #include "libANGLE/renderer/vulkan/linux/xcb/DisplayVkXcb.h" #include #include #include "common/system_utils.h" #include "libANGLE/Display.h" #include "libANGLE/renderer/vulkan/linux/xcb/WindowSurfaceVkXcb.h" #include "libANGLE/renderer/vulkan/vk_caps_utils.h" namespace rx { namespace { EGLint GetXcbVisualType(xcb_screen_t *screen) { // Visual type is the class member of xcb_visualtype_t whose id matches the root visual. for (xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(screen); depth_iter.rem; xcb_depth_next(&depth_iter)) { for (xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data); visual_iter.rem; xcb_visualtype_next(&visual_iter)) { if (screen->root_visual == visual_iter.data->visual_id) { return visual_iter.data->_class; } } } return EGL_NONE; } } // namespace DisplayVkXcb::DisplayVkXcb(const egl::DisplayState &state) : DisplayVkLinux(state), mXcbConnection(nullptr), mHasXDisplay(false) {} egl::Error DisplayVkXcb::initialize(egl::Display *display) { mHasXDisplay = !angle::GetEnvironmentVar("DISPLAY").empty(); if (mHasXDisplay) { mXcbConnection = xcb_connect(nullptr, nullptr); ASSERT(mXcbConnection != nullptr); int xcb_connection_error = xcb_connection_has_error(mXcbConnection); if (xcb_connection_error) { ERR() << "xcb_connect() failed, error " << xcb_connection_error; xcb_disconnect(mXcbConnection); mXcbConnection = nullptr; return egl::EglNotInitialized(); } } return DisplayVk::initialize(display); } void DisplayVkXcb::terminate() { if (mHasXDisplay) { ASSERT(mXcbConnection != nullptr); xcb_disconnect(mXcbConnection); mXcbConnection = nullptr; } DisplayVk::terminate(); } bool DisplayVkXcb::isValidNativeWindow(EGLNativeWindowType window) const { ASSERT(mHasXDisplay); // There doesn't appear to be an xcb function explicitly for checking the validity of a // window ID, but xcb_query_tree_reply will return nullptr if the window doesn't exist. xcb_query_tree_cookie_t cookie = xcb_query_tree(mXcbConnection, static_cast(window)); xcb_query_tree_reply_t *reply = xcb_query_tree_reply(mXcbConnection, cookie, nullptr); if (reply) { free(reply); return true; } return false; } SurfaceImpl *DisplayVkXcb::createWindowSurfaceVk(const egl::SurfaceState &state, EGLNativeWindowType window) { ASSERT(mHasXDisplay); return new WindowSurfaceVkXcb(state, window, mXcbConnection); } egl::ConfigSet DisplayVkXcb::generateConfigs() { const std::array kColorFormats = {GL_BGRA8_EXT}; std::vector 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 DisplayVkXcb::checkConfigSupport(egl::Config *config) { // If no window system, cannot support windows. if (!mHasXDisplay) { // No window support if no X11. config->surfaceType &= ~EGL_WINDOW_BIT; return; } // TODO(geofflang): Test for native support and modify the config accordingly. // http://anglebug.com/2692 // Find the screen the window was created on: xcb_screen_iterator_t screenIterator = xcb_setup_roots_iterator(xcb_get_setup(mXcbConnection)); ASSERT(screenIterator.rem); xcb_screen_t *screen = screenIterator.data; ASSERT(screen); // Visual id is root_visual of the screen config->nativeVisualID = screen->root_visual; config->nativeVisualType = GetXcbVisualType(screen); } const char *DisplayVkXcb::getWSIExtension() const { return VK_KHR_XCB_SURFACE_EXTENSION_NAME; } bool IsVulkanXcbDisplayAvailable() { return true; } DisplayImpl *CreateVulkanXcbDisplay(const egl::DisplayState &state) { return new DisplayVkXcb(state); } angle::Result DisplayVkXcb::waitNativeImpl() { XSync(reinterpret_cast(mState.displayId), False); return angle::Result::Continue; } } // namespace rx