PlatformVkLinux now supports all combos of XLIB and XCB.

You can now build Filament with support for both X11 APIs, or neither.
If both are supported, run-time selection is achieved using a SwapChain
flag.

Supporting only one API at build time (or neither) is useful because our
list of "required" VkInstance extensions can vary according to which
API's are supported. During VkInstance creation, we do not have a priori
knowledge about what kinds of swap chains will be created. (headless vs
non-headless, XCB vs XLIB, etc)

Note that some Vulkan implementation (e.g. some builds of SwiftShader)
only support XCB.
This commit is contained in:
Philip Rideout
2020-10-22 13:18:33 -07:00
parent f55c9ee437
commit 2e10fe6680
17 changed files with 87 additions and 36 deletions

View File

@@ -21,6 +21,10 @@ option(FILAMENT_ENABLE_LTO "Enable link-time optimizations if supported by the c
option(FILAMENT_SKIP_SAMPLES "Don't build samples" OFF)
option(FILAMENT_SUPPORTS_XCB "Include XCB support in Linux builds" ON)
option(FILAMENT_SUPPORTS_XLIB "Include XLIB support in Linux builds" ON)
set(FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB "2" CACHE STRING
"Per render pass arena size. Must be roughly 1 MB larger than FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB, default 2."
)
@@ -84,6 +88,15 @@ if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT WEBGL)
endif()
if (LINUX)
if (FILAMENT_SUPPORTS_XCB)
add_definitions(-DFILAMENT_SUPPORTS_XCB)
endif()
if (FILAMENT_SUPPORTS_XLIB)
add_definitions(-DFILAMENT_SUPPORTS_XLIB)
endif()
execute_process(COMMAND uname -p
OUTPUT_VARIABLE PROCESSOR_ARCH
OUTPUT_STRIP_TRAILING_WHITESPACE

View File

@@ -85,6 +85,12 @@ public class SwapChain {
*/
public static final long CONFIG_READABLE = 0x2;
/**
* Indicates that the native X11 window is an XCB window rather than an XLIB window.
* This is ignored on non-Linux platforms and in builds that support only one X11 API.
*/
public static final long CONFIG_ENABLE_XCB = 0x4;
SwapChain(long nativeSwapChain, Object surface) {
mNativeObject = nativeSwapChain;
mSurface = surface;

View File

@@ -41,6 +41,7 @@ namespace backend {
static constexpr uint64_t SWAP_CHAIN_CONFIG_TRANSPARENT = 0x1;
static constexpr uint64_t SWAP_CHAIN_CONFIG_READABLE = 0x2;
static constexpr uint64_t SWAP_CHAIN_CONFIG_ENABLE_XCB = 0x4;
static constexpr size_t MAX_VERTEX_ATTRIBUTE_COUNT = 16; // This is guaranteed by OpenGL ES.
static constexpr size_t MAX_SAMPLER_COUNT = 16; // Matches the Adreno Vulkan driver.

View File

@@ -47,7 +47,7 @@ Driver* PlatformVkAndroid::createDriver(void* const sharedContext) noexcept {
sizeof(requiredInstanceExtensions) / sizeof(requiredInstanceExtensions[0]));
}
void* PlatformVkAndroid::createVkSurfaceKHR(void* nativeWindow, void* vkinstance) noexcept {
void* PlatformVkAndroid::createVkSurfaceKHR(void* nativeWindow, void* vkinstance, uint64_t flags) noexcept {
const VkInstance instance = (VkInstance) vkinstance;
ANativeWindow* aNativeWindow = (ANativeWindow*) nativeWindow;
VkAndroidSurfaceCreateInfoKHR createInfo {

View File

@@ -29,7 +29,7 @@ public:
backend::Driver* createDriver(void* const sharedContext) noexcept override;
void* createVkSurfaceKHR(void* nativeWindow, void* instance) noexcept override;
void* createVkSurfaceKHR(void* nativeWindow, void* instance, uint64_t flags) noexcept override;
int getOSVersion() const noexcept override { return 0; }
};

View File

@@ -27,7 +27,7 @@ namespace filament {
class PlatformVkCocoa final : public backend::VulkanPlatform {
public:
backend::Driver* createDriver(void* sharedContext) noexcept override;
void* createVkSurfaceKHR(void* nativeWindow, void* instance) noexcept override;
void* createVkSurfaceKHR(void* nativeWindow, void* instance, uint64_t flags) noexcept override;
int getOSVersion() const noexcept override { return 0; }
};

View File

@@ -51,7 +51,7 @@ Driver* PlatformVkCocoa::createDriver(void* sharedContext) noexcept {
sizeof(requiredInstanceExtensions) / sizeof(requiredInstanceExtensions[0]));
}
void* PlatformVkCocoa::createVkSurfaceKHR(void* nativeWindow, void* instance) noexcept {
void* PlatformVkCocoa::createVkSurfaceKHR(void* nativeWindow, void* instance, uint64_t flags) noexcept {
// Obtain the CAMetalLayer-backed view.
NSView* nsview = (__bridge NSView*) nativeWindow;
ASSERT_POSTCONDITION(nsview, "Unable to obtain Metal-backed NSView.");

View File

@@ -27,7 +27,7 @@ namespace filament {
class PlatformVkCocoaTouch final : public backend::VulkanPlatform {
public:
backend::Driver* createDriver(void* const sharedContext) noexcept override;
void* createVkSurfaceKHR(void* nativeWindow, void* instance) noexcept override;
void* createVkSurfaceKHR(void* nativeWindow, void* instance, uint64_t flags) noexcept override;
int getOSVersion() const noexcept override { return 0; }
};

View File

@@ -46,7 +46,7 @@ Driver* PlatformVkCocoaTouch::createDriver(void* const sharedContext) noexcept {
sizeof(requestedExtensions) / sizeof(requestedExtensions[0]));
}
void* PlatformVkCocoaTouch::createVkSurfaceKHR(void* nativeWindow, void* instance) noexcept {
void* PlatformVkCocoaTouch::createVkSurfaceKHR(void* nativeWindow, void* instance, uint64_t flags) noexcept {
#if METAL_AVAILABLE
CAMetalLayer* metalLayer = (CAMetalLayer*) nativeWindow;

View File

@@ -36,14 +36,18 @@ static constexpr const char* LIBRARY_X11 = "libX11.so.6";
#ifdef FILAMENT_SUPPORTS_XCB
typedef xcb_connection_t* (*XCB_CONNECT)(const char *displayname, int *screenp);
#else
#endif
#ifdef FILAMENT_SUPPORTS_XLIB
typedef Display* (*X11_OPEN_DISPLAY)(const char*);
#endif
struct X11Functions {
#ifdef FILAMENT_SUPPORTS_XCB
XCB_CONNECT xcbConnect;
#else
#endif
#ifdef FILAMENT_SUPPORTS_XLIB
X11_OPEN_DISPLAY openDisplay;
#endif
void* library = nullptr;
@@ -55,7 +59,8 @@ Driver* PlatformVkLinux::createDriver(void* const sharedContext) noexcept {
"VK_KHR_surface",
#ifdef FILAMENT_SUPPORTS_XCB
"VK_KHR_xcb_surface",
#else
#endif
#ifdef FILAMENT_SUPPORTS_XLIB
"VK_KHR_xlib_surface",
#endif
"VK_KHR_get_physical_device_properties2",
@@ -67,42 +72,57 @@ Driver* PlatformVkLinux::createDriver(void* const sharedContext) noexcept {
sizeof(requiredInstanceExtensions) / sizeof(requiredInstanceExtensions[0]));
}
void* PlatformVkLinux::createVkSurfaceKHR(void* nativeWindow, void* instance) noexcept {
#ifdef FILAMENT_SUPPORTS_XCB
void* PlatformVkLinux::createVkSurfaceKHR(void* nativeWindow, void* instance, uint64_t flags) noexcept {
if (g_x11.library == nullptr) {
g_x11.library = dlopen(LIBRARY_X11, RTLD_LOCAL | RTLD_NOW);
ASSERT_PRECONDITION(g_x11.library, "Unable to open X11 library.");
#ifdef FILAMENT_SUPPORTS_XCB
g_x11.xcbConnect = (XCB_CONNECT) dlsym(g_x11.library, "xcb_connect");
int screen;
mConnection = g_x11.xcbConnect(nullptr, &screen);
}
ASSERT_POSTCONDITION(vkCreateXcbSurfaceKHR, "Unable to load vkCreateXcbSurfaceKHR function.");
VkSurfaceKHR surface = nullptr;
const uint64_t ptrval = reinterpret_cast<uint64_t>(nativeWindow);
VkXcbSurfaceCreateInfoKHR createInfo = {
.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
.connection = mConnection,
.window = (xcb_window_t) ptrval,
};
VkResult result = vkCreateXcbSurfaceKHR((VkInstance) instance, &createInfo, VKALLOC, &surface);
#else
if (g_x11.library == nullptr) {
g_x11.library = dlopen(LIBRARY_X11, RTLD_LOCAL | RTLD_NOW);
ASSERT_PRECONDITION(g_x11.library, "Unable to open X11 library.");
ASSERT_POSTCONDITION(vkCreateXcbSurfaceKHR, "Unable to load vkCreateXcbSurfaceKHR function.");
#endif
#ifdef FILAMENT_SUPPORTS_XLIB
g_x11.openDisplay = (X11_OPEN_DISPLAY) dlsym(g_x11.library, "XOpenDisplay");
mDisplay = g_x11.openDisplay(NULL);
ASSERT_PRECONDITION(mDisplay, "Unable to open X11 display.");
ASSERT_POSTCONDITION(vkCreateXlibSurfaceKHR, "Unable to load vkCreateXlibSurfaceKHR function.");
#endif
}
ASSERT_POSTCONDITION(vkCreateXlibSurfaceKHR, "Unable to load vkCreateXlibSurfaceKHR function.");
VkSurfaceKHR surface = nullptr;
#ifdef FILAMENT_SUPPORTS_XCB
#ifdef FILAMENT_SUPPORTS_XLIB
const bool windowIsXCB = flags & SWAP_CHAIN_CONFIG_ENABLE_XCB;
#else
const bool windowIsXCB = true;
#endif
if (windowIsXCB) {
const uint64_t ptrval = reinterpret_cast<uint64_t>(nativeWindow);
VkXcbSurfaceCreateInfoKHR createInfo = {
.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
.connection = mConnection,
.window = (xcb_window_t) ptrval,
};
vkCreateXcbSurfaceKHR((VkInstance) instance, &createInfo, VKALLOC, &surface);
return surface;
}
#endif
#ifdef FILAMENT_SUPPORTS_XLIB
VkXlibSurfaceCreateInfoKHR createInfo = {
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
.dpy = mDisplay,
.window = (Window) nativeWindow,
};
VkResult result = vkCreateXlibSurfaceKHR((VkInstance) instance, &createInfo, VKALLOC, &surface);
vkCreateXlibSurfaceKHR((VkInstance) instance, &createInfo, VKALLOC, &surface);
#endif
ASSERT_POSTCONDITION(result == VK_SUCCESS, "vkCreateXlibSurfaceKHR error.");
return surface;
}

View File

@@ -24,7 +24,9 @@
#ifdef FILAMENT_SUPPORTS_XCB
#include <xcb/xcb.h>
#else
#endif
#ifdef FILAMENT_SUPPORTS_XLIB
#include <X11/Xlib.h>
#endif
@@ -35,14 +37,15 @@ public:
backend::Driver* createDriver(void* const sharedContext) noexcept override;
void* createVkSurfaceKHR(void* nativeWindow, void* instance) noexcept override;
void* createVkSurfaceKHR(void* nativeWindow, void* instance, uint64_t flags) noexcept override;
int getOSVersion() const noexcept override { return 0; }
private:
#ifdef FILAMENT_SUPPORTS_XCB
xcb_connection_t* mConnection;
#else
#endif
#ifdef FILAMENT_SUPPORTS_XLIB
Display* mDisplay;
#endif
};

View File

@@ -40,7 +40,7 @@ Driver* PlatformVkWindows::createDriver(void* const sharedContext) noexcept {
sizeof(requiredInstanceExtensions) / sizeof(requiredInstanceExtensions[0]));
}
void* PlatformVkWindows::createVkSurfaceKHR(void* nativeWindow, void* instance) noexcept {
void* PlatformVkWindows::createVkSurfaceKHR(void* nativeWindow, void* instance, uint64_t flags) noexcept {
VkSurfaceKHR surface = nullptr;
HWND window = (HWND) nativeWindow;

View File

@@ -29,7 +29,7 @@ public:
backend::Driver* createDriver(void* const sharedContext) noexcept override;
void* createVkSurfaceKHR(void* nativeWindow, void* instance) noexcept override;
void* createVkSurfaceKHR(void* nativeWindow, void* instance, uint64_t flags) noexcept override;
int getOSVersion() const noexcept override { return 0; }

View File

@@ -559,7 +559,8 @@ void VulkanDriver::createSyncR(Handle<HwSync> sh, int) {
void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
const VkInstance instance = mContext.instance;
auto vksurface = (VkSurfaceKHR) mContextManager.createVkSurfaceKHR(nativeWindow, instance);
auto vksurface = (VkSurfaceKHR) mContextManager.createVkSurfaceKHR(nativeWindow, instance,
flags);
auto* swapChain = construct_handle<VulkanSwapChain>(mHandleMap, sch, mContext, vksurface);
// TODO: move the following line into makeCurrent.

View File

@@ -43,7 +43,7 @@ namespace backend {
class VulkanPlatform : public DefaultPlatform {
public:
// Given a Vulkan instance and native window handle, creates the platform-specific surface.
virtual void* createVkSurfaceKHR(void* nativeWindow, void* instance) noexcept = 0;
virtual void* createVkSurfaceKHR(void* nativeWindow, void* instance, uint64_t flags) noexcept = 0;
~VulkanPlatform() override;
};

View File

@@ -153,6 +153,12 @@ public:
*/
static const uint64_t CONFIG_READABLE = backend::SWAP_CHAIN_CONFIG_READABLE;
/**
* Indicates that the native X11 window is an XCB window rather than an XLIB window.
* This is ignored on non-Linux platforms and in builds that support only one X11 API.
*/
static const uint64_t CONFIG_ENABLE_XCB = backend::SWAP_CHAIN_CONFIG_ENABLE_XCB;
void* getNativeWindow() const noexcept;
};

View File

@@ -28,7 +28,8 @@
#elif defined(__linux__)
#if defined(FILAMENT_SUPPORTS_XCB)
#define VK_USE_PLATFORM_XCB_KHR 1
#else
#endif
#if defined(FILAMENT_SUPPORTS_XLIB)
#define VK_USE_PLATFORM_XLIB_KHR 1
#endif
#elif defined(__APPLE__)