The open source OpenXR runtime
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
90void
91render_calc_time_warp_matrix(const struct xrt_pose *src_pose,
92 const struct xrt_fov *src_fov,
93 const struct xrt_pose *new_pose,
94 struct xrt_matrix_4x4 *matrix)
95{
96 // Src projection matrix.
97 struct xrt_matrix_4x4_f64 src_proj;
98 calc_projection(src_fov, &src_proj);
99
100 // Src rotation matrix.
101 struct xrt_matrix_4x4_f64 src_rot_inv;
102 struct xrt_quat src_q = src_pose->orientation;
103 m_mat4_f64_orientation(&src_q, &src_rot_inv); // This is a model matrix, a inverted view matrix.
104
105 // New rotation matrix.
106 struct xrt_matrix_4x4_f64 new_rot, new_rot_inv;
107 struct xrt_quat new_q = new_pose->orientation;
108 m_mat4_f64_orientation(&new_q, &new_rot_inv); // This is a model matrix, a inverted view matrix.
109 m_mat4_f64_invert(&new_rot_inv, &new_rot); // Invert to make it a view matrix.
110
111 // Combine both rotation matrices to get difference.
112 struct xrt_matrix_4x4_f64 delta_rot, delta_rot_inv;
113 m_mat4_f64_multiply(&new_rot, &src_rot_inv, &delta_rot);
114 m_mat4_f64_invert(&delta_rot, &delta_rot_inv);
115
116 // Combine the source projection matrix and
117 struct xrt_matrix_4x4_f64 result;
118 m_mat4_f64_multiply(&src_proj, &delta_rot_inv, &result);
119
120 // Convert from f64 to f32.
121 for (int i = 0; i < 16; i++) {
122 matrix->v[i] = (float)result.v[i];
123 }
124}
125
126void
127render_calc_time_warp_projection(const struct xrt_fov *fov, struct xrt_matrix_4x4 *result)
128{
129 struct xrt_matrix_4x4_f64 tmp;
130 calc_projection(fov, &tmp);
131
132 for (int i = 0; i < 16; i++) {
133 result->v[i] = (float)tmp.v[i];
134 }
135}
136
137void
138render_calc_uv_to_tangent_lengths_rect(const struct xrt_fov *fov, struct xrt_normalized_rect *out_rect)
139{
140 const struct xrt_fov copy = *fov;
141
142 const double tan_left = tan(copy.angle_left);
143 const double tan_right = tan(copy.angle_right);
144
145 const double tan_down = tan(copy.angle_down);
146 const double tan_up = tan(copy.angle_up);
147
148 const double tan_width = tan_right - tan_left;
149 const double tan_height = tan_up - tan_down;
150
151 /*
152 * I do not know why we have to calculate the offsets like this, but
153 * this one is the one that seems to work with what is currently in the
154 * calc timewarp matrix function and the distortion shader. It works
155 * with Index (unbalanced left and right angles) and WMR (unbalanced up
156 * and down angles) so here it is. In so far it matches what the gfx
157 * and non-timewarp compute pipeline produces.
158 */
159 const double tan_offset_x = ((tan_right + tan_left) - tan_width) / 2;
160 const double tan_offset_y = (-(tan_up + tan_down) - tan_height) / 2;
161
162 struct xrt_normalized_rect transform = {
163 .x = (float)tan_offset_x,
164 .y = (float)tan_offset_y,
165 .w = (float)tan_width,
166 .h = (float)tan_height,
167 };
168
169 *out_rect = transform;
170}