The open source OpenXR runtime
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 219 lines 6.6 kB view raw
1// Copyright 2019-2022, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief The compositor compute based rendering code. 6 * @author Jakob Bornecrantz <jakob@collabora.com> 7 * @ingroup comp_render 8 */ 9 10#include "math/m_api.h" 11#include "math/m_matrix_4x4_f64.h" 12 13#include "render/render_interface.h" 14 15 16/*! 17 * Create a simplified projection matrix for timewarp. 18 */ 19static void 20calc_projection(const struct xrt_fov *fov, struct xrt_matrix_4x4_f64 *result) 21{ 22 const double tan_left = tan(fov->angle_left); 23 const double tan_right = tan(fov->angle_right); 24 25 const double tan_down = tan(fov->angle_down); 26 const double tan_up = tan(fov->angle_up); 27 28 const bool vulkan_projection_space_y = true; 29 30 const double tan_width = tan_right - tan_left; 31 const double tan_height = vulkan_projection_space_y // Projection space y direction: 32 ? (tan_down - tan_up) // Vulkan Y down 33 : (tan_up - tan_down); // OpenGL Y up 34 35 const double near_plane = 0.5; 36 const double far_plane = 1.5; 37 38 const double a11 = 2 / tan_width; 39 const double a22 = 2 / tan_height; 40 41 const double a31 = (tan_right + tan_left) / tan_width; 42 const double a32 = (tan_up + tan_down) / tan_height; 43 44 const double a33 = -far_plane / (far_plane - near_plane); 45 const double a43 = -(far_plane * near_plane) / (far_plane - near_plane); 46 47 48#if 0 49 // We skip a33 & a43 because we don't have depth. 50 (void)a33; 51 (void)a43; 52 53 // clang-format off 54 *result = (struct xrt_matrix_4x4_f64){ 55 { 56 a11, 0, 0, 0, 57 0, a22, 0, 0, 58 a31, a32, -1, 0, 59 0, 0, 0, 1, 60 } 61 }; 62 // clang-format on 63#else 64 /* 65 * Apparently the timewarp doesn't look good without this path being 66 * used. With the above it stretches out. I tried with the code to see 67 * if I could affect the depth where the view was placed but couldn't 68 * see to do it, which is a head scratcher. 69 */ 70 // clang-format off 71 *result = (struct xrt_matrix_4x4_f64) { 72 .v = { 73 a11, 0, 0, 0, 74 0, a22, 0, 0, 75 a31, a32, a33, -1, 76 0, 0, a43, 0, 77 } 78 }; 79 // clang-format on 80#endif 81} 82 83 84/* 85 * 86 * 'Exported' functions. 87 * 88 */ 89 90uint32_t 91render_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 139void 140render_calc_time_warp_matrix(const struct xrt_pose *src_pose, 141 const struct xrt_fov *src_fov, 142 const struct xrt_pose *new_pose, 143 struct xrt_matrix_4x4 *matrix) 144{ 145 // Src projection matrix. 146 struct xrt_matrix_4x4_f64 src_proj; 147 calc_projection(src_fov, &src_proj); 148 149 // Src rotation matrix. 150 struct xrt_matrix_4x4_f64 src_rot_inv; 151 struct xrt_quat src_q = src_pose->orientation; 152 m_mat4_f64_orientation(&src_q, &src_rot_inv); // This is a model matrix, a inverted view matrix. 153 154 // New rotation matrix. 155 struct xrt_matrix_4x4_f64 new_rot, new_rot_inv; 156 struct xrt_quat new_q = new_pose->orientation; 157 m_mat4_f64_orientation(&new_q, &new_rot_inv); // This is a model matrix, a inverted view matrix. 158 m_mat4_f64_invert(&new_rot_inv, &new_rot); // Invert to make it a view matrix. 159 160 // Combine both rotation matrices to get difference. 161 struct xrt_matrix_4x4_f64 delta_rot, delta_rot_inv; 162 m_mat4_f64_multiply(&new_rot, &src_rot_inv, &delta_rot); 163 m_mat4_f64_invert(&delta_rot, &delta_rot_inv); 164 165 // Combine the source projection matrix and 166 struct xrt_matrix_4x4_f64 result; 167 m_mat4_f64_multiply(&src_proj, &delta_rot_inv, &result); 168 169 // Convert from f64 to f32. 170 for (int i = 0; i < 16; i++) { 171 matrix->v[i] = (float)result.v[i]; 172 } 173} 174 175void 176render_calc_time_warp_projection(const struct xrt_fov *fov, struct xrt_matrix_4x4 *result) 177{ 178 struct xrt_matrix_4x4_f64 tmp; 179 calc_projection(fov, &tmp); 180 181 for (int i = 0; i < 16; i++) { 182 result->v[i] = (float)tmp.v[i]; 183 } 184} 185 186void 187render_calc_uv_to_tangent_lengths_rect(const struct xrt_fov *fov, struct xrt_normalized_rect *out_rect) 188{ 189 const struct xrt_fov copy = *fov; 190 191 const double tan_left = tan(copy.angle_left); 192 const double tan_right = tan(copy.angle_right); 193 194 const double tan_down = tan(copy.angle_down); 195 const double tan_up = tan(copy.angle_up); 196 197 const double tan_width = tan_right - tan_left; 198 const double tan_height = tan_up - tan_down; 199 200 /* 201 * I do not know why we have to calculate the offsets like this, but 202 * this one is the one that seems to work with what is currently in the 203 * calc timewarp matrix function and the distortion shader. It works 204 * with Index (unbalanced left and right angles) and WMR (unbalanced up 205 * and down angles) so here it is. In so far it matches what the gfx 206 * and non-timewarp compute pipeline produces. 207 */ 208 const double tan_offset_x = ((tan_right + tan_left) - tan_width) / 2; 209 const double tan_offset_y = (-(tan_up + tan_down) - tan_height) / 2; 210 211 struct xrt_normalized_rect transform = { 212 .x = (float)tan_offset_x, 213 .y = (float)tan_offset_y, 214 .w = (float)tan_width, 215 .h = (float)tan_height, 216 }; 217 218 *out_rect = transform; 219}