Can't create swapchain when the Renderdoc Vulkan layer is active in an OpenXR client
I'm not sure that this is a bug in Monado or Renderdoc, I'm sharing this here because this may be the place where someone is most likely to understand what is happening. Whether or not the Renderdoc layer is active can image memory requirements, resulting in a failure to create the swapchain because the required size is higher than what Monado expected:
$ gcc xr-swapchain-issue.c -lopenxr_loader -lvulkan -o xr-swapchain-issue
&& ENABLE_VULKAN_RENDERDOC_CAPTURE=0 ./xr-swapchain-issue
# … logs and exits fine
$ gcc xr-swapchain-issue.c -lopenxr_loader -lvulkan -o xr-swapchain-issue
&& ENABLE_VULKAN_RENDERDOC_CAPTURE=1 ./xr-swapchain-issue
ERROR [vk_alloc_and_bind_image_memory] (vk_create_image_from_native) vkGetImageMemoryRequirements: Requested more memory (37945344) then given (37748736)
I only started encountering this issue when switching to an AMD GPU using the mesa open source drivers. The same code worked fine when running under the proprietary NVIDIA drivers.
I tried to also run the monado service with ENABLE_VULKAN_RENDERDOC_CAPTURE=1 in case you need both the client and the server to have the layer active, but that caused monado to segfault.
Code to reproduce the issue:
#include <vulkan/vulkan.h>
#define XR_USE_PLATFORM_XLIB
#define XR_USE_GRAPHICS_API_VULKAN
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
int xr_check(XrInstance instance, XrResult result, const char *prefix) {
if (XR_SUCCEEDED(result)) return 1;
char message[XR_MAX_RESULT_STRING_SIZE];
xrResultToString(instance, result, message);
fprintf(stderr, "%s %s\n", prefix, message);
return 0;
}
#define XSTRINGIFY(X) #X
#define STRINGIFY(X) XSTRINGIFY(X)
#define XR_CHECK(instance, X) xr_check((instance), (X), "[" __FILE__ ":" STRINGIFY(__LINE__) "] " #X ": ")
#define countof(array) (sizeof(array)/sizeof(*(array)))
int main(int argc, char *argv[]) {
const char* enabled_exts[] = {
XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME
};
const char *enabled_layers[] = {
"XR_APILAYER_LUNARG_core_validation"
};
XrInstance instance;
XrInstanceCreateInfo info = {};
info.type = XR_TYPE_INSTANCE_CREATE_INFO;
info.next = NULL;
strlcpy(info.applicationInfo.applicationName, "xr-test",
sizeof(info.applicationInfo.applicationName));
info.applicationInfo.applicationVersion = 1;
strlcpy(info.applicationInfo.engineName, "xr-test",
sizeof(info.applicationInfo.engineName));
info.applicationInfo.engineVersion = 1;
info.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
info.enabledExtensionCount = countof(enabled_exts);
info.enabledExtensionNames = enabled_exts;
info.enabledApiLayerCount = countof(enabled_layers);
info.enabledApiLayerNames = enabled_layers;
info.createFlags = 0;
if (!XR_CHECK(NULL, xrCreateInstance(&info, &instance))) return 1;
PFN_xrCreateVulkanInstanceKHR xrCreateVulkanInstanceKHR;
XR_CHECK(
instance,
xrGetInstanceProcAddr(
instance, "xrCreateVulkanInstanceKHR",
(PFN_xrVoidFunction*)&xrCreateVulkanInstanceKHR));
PFN_xrCreateVulkanDeviceKHR xrCreateVulkanDeviceKHR;
XR_CHECK(
instance,
xrGetInstanceProcAddr(
instance, "xrCreateVulkanDeviceKHR",
(PFN_xrVoidFunction*)&xrCreateVulkanDeviceKHR));
PFN_xrGetVulkanGraphicsRequirements2KHR xrGetVulkanGraphicsRequirements2KHR;
XR_CHECK(
instance,
xrGetInstanceProcAddr(
instance, "xrGetVulkanGraphicsRequirements2KHR",
(PFN_xrVoidFunction*)&xrGetVulkanGraphicsRequirements2KHR));
PFN_xrGetVulkanGraphicsDevice2KHR xrGetVulkanGraphicsDevice2KHR;
XR_CHECK(
instance,
xrGetInstanceProcAddr(
instance, "xrGetVulkanGraphicsDevice2KHR",
(PFN_xrVoidFunction*)&xrGetVulkanGraphicsDevice2KHR));
XrSystemId system_id;
XrSystemGetInfo system_get_info = {0};
system_get_info.type = XR_TYPE_SYSTEM_GET_INFO;
system_get_info.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
if (!XR_CHECK(instance, xrGetSystem(instance, &system_get_info, &system_id)))
return 1;
const char *layers[] = {"VK_LAYER_KHRONOS_validation"};
VkApplicationInfo app_info = {};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
app_info.pApplicationName = "pipeline-test";
app_info.pEngineName = "pipeline-test";
app_info.apiVersion = VK_MAKE_API_VERSION(0, 1, 3, 0);
VkInstanceCreateInfo vk_instance_info = {};
vk_instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
vk_instance_info.pApplicationInfo = &app_info;
vk_instance_info.enabledLayerCount = countof(layers);
vk_instance_info.ppEnabledLayerNames = layers;
XrVulkanInstanceCreateInfoKHR xr_instance_info = {};
xr_instance_info.type = XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR;
xr_instance_info.vulkanCreateInfo = &vk_instance_info;
xr_instance_info.systemId = system_id;
xr_instance_info.pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
VkInstance vk_instance;
VkResult vk_result;
XR_CHECK(instance, xrCreateVulkanInstanceKHR(
instance, &xr_instance_info, &vk_instance, &vk_result));
XrVulkanGraphicsDeviceGetInfoKHR physical_device_info = {};
physical_device_info.type = XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR;
physical_device_info.vulkanInstance = vk_instance;
physical_device_info.systemId = system_id;
VkPhysicalDevice physical_device;
XR_CHECK(instance, xrGetVulkanGraphicsDevice2KHR(instance, &physical_device_info, &physical_device));
VkPhysicalDeviceFeatures2 features = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
VkDeviceQueueCreateInfo queue_info = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO};
float priorities = 1.0;
queue_info.queueCount = 1;
queue_info.queueFamilyIndex = 0;
queue_info.pQueuePriorities = &priorities;
VkDeviceCreateInfo vk_device_info = {};
vk_device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
vk_device_info.pNext = (void*)&features;
vk_device_info.queueCreateInfoCount = 1;
vk_device_info.pQueueCreateInfos = &queue_info;
XrVulkanDeviceCreateInfoKHR xr_device_info = {};
xr_device_info.type = XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR;
xr_device_info.vulkanCreateInfo = &vk_device_info;
xr_device_info.vulkanPhysicalDevice = physical_device;
xr_device_info.pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
xr_device_info.systemId = system_id;
VkDevice vk_device;
XR_CHECK(instance, xrCreateVulkanDeviceKHR(instance, &xr_device_info, &vk_device, &vk_result));
XrGraphicsBindingVulkan2KHR graphics_binding = {};
graphics_binding.type = XR_TYPE_GRAPHICS_BINDING_VULKAN2_KHR;
graphics_binding.queueIndex = 0;
graphics_binding.queueFamilyIndex = 0;
graphics_binding.instance = vk_instance;
graphics_binding.physicalDevice = physical_device;
graphics_binding.device = vk_device;
XrSessionCreateInfo session_info = {};
session_info.type = XR_TYPE_SESSION_CREATE_INFO;
session_info.next = &graphics_binding;
session_info.systemId = system_id;
XrGraphicsRequirementsVulkan2KHR requirements = {};
requirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR;
XR_CHECK(instance, xrGetVulkanGraphicsRequirements2KHR(instance, system_id, &requirements));
XrSession session;
XR_CHECK(instance, xrCreateSession(instance, &session_info, &session));
XrViewConfigurationView views[2] = {};
views[0].type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
views[1].type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
uint32_t view_count;
XR_CHECK(instance,
xrEnumerateViewConfigurationViews(
instance, system_id, XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO,
2, &view_count, views));
uint32_t width = views[0].recommendedImageRectWidth;
uint32_t height = views[0].recommendedImageRectHeight;
XrSwapchainCreateInfo swapchain_info = {};
swapchain_info.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
swapchain_info.arraySize = 2;
swapchain_info.faceCount = 1;
swapchain_info.mipCount = 1;
swapchain_info.sampleCount = 1;
swapchain_info.width = width;
swapchain_info.height = height;
swapchain_info.usageFlags = XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT |
XR_SWAPCHAIN_USAGE_TRANSFER_SRC_BIT;
swapchain_info.format = VK_FORMAT_R8G8B8A8_SRGB;
XrSwapchain swapchain;
XR_CHECK(instance, xrCreateSwapchain(session, &swapchain_info, &swapchain));
return 0;
}
EDIT: Turns out it was easier than I thought to understand why Renderdoc was doing this https://github.com/baldurk/renderdoc/commit/23534215264edf5bf7687a636f1f04b85207ccef
so I guess I'll report it on their end