The open source OpenXR runtime

c/render: cap max layers to physical device limits

Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2639>

+86 -4
+5 -2
src/xrt/compositor/main/comp_compositor.c
··· 1132 1132 struct xrt_system_compositor_info sys_info_storage = {0}; 1133 1133 struct xrt_system_compositor_info *sys_info = &sys_info_storage; 1134 1134 1135 - // Required by OpenXR spec. 1136 - sys_info->max_layers = XRT_MAX_LAYERS; 1135 + // Required by OpenXR spec (minimum 16). 1136 + sys_info->max_layers = render_max_layers_capable( // 1137 + get_vk(c), // 1138 + c->settings.use_compute, // 1139 + XRT_MAX_LAYERS); // 1137 1140 sys_info->compositor_vk_deviceUUID = c->settings.selected_gpu_deviceUUID; 1138 1141 sys_info->client_vk_deviceUUID = c->settings.client_gpu_deviceUUID; 1139 1142 sys_info->client_d3d_deviceLUID = c->settings.client_gpu_deviceLUID;
+7 -1
src/xrt/compositor/null/null_compositor.c
··· 268 268 { 269 269 struct xrt_system_compositor_info *sys_info = &c->sys_info; 270 270 271 - // Required by OpenXR spec. 271 + /* 272 + * Required by OpenXR spec (minimum 16). 273 + * 274 + * NOTE: When using Vulkan compositor components (c/render, c/util), 275 + * call render_max_layers_capable() to clamp this value based on 276 + * actual device limits. 277 + */ 272 278 sys_info->max_layers = XRT_MAX_LAYERS; 273 279 274 280 uint32_t view_count = xdev->hmd->view_count;
+18
src/xrt/compositor/render/render_interface.h
··· 93 93 //! The binding that the shared layer fragment shader has its source on. 94 94 #define RENDER_BINDING_LAYER_SHARED_SRC 1 95 95 96 + /*! 97 + * The maximum number samplers per view that can be used by the compute shader 98 + * for layer composition (layer.comp) 99 + */ 100 + #define RENDER_CS_MAX_SAMPLERS_PER_VIEW 2 96 101 97 102 /* 98 103 * 99 104 * Util functions. 100 105 * 101 106 */ 107 + 108 + /*! 109 + * Determines the maximum number of compositor layers supported based on Vulkan 110 + * device limits and the composition path being used. 111 + * 112 + * @param vk Vulkan bundle containing device properties 113 + * @param use_compute True if using compute pipeline path, false for graphics 114 + * @param desired_max_layers Maximum layers requested by the compositor 115 + * @return Actual maximum layers supported, clamped by device limits (minimum 16) 116 + * 117 + */ 118 + uint32_t 119 + render_max_layers_capable(const struct vk_bundle *vk, bool use_compute, uint32_t desired_max_layers); 102 120 103 121 /*! 104 122 * Create a simplified projection matrix for timewarp.
+49
src/xrt/compositor/render/render_util.c
··· 87 87 * 88 88 */ 89 89 90 + uint32_t 91 + render_max_layers_capable(const struct vk_bundle *vk, bool use_compute, uint32_t desired_max_layers) 92 + { 93 + /*! 94 + * Graphics pipeline: 95 + * 96 + * This path has no relevant Vulkan device limits that would 97 + * constrain the maximum number of layers (each layer uses a single descriptor 98 + * set bound individually per draw). 99 + */ 100 + if (!use_compute) { 101 + // The min required by OpenXR spec is 16. 102 + return MAX(desired_max_layers, 16); 103 + } 104 + 105 + /*! 106 + * Compute pipeline: 107 + * 108 + * Clamp max layers based on compute pipeline descriptor limits. 109 + * 110 + * The compute path uses an array of combined image samplers, with 111 + * @ref samplers_per_layer samplers needed per layer. We check both the 112 + * per-stage sampler and sampled image limits, then calculate the 113 + * maximum number of complete layers that fit within those limits. 114 + */ 115 + uint32_t desired_image_sampler_count = desired_max_layers * RENDER_CS_MAX_SAMPLERS_PER_VIEW; 116 + 117 + const uint32_t max_sizes[] = { 118 + vk->limits.max_per_stage_descriptor_samplers, 119 + vk->limits.max_per_stage_descriptor_sampled_images, 120 + }; 121 + for (uint32_t i = 0; i < ARRAY_SIZE(max_sizes); ++i) { 122 + desired_image_sampler_count = MIN(desired_image_sampler_count, max_sizes[i]); 123 + } 124 + 125 + const uint32_t calculated_max_layers = desired_image_sampler_count / RENDER_CS_MAX_SAMPLERS_PER_VIEW; 126 + 127 + if (calculated_max_layers < 16) { 128 + VK_WARN(vk, 129 + "Device supports only %u compositor layers due to Vulkan limits. " 130 + "which is below Vulkan minimum of 16. " 131 + "This may indicate a driver bug. Attempting 16 anyway.", 132 + calculated_max_layers); 133 + } 134 + 135 + // The min required by OpenXR spec is 16. 136 + return MAX(calculated_max_layers, 16); 137 + } 138 + 90 139 void 91 140 render_calc_time_warp_matrix(const struct xrt_pose *src_pose, 92 141 const struct xrt_fov *src_fov,
+7 -1
src/xrt/targets/sdl_test/sdl_compositor.c
··· 256 256 { 257 257 struct xrt_system_compositor_info *sys_info = &c->sys_info; 258 258 259 - // Required by OpenXR spec. 259 + /* 260 + * Required by OpenXR spec (minimum 16). 261 + * 262 + * NOTE: When using Vulkan compositor components (c/render, c/util), 263 + * call render_max_layers_capable() to clamp this value based on 264 + * actual device limits. 265 + */ 260 266 sys_info->max_layers = XRT_MAX_LAYERS; 261 267 262 268 // UUIDs and LUID already set in vk init.