Skip to content

Instantly share code, notes, and snippets.

@spundun
Created June 27, 2022 15:34
Show Gist options
  • Save spundun/dddfe31a331f05f26ec015a304aa736f to your computer and use it in GitHub Desktop.
Save spundun/dddfe31a331f05f26ec015a304aa736f to your computer and use it in GitHub Desktop.
Reproducing ERROR_SURFACE_LOST_KHR issue with Vulkan/Wayland/VirtIO

I build this code using the following command on Arch Linux virtual machine running in Crostini on top of Chrome OS

clang++ vulkaninfo.cpp -DVK_ENABLE_BETA_EXTENSIONS -DVK_NO_PROTOTYPES -DVK_USE_PLATFORM_WAYLAND_KHR -DVK_USE_PLATFORM_XCB_KHR -DVK_USE_PLATFORM_XLIB_KHR -march=x86-64 -mtune=generic -pipe -fno-plt -fexceptions -Wp,-D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fstack-clash-protection -fcf-protection -Wp,-D_GLIBCXX_ASSERTIONS -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fno-strict-aliasing -fno-builtin-memcmp -Wimplicit-fallthrough -std=c++11 -fno-rtti -fvisibility=hidden -Wl,--sort-common,--as-needed,-z,relro,-z,now -ldl /usr/lib/libxcb.so /usr/lib/libSM.so /usr/lib/libICE.so /usr/lib/libX11.so /usr/lib/libXext.so /usr/lib/libwayland-client.so -O2

Some of those flags are probably unnecessary and could be removed for simplicity.

#include <algorithm>
#include <array>
#include <exception>
#include <iostream>
#include <fstream>
#include <memory>
#include <ostream>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
#include <utility>
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <cstring>
#include <dlfcn.h>
#include <vulkan/vulkan.h>
#include <cassert>
#include <bitset>
#define LOG(s) std::cout << "Line:" << std::to_string(__LINE__) << ": " << s << std::endl
static VKAPI_ATTR VkBool32 VKAPI_CALL DbgCallback(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType,
uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix,
const char *pMsg, void *pUserData) {
std::bitset<8> bs(msgFlags);
std::cerr << bs << ": [" << pLayerPrefix << "] Code " << msgCode << " : " << pMsg << "\n";
// True is reserved for layer developers, and MAY mean calls are not distributed down the layer chain after validation
// error. False SHOULD always be returned by apps:
return VK_FALSE;
}
int main(int argc, char **argv) {
///////////////////////////////////////////////////////
/// Get Wayland Vulkan DLL Symbols
void *library;
library = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
auto vkEnumeratePhysicalDevices =
reinterpret_cast<PFN_vkEnumeratePhysicalDevices>(dlsym(library, "vkEnumeratePhysicalDevices"));
auto vkCreateWaylandSurfaceKHR = reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>(dlsym(library, "vkCreateWaylandSurfaceKHR"));
auto vkEnumerateInstanceExtensionProperties =
reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(dlsym(library, "vkEnumerateInstanceExtensionProperties"));
auto vkCreateInstance = reinterpret_cast<PFN_vkCreateInstance>(dlsym(library, "vkCreateInstance"));
auto vkEnumerateInstanceVersion =
reinterpret_cast<PFN_vkEnumerateInstanceVersion>(dlsym(library, "vkEnumerateInstanceVersion"));
auto vkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(dlsym(library, "vkGetInstanceProcAddr"));
///
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
/// Get Global Layer Extensions
VkExtensionProperties init;
uint32_t count = 0;
std::vector<VkExtensionProperties> global_extensions;
VkResult err = vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
assert(err == VK_SUCCESS);
global_extensions.resize(count, init);
err = vkEnumerateInstanceExtensionProperties(nullptr, &count, global_extensions.data());
assert(err == VK_SUCCESS);
global_extensions.resize(count);
std::vector<const char *> inst_exts;
bool has_portability_extension = false;
for (const auto &ext : global_extensions) {
std::cout << ext.extensionName << std::endl;
inst_exts.push_back(ext.extensionName);
if (0 == strcmp(ext.extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) has_portability_extension = true;
}
assert(has_portability_extension == true);
///
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
/// Make Vulkan Instance
VkInstance instance;
const VkDebugReportCallbackCreateInfoEXT dbg_info = {VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, nullptr,
VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT,
DbgCallback};
uint32_t instance_version;
err = vkEnumerateInstanceVersion(&instance_version);
assert(err == VK_SUCCESS);
const VkApplicationInfo app_info = {
VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr, "vulkan_wayland_virtio_test", 1, nullptr, 0, instance_version};
const VkInstanceCreateInfo inst_info = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
&dbg_info,
static_cast<VkInstanceCreateFlags>(VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR),
&app_info,
0,
nullptr,
static_cast<uint32_t>(inst_exts.size()),
inst_exts.data()};
err = vkCreateInstance(&inst_info, nullptr, &instance);
assert(err == VK_SUCCESS);
VkDebugReportCallbackEXT debug_callback = VK_NULL_HANDLE;
auto vkCreateDebugReportCallbackEXT = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"));
err = vkCreateDebugReportCallbackEXT(instance, &dbg_info, nullptr, &debug_callback);
assert(err == VK_SUCCESS);
///
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
/// Get Physical Device
VkPhysicalDevice init_physical_device{};
count = 0;
err = vkEnumeratePhysicalDevices(instance, &count, nullptr);
assert(err == VK_SUCCESS);
std::vector<VkPhysicalDevice> phys_devices;
phys_devices.resize(count, init_physical_device);
err = vkEnumeratePhysicalDevices(instance, &count, phys_devices.data());
phys_devices.resize(count);
assert(err == VK_SUCCESS);
if (phys_devices.size() != 1) {
LOG("Unexpected size of phys_devices array: " << phys_devices.size());
}
auto &phys_device = phys_devices[0];
///
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
/// Create a Wayland Window
wl_display *wayland_display = wl_display_connect(nullptr);
wl_surface *wayland_surface;
struct wl_registry *registry = wl_display_get_registry(wayland_display);
auto wayland_registry_global = [](void *data, struct wl_registry *registry, uint32_t id, const char *interface,
uint32_t version) -> void {
auto wayland_surface = static_cast<wl_surface **>(data);
if (strcmp(interface, "wl_compositor") == 0) {
struct wl_compositor *compositor = (struct wl_compositor *)wl_registry_bind(registry, id, &wl_compositor_interface, 1);
*wayland_surface = wl_compositor_create_surface(compositor);
}
};
auto wayland_registry_global_remove = [](void *data, struct wl_registry *registry, uint32_t id) -> void {};
const struct wl_registry_listener wayland_registry_listener = {wayland_registry_global, wayland_registry_global_remove};
wl_registry_add_listener(wl_display_get_registry(wayland_display), &wayland_registry_listener, &wayland_surface);
wl_display_roundtrip(wayland_display);
wl_registry_destroy(registry);
///////////////////////////////////////////////////////
/// Create a Wayland Surface
VkWaylandSurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.display = wayland_display;
createInfo.surface = wayland_surface;
VkSurfaceKHR surface;
err = vkCreateWaylandSurfaceKHR(instance, &createInfo, nullptr, &surface);
assert(err == VK_SUCCESS);
///
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
/// Get Wayland Surface Formats
auto vkGetPhysicalDeviceSurfaceFormats2KHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormats2KHR>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormats2KHR"));
const VkPhysicalDeviceSurfaceInfo2KHR surface_info2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, nullptr, surface};
VkSurfaceFormat2KHR init_surface_format{};
init_surface_format.sType = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR;
std::vector<VkSurfaceFormat2KHR> surf_formats2;
err = vkGetPhysicalDeviceSurfaceFormats2KHR(phys_device, &surface_info2, &count, nullptr);
assert(err == VK_ERROR_SURFACE_LOST_KHR);
assert(err == VK_SUCCESS);
surf_formats2.resize(count, init_surface_format);
err = vkGetPhysicalDeviceSurfaceFormats2KHR(phys_device, &surface_info2, &count, surf_formats2.data());
surf_formats2.resize(count);
assert(err == VK_SUCCESS);
///
///////////////////////////////////////////////////////
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment