Reland "Vulkan: Fallback to XCB for Xlib surfaces"

This is a reland of fb0bf70459

Reland after making libx11-xcb dynamically loaded since it isn't present
on all Linux deployment targets of Chromium. Also includes a couple of
additional cosmetic changes to d3d12/PlatformFunctions noticed while
looking at it for inspiration.

Original change's description:
> Vulkan: Fallback to XCB for Xlib surfaces
>
> Chromium builds the Vulkan loader without support Xlib (because it
> prefers XCB) which caused Xlib wgpu::SwapChain creation to fail on the
> Vulkan backend.
>
> This CL adds a fallback to use VK_KHR_xcb_surface if VK_KHR_xlib_surface
> isn't present.
>
> Bug: dawn:662
> Change-Id: I0e0128ee6b5c75da03998dbae231d17e48bacc81
> Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/41180
> Reviewed-by: Austin Eng <enga@chromium.org>
> Commit-Queue: Austin Eng <enga@chromium.org>
> Auto-Submit: Corentin Wallez <cwallez@chromium.org>

Bug: dawn:662
Change-Id: I617fcd1059dddfa05c29ac20d77f891ca6962342
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/41380
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Auto-Submit: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Corentin Wallez 2021-02-11 08:26:38 +00:00 committed by Commit Bot service account
parent 7e80cce1a9
commit aa0e1be0e8
13 changed files with 153 additions and 8 deletions

View File

@ -162,6 +162,7 @@ namespace dawn_native { namespace vulkan {
#if defined(DAWN_USE_X11) #if defined(DAWN_USE_X11)
# define VK_USE_PLATFORM_XLIB_KHR # define VK_USE_PLATFORM_XLIB_KHR
# define VK_USE_PLATFORM_XCB_KHR
# include "common/xlib_with_undefs.h" # include "common/xlib_with_undefs.h"
#endif // defined(DAWN_USE_X11) #endif // defined(DAWN_USE_X11)

View File

@ -26,6 +26,10 @@
// interface. // interface.
#include <X11/Xlib.h> #include <X11/Xlib.h>
// Xlib-xcb.h technically includes Xlib.h but we separate the includes to make it more clear what
// the problem is if one of these two includes fail.
#include <X11/Xlib-xcb.h>
#undef Success #undef Success
#undef None #undef None
#undef Always #undef Always

View File

@ -296,6 +296,10 @@ source_set("dawn_native_sources") {
if (dawn_use_x11) { if (dawn_use_x11) {
libs += [ "X11" ] libs += [ "X11" ]
sources += [
"XlibXcbFunctions.cpp",
"XlibXcbFunctions.h",
]
} }
if (is_win) { if (is_win) {

View File

@ -181,6 +181,7 @@ target_link_libraries(dawn_native
if (DAWN_USE_X11) if (DAWN_USE_X11)
find_package(X11 REQUIRED) find_package(X11 REQUIRED)
target_link_libraries(dawn_native PRIVATE ${X11_LIBRARIES}) target_link_libraries(dawn_native PRIVATE ${X11_LIBRARIES})
target_include_directories(dawn_native PRIVATE ${X11_INCLUDE_DIR})
endif() endif()
if (WIN32) if (WIN32)

View File

@ -19,6 +19,10 @@
#include "dawn_native/ErrorData.h" #include "dawn_native/ErrorData.h"
#include "dawn_native/Surface.h" #include "dawn_native/Surface.h"
#if defined(DAWN_USE_X11)
# include "dawn_native/XlibXcbFunctions.h"
#endif // defined(DAWN_USE_X11)
namespace dawn_native { namespace dawn_native {
// Forward definitions of each backend's "Connect" function that creates new BackendConnection. // Forward definitions of each backend's "Connect" function that creates new BackendConnection.
@ -223,6 +227,17 @@ namespace dawn_native {
return mPlatform; return mPlatform;
} }
const XlibXcbFunctions* InstanceBase::GetOrCreateXlibXcbFunctions() {
#if defined(DAWN_USE_X11)
if (mXlibXcbFunctions == nullptr) {
mXlibXcbFunctions = std::make_unique<XlibXcbFunctions>();
}
return mXlibXcbFunctions.get();
#else
UNREACHABLE();
#endif // defined(DAWN_USE_X11)
}
Surface* InstanceBase::CreateSurface(const SurfaceDescriptor* descriptor) { Surface* InstanceBase::CreateSurface(const SurfaceDescriptor* descriptor) {
if (ConsumedError(ValidateSurfaceDescriptor(this, descriptor))) { if (ConsumedError(ValidateSurfaceDescriptor(this, descriptor))) {
return nullptr; return nullptr;

View File

@ -30,6 +30,7 @@
namespace dawn_native { namespace dawn_native {
class Surface; class Surface;
class XlibXcbFunctions;
// This is called InstanceBase for consistency across the frontend, even if the backends don't // This is called InstanceBase for consistency across the frontend, even if the backends don't
// specialize this class. // specialize this class.
@ -67,6 +68,9 @@ namespace dawn_native {
void SetPlatform(dawn_platform::Platform* platform); void SetPlatform(dawn_platform::Platform* platform);
dawn_platform::Platform* GetPlatform() const; dawn_platform::Platform* GetPlatform() const;
// Get backend-independent libraries that need to be loaded dynamically.
const XlibXcbFunctions* GetOrCreateXlibXcbFunctions();
// Dawn API // Dawn API
Surface* CreateSurface(const SurfaceDescriptor* descriptor); Surface* CreateSurface(const SurfaceDescriptor* descriptor);
@ -97,6 +101,10 @@ namespace dawn_native {
ExtensionsInfo mExtensionsInfo; ExtensionsInfo mExtensionsInfo;
TogglesInfo mTogglesInfo; TogglesInfo mTogglesInfo;
#if defined(DAWN_USE_X11)
std::unique_ptr<XlibXcbFunctions> mXlibXcbFunctions;
#endif // defined(DAWN_USE_X11)
}; };
} // namespace dawn_native } // namespace dawn_native

View File

@ -0,0 +1,31 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_native/XlibXcbFunctions.h"
namespace dawn_native {
XlibXcbFunctions::XlibXcbFunctions() {
if (!mLib.Open("libX11-xcb.so.1") ||
!mLib.GetProc(&xGetXCBConnection, "XGetXCBConnection")) {
mLib.Close();
}
}
XlibXcbFunctions::~XlibXcbFunctions() = default;
bool XlibXcbFunctions::IsLoaded() const {
return xGetXCBConnection != nullptr;
}
} // namespace dawn_native

View File

@ -0,0 +1,46 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNNATIVE_XLIBXCBFUNCTIONS_H_
#define DAWNNATIVE_XLIBXCBFUNCTIONS_H_
#include "common/DynamicLib.h"
#include "dawn_native/Error.h"
#include "common/xlib_with_undefs.h"
class DynamicLib;
namespace dawn_native {
// A helper class that dynamically loads the x11-xcb library that contains XGetXCBConnection
// (and nothing else). This has to be dynamic because this libraries isn't present on all Linux
// deployment platforms that Chromium targets.
class XlibXcbFunctions {
public:
XlibXcbFunctions();
~XlibXcbFunctions();
bool IsLoaded() const;
// Functions from x11-xcb
decltype(&::XGetXCBConnection) xGetXCBConnection = nullptr;
private:
DynamicLib mLib;
};
} // namespace dawn_native
#endif // DAWNNATIVE_XLIBXCBFUNCTIONS_H_

View File

@ -100,10 +100,8 @@ namespace dawn_native { namespace d3d12 {
} }
} // anonymous namespace } // anonymous namespace
PlatformFunctions::PlatformFunctions() { PlatformFunctions::PlatformFunctions() = default;
} PlatformFunctions::~PlatformFunctions() = default;
PlatformFunctions::~PlatformFunctions() {
}
MaybeError PlatformFunctions::LoadFunctions() { MaybeError PlatformFunctions::LoadFunctions() {
DAWN_TRY(LoadD3D12()); DAWN_TRY(LoadD3D12());

View File

@ -22,8 +22,6 @@
#include <d3dcompiler.h> #include <d3dcompiler.h>
class DynamicLib;
namespace dawn_native { namespace d3d12 { namespace dawn_native { namespace d3d12 {
// Loads the functions required from the platform dynamically so that we don't need to rely on // Loads the functions required from the platform dynamically so that we don't need to rely on
@ -108,4 +106,4 @@ namespace dawn_native { namespace d3d12 {
}} // namespace dawn_native::d3d12 }} // namespace dawn_native::d3d12
#endif // DAWNNATIVE_VULKAN_VULKANFUNCTIONS_H_ #endif // DAWNNATIVE_D3D12_PLATFORMFUNCTIONS_H_

View File

@ -15,6 +15,7 @@
#include "dawn_native/vulkan/SwapChainVk.h" #include "dawn_native/vulkan/SwapChainVk.h"
#include "common/Compiler.h" #include "common/Compiler.h"
#include "dawn_native/Instance.h"
#include "dawn_native/Surface.h" #include "dawn_native/Surface.h"
#include "dawn_native/vulkan/AdapterVk.h" #include "dawn_native/vulkan/AdapterVk.h"
#include "dawn_native/vulkan/BackendVk.h" #include "dawn_native/vulkan/BackendVk.h"
@ -25,6 +26,10 @@
#include <algorithm> #include <algorithm>
#if defined(DAWN_USE_X11)
# include "dawn_native/XlibXcbFunctions.h"
#endif // defined(DAWN_USE_X11)
namespace dawn_native { namespace vulkan { namespace dawn_native { namespace vulkan {
// OldSwapChain // OldSwapChain
@ -130,7 +135,7 @@ namespace dawn_native { namespace vulkan {
#endif // defined(DAWN_PLATFORM_WINDOWS) #endif // defined(DAWN_PLATFORM_WINDOWS)
#if defined(DAWN_USE_X11) #if defined(DAWN_USE_X11)
case Surface::Type::Xlib: case Surface::Type::Xlib: {
if (info.HasExt(InstanceExt::XlibSurface)) { if (info.HasExt(InstanceExt::XlibSurface)) {
VkXlibSurfaceCreateInfoKHR createInfo; VkXlibSurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
@ -145,7 +150,32 @@ namespace dawn_native { namespace vulkan {
"CreateXlibSurface")); "CreateXlibSurface"));
return vkSurface; return vkSurface;
} }
// Fall back to using XCB surfaces if the Xlib extension isn't available.
// See https://xcb.freedesktop.org/MixingCalls/ for more information about
// interoperability between Xlib and XCB
const XlibXcbFunctions* xlibXcb =
backend->GetInstance()->GetOrCreateXlibXcbFunctions();
ASSERT(xlibXcb != nullptr);
if (info.HasExt(InstanceExt::XcbSurface) && xlibXcb->IsLoaded()) {
VkXcbSurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = nullptr;
createInfo.flags = 0;
// The XCB connection lives as long as the X11 display.
createInfo.connection = xlibXcb->xGetXCBConnection(
static_cast<Display*>(surface->GetXDisplay()));
createInfo.window = surface->GetXWindow();
VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
DAWN_TRY(CheckVkSuccess(
fn.CreateXcbSurfaceKHR(instance, &createInfo, nullptr, &*vkSurface),
"CreateXcbSurfaceKHR"));
return vkSurface;
}
break; break;
}
#endif // defined(DAWN_USE_X11) #endif // defined(DAWN_USE_X11)
default: default:

View File

@ -152,6 +152,10 @@ namespace dawn_native { namespace vulkan {
GET_INSTANCE_PROC(CreateXlibSurfaceKHR); GET_INSTANCE_PROC(CreateXlibSurfaceKHR);
GET_INSTANCE_PROC(GetPhysicalDeviceXlibPresentationSupportKHR); GET_INSTANCE_PROC(GetPhysicalDeviceXlibPresentationSupportKHR);
} }
if (globalInfo.HasExt(InstanceExt::XcbSurface)) {
GET_INSTANCE_PROC(CreateXcbSurfaceKHR);
GET_INSTANCE_PROC(GetPhysicalDeviceXcbPresentationSupportKHR);
}
#endif // defined(DAWN_USE_X11) #endif // defined(DAWN_USE_X11)
return {}; return {};
} }

View File

@ -137,6 +137,11 @@ namespace dawn_native { namespace vulkan {
PFN_vkCreateXlibSurfaceKHR CreateXlibSurfaceKHR = nullptr; PFN_vkCreateXlibSurfaceKHR CreateXlibSurfaceKHR = nullptr;
PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR
GetPhysicalDeviceXlibPresentationSupportKHR = nullptr; GetPhysicalDeviceXlibPresentationSupportKHR = nullptr;
// KHR_xcb_surface
PFN_vkCreateXcbSurfaceKHR CreateXcbSurfaceKHR = nullptr;
PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR
GetPhysicalDeviceXcbPresentationSupportKHR = nullptr;
#endif // defined(DAWN_USE_X11) #endif // defined(DAWN_USE_X11)
// ---------- Device procs // ---------- Device procs