The open source OpenXR runtime
1// Copyright 2019-2024, Collabora, Ltd.
2// Copyright 2025, NVIDIA CORPORATION.
3// SPDX-License-Identifier: BSL-1.0
4/*!
5 * @file
6 * @brief Compositor (compute shader) rendering code.
7 * @author Jakob Bornecrantz <jakob@collabora.com>
8 * @author Christoph Haag <christoph.haag@collabora.com>
9 * @author Fernando Velazquez Innella <finnella@magicleap.com>
10 * @author Rylie Pavlik <rylie.pavlik@collabora.com>
11 * @ingroup comp_util
12 */
13
14#include "util/comp_layer_accum.h"
15#include "xrt/xrt_compositor.h"
16
17#include "os/os_time.h"
18
19#include "math/m_api.h"
20#include "math/m_mathinclude.h"
21
22#include "util/u_misc.h"
23#include "util/u_trace_marker.h"
24
25#include "vk/vk_helpers.h"
26
27#include "render/render_interface.h"
28
29#include "shaders/layer_defines.inc.glsl"
30
31#include "util/comp_render.h"
32#include "util/comp_render_helpers.h"
33#include "util/comp_base.h"
34
35
36/*
37 *
38 * Helpers
39 *
40 */
41
42static inline const struct comp_swapchain_image *
43get_layer_image(const struct comp_layer *layer, uint32_t swapchain_index, uint32_t image_index)
44{
45
46 const struct comp_swapchain *sc = (struct comp_swapchain *)(comp_layer_get_swapchain(layer, swapchain_index));
47 return &sc->images[image_index];
48}
49
50static inline const struct comp_swapchain_image *
51get_layer_depth_image(const struct comp_layer *layer, uint32_t swapchain_index, uint32_t image_index)
52{
53
54 const struct comp_swapchain *sc =
55 (struct comp_swapchain *)(comp_layer_get_depth_swapchain(layer, swapchain_index));
56 return &sc->images[image_index];
57}
58
59
60static inline uint32_t
61xrt_layer_to_cs_layer_type(const struct xrt_layer_data *data)
62{
63 switch (data->type) {
64 case XRT_LAYER_QUAD: return LAYER_COMP_TYPE_QUAD;
65 case XRT_LAYER_CYLINDER: return LAYER_COMP_TYPE_CYLINDER;
66 case XRT_LAYER_EQUIRECT2: return LAYER_COMP_TYPE_EQUIRECT2;
67 case XRT_LAYER_PROJECTION:
68 case XRT_LAYER_PROJECTION_DEPTH: return LAYER_COMP_TYPE_PROJECTION;
69 default: U_LOG_E("Invalid layer type! %u", data->type); return LAYER_COMP_TYPE_NOOP;
70 }
71}
72
73
74/*
75 *
76 * Compute layer data builders.
77 *
78 */
79
80/// Data setup for a cylinder layer
81static inline void
82do_cs_cylinder_layer(const struct comp_layer *layer,
83 const struct xrt_matrix_4x4 *eye_view_mat,
84 const struct xrt_matrix_4x4 *world_view_mat,
85 uint32_t view_index,
86 uint32_t cur_layer,
87 uint32_t cur_image,
88 VkSampler clamp_to_edge,
89 VkSampler clamp_to_border_black,
90 VkSampler src_samplers[RENDER_MAX_IMAGES_SIZE],
91 VkImageView src_image_views[RENDER_MAX_IMAGES_SIZE],
92 struct render_compute_layer_ubo_data *ubo_data,
93 uint32_t *out_cur_image)
94{
95 const struct xrt_layer_data *layer_data = &layer->data;
96 const struct xrt_layer_cylinder_data *c = &layer_data->cylinder;
97 const uint32_t array_index = c->sub.array_index;
98 const struct comp_swapchain_image *image = get_layer_image(layer, 0, c->sub.image_index);
99
100 // Image to use.
101 src_samplers[cur_image] = clamp_to_edge;
102 src_image_views[cur_image] = get_image_view(image, layer_data->flags, array_index);
103
104 // Used for Subimage and OpenGL flip.
105 set_post_transform_rect( //
106 layer_data, // data
107 &c->sub.norm_rect, // src_norm_rect
108 false, // invert_flip
109 &ubo_data->post_transforms[cur_layer]); // out_norm_rect
110
111 ubo_data->cylinder_data[cur_layer].central_angle = c->central_angle;
112 ubo_data->cylinder_data[cur_layer].aspect_ratio = c->aspect_ratio;
113
114 struct xrt_vec3 scale = {1.f, 1.f, 1.f};
115
116 struct xrt_matrix_4x4 model;
117 math_matrix_4x4_model(&c->pose, &scale, &model);
118
119 struct xrt_matrix_4x4 model_inv;
120 math_matrix_4x4_inverse(&model, &model_inv);
121
122 const struct xrt_matrix_4x4 *v = is_layer_view_space(layer_data) ? eye_view_mat : world_view_mat;
123
124 struct xrt_matrix_4x4 v_inv;
125 math_matrix_4x4_inverse(v, &v_inv);
126
127 math_matrix_4x4_multiply(&model_inv, &v_inv, &ubo_data->mv_inverse[cur_layer]);
128
129 // Simplifies the shader.
130 if (c->radius >= INFINITY) {
131 ubo_data->cylinder_data[cur_layer].radius = 0.f;
132 } else {
133 ubo_data->cylinder_data[cur_layer].radius = c->radius;
134 }
135
136 ubo_data->cylinder_data[cur_layer].central_angle = c->central_angle;
137 ubo_data->cylinder_data[cur_layer].aspect_ratio = c->aspect_ratio;
138
139 ubo_data->image_info[cur_layer].color_image_index = cur_image;
140 cur_image++;
141
142 *out_cur_image = cur_image;
143}
144
145/// Data setup for an "equirect2" layer
146static inline void
147do_cs_equirect2_layer(const struct comp_layer *layer,
148 const struct xrt_matrix_4x4 *eye_view_mat,
149 const struct xrt_matrix_4x4 *world_view_mat,
150 uint32_t view_index,
151 uint32_t cur_layer,
152 uint32_t cur_image,
153 VkSampler clamp_to_edge,
154 VkSampler clamp_to_border_black,
155 VkSampler src_samplers[RENDER_MAX_IMAGES_SIZE],
156 VkImageView src_image_views[RENDER_MAX_IMAGES_SIZE],
157 struct render_compute_layer_ubo_data *ubo_data,
158 uint32_t *out_cur_image)
159{
160 const struct xrt_layer_data *layer_data = &layer->data;
161 const struct xrt_layer_equirect2_data *eq2 = &layer_data->equirect2;
162 const uint32_t array_index = eq2->sub.array_index;
163 const struct comp_swapchain_image *image = get_layer_image(layer, 0, eq2->sub.image_index);
164
165 // Image to use.
166 src_samplers[cur_image] = clamp_to_edge;
167 src_image_views[cur_image] = get_image_view(image, layer_data->flags, array_index);
168
169 // Used for Subimage and OpenGL flip.
170 set_post_transform_rect( //
171 layer_data, // data
172 &eq2->sub.norm_rect, // src_norm_rect
173 false, // invert_flip
174 &ubo_data->post_transforms[cur_layer]); // out_norm_rect
175
176 struct xrt_vec3 scale = {1.f, 1.f, 1.f};
177
178 struct xrt_matrix_4x4 model;
179 math_matrix_4x4_model(&eq2->pose, &scale, &model);
180
181 struct xrt_matrix_4x4 model_inv;
182 math_matrix_4x4_inverse(&model, &model_inv);
183
184 const struct xrt_matrix_4x4 *v = is_layer_view_space(layer_data) ? eye_view_mat : world_view_mat;
185
186 struct xrt_matrix_4x4 v_inv;
187 math_matrix_4x4_inverse(v, &v_inv);
188
189 math_matrix_4x4_multiply(&model_inv, &v_inv, &ubo_data->mv_inverse[cur_layer]);
190
191 // Simplifies the shader.
192 if (eq2->radius >= INFINITY) {
193 ubo_data->eq2_data[cur_layer].radius = 0.f;
194 } else {
195 ubo_data->eq2_data[cur_layer].radius = eq2->radius;
196 }
197
198 ubo_data->eq2_data[cur_layer].central_horizontal_angle = eq2->central_horizontal_angle;
199 ubo_data->eq2_data[cur_layer].upper_vertical_angle = eq2->upper_vertical_angle;
200 ubo_data->eq2_data[cur_layer].lower_vertical_angle = eq2->lower_vertical_angle;
201
202 ubo_data->image_info[cur_layer].color_image_index = cur_image;
203 cur_image++;
204
205 *out_cur_image = cur_image;
206}
207
208/// Data setup for a projection layer
209static inline void
210do_cs_projection_layer(const struct comp_layer *layer,
211 const struct xrt_pose *world_pose_scanout_begin,
212 uint32_t view_index,
213 uint32_t cur_layer,
214 uint32_t cur_image,
215 VkSampler clamp_to_edge,
216 VkSampler clamp_to_border_black,
217 VkSampler src_samplers[RENDER_MAX_IMAGES_SIZE],
218 VkImageView src_image_views[RENDER_MAX_IMAGES_SIZE],
219 struct render_compute_layer_ubo_data *ubo_data,
220 bool do_timewarp,
221 uint32_t *out_cur_image)
222{
223 const struct xrt_layer_data *layer_data = &layer->data;
224 const struct xrt_layer_projection_view_data *vd = NULL;
225 const struct xrt_layer_depth_data *dvd = NULL;
226
227 if (layer_data->type == XRT_LAYER_PROJECTION) {
228 view_index_to_projection_data(view_index, layer_data, &vd);
229 } else {
230 view_index_to_depth_data(view_index, layer_data, &vd, &dvd);
231 }
232
233 uint32_t sc_array_index = is_view_index_right(view_index) ? 1 : 0;
234 uint32_t array_index = vd->sub.array_index;
235 const struct comp_swapchain_image *image = get_layer_image(layer, sc_array_index, vd->sub.image_index);
236
237 // Color
238 src_samplers[cur_image] = clamp_to_border_black;
239 src_image_views[cur_image] = get_image_view(image, layer_data->flags, array_index);
240 ubo_data->image_info[cur_layer + 0].color_image_index = cur_image++;
241
242 // Depth
243 if (layer_data->type == XRT_LAYER_PROJECTION_DEPTH) {
244 uint32_t d_array_index = dvd->sub.array_index;
245 const struct comp_swapchain_image *d_image =
246 get_layer_depth_image(layer, sc_array_index, dvd->sub.image_index);
247
248 src_samplers[cur_image] = clamp_to_edge; // Edge to keep depth stable at edges.
249 src_image_views[cur_image] = get_image_view(d_image, layer_data->flags, d_array_index);
250 ubo_data->image_info[cur_layer + 0].depth_image_index = cur_image++;
251 }
252
253 set_post_transform_rect( //
254 layer_data, // data
255 &vd->sub.norm_rect, // src_norm_rect
256 false, // invert_flip
257 &ubo_data->post_transforms[cur_layer]); // out_norm_rect
258
259 // unused if timewarp is off
260 if (do_timewarp) {
261 render_calc_time_warp_matrix( //
262 &vd->pose, //
263 &vd->fov, //
264 world_pose_scanout_begin, //
265 &ubo_data->transforms_timewarp[cur_layer]); //
266 }
267
268 *out_cur_image = cur_image;
269}
270
271/// Data setup for a quad layer
272static inline void
273do_cs_quad_layer(const struct comp_layer *layer,
274 const struct xrt_matrix_4x4 *eye_view_mat,
275 const struct xrt_matrix_4x4 *world_view_mat,
276 uint32_t view_index,
277 uint32_t cur_layer,
278 uint32_t cur_image,
279 VkSampler clamp_to_edge,
280 VkSampler clamp_to_border_black,
281 VkSampler src_samplers[RENDER_MAX_IMAGES_SIZE],
282 VkImageView src_image_views[RENDER_MAX_IMAGES_SIZE],
283 struct render_compute_layer_ubo_data *ubo_data,
284 uint32_t *out_cur_image)
285{
286 const struct xrt_layer_data *layer_data = &layer->data;
287 const struct xrt_layer_quad_data *q = &layer_data->quad;
288 const uint32_t array_index = q->sub.array_index;
289 const struct comp_swapchain_image *image = get_layer_image(layer, 0, q->sub.image_index);
290
291 // Image to use.
292 src_samplers[cur_image] = clamp_to_edge;
293 src_image_views[cur_image] = get_image_view(image, layer_data->flags, array_index);
294
295 // Set the normalized post transform values.
296 struct xrt_normalized_rect post_transform = XRT_STRUCT_INIT;
297
298 // Used for Subimage and OpenGL flip.
299 set_post_transform_rect( //
300 layer_data, // data
301 &q->sub.norm_rect, // src_norm_rect
302 true, // invert_flip
303 &post_transform); // out_norm_rect
304
305 // Is this layer viewspace or not.
306 const struct xrt_matrix_4x4 *view_mat = is_layer_view_space(layer_data) ? eye_view_mat : world_view_mat;
307
308 // Transform quad pose into view space.
309 struct xrt_vec3 quad_position = XRT_STRUCT_INIT;
310 math_matrix_4x4_transform_vec3(view_mat, &layer_data->quad.pose.position, &quad_position);
311
312 // neutral quad layer faces +z, towards the user
313 struct xrt_vec3 normal = (struct xrt_vec3){.x = 0, .y = 0, .z = 1};
314
315 // rotation of the quad normal in world space
316 struct xrt_quat rotation = layer_data->quad.pose.orientation;
317 math_quat_rotate_vec3(&rotation, &normal, &normal);
318
319 /*
320 * normal is a vector that originates on the plane, not on the origin.
321 * Instead of using the inverse quad transform to transform it into view space we can
322 * simply add up vectors:
323 *
324 * combined_normal [in world space] = plane_origin [in world space] + normal [in plane
325 * space] [with plane in world space]
326 *
327 * Then combined_normal can be transformed to view space via view matrix and a new
328 * normal_view_space retrieved:
329 *
330 * normal_view_space = combined_normal [in view space] - plane_origin [in view space]
331 */
332 struct xrt_vec3 normal_view_space = normal;
333 math_vec3_accum(&layer_data->quad.pose.position, &normal_view_space);
334 math_matrix_4x4_transform_vec3(view_mat, &normal_view_space, &normal_view_space);
335 math_vec3_subtract(&quad_position, &normal_view_space);
336
337 struct xrt_vec3 scale = {1.f, 1.f, 1.f};
338 struct xrt_matrix_4x4 plane_transform_view_space, inverse_quad_transform;
339 math_matrix_4x4_model(&layer_data->quad.pose, &scale, &plane_transform_view_space);
340 math_matrix_4x4_multiply(view_mat, &plane_transform_view_space, &plane_transform_view_space);
341 math_matrix_4x4_inverse(&plane_transform_view_space, &inverse_quad_transform);
342
343 // Write all of the UBO data.
344 ubo_data->post_transforms[cur_layer] = post_transform;
345 ubo_data->quad_extent[cur_layer].val = layer_data->quad.size;
346 ubo_data->quad_position[cur_layer].val = quad_position;
347 ubo_data->quad_normal[cur_layer].val = normal_view_space;
348 ubo_data->inverse_quad_transform[cur_layer] = inverse_quad_transform;
349 ubo_data->image_info[cur_layer].color_image_index = cur_image;
350 cur_image++;
351
352 *out_cur_image = cur_image;
353}
354
355static void
356crc_clear_output(struct render_compute *render, const struct comp_render_dispatch_data *d)
357{
358 if (d->target.view_count > XRT_MAX_VIEWS) {
359 U_LOG_E("Only supports max %d views!", XRT_MAX_VIEWS);
360 assert(d->target.view_count <= XRT_MAX_VIEWS);
361 return;
362 }
363
364 struct render_viewport_data target_viewport_datas[XRT_MAX_VIEWS];
365 for (uint32_t i = 0; i < d->target.view_count; ++i) {
366 target_viewport_datas[i] = d->views[i].target.viewport_data;
367 }
368
369
370 render_compute_clear( //
371 render, //
372 d->target.cs.image, //
373 d->target.cs.storage_view, // target_image_view
374 target_viewport_datas); // views
375}
376
377/*
378 *
379 * Compute distortion helpers.
380 *
381 */
382
383/// For use after squashing layers
384static void
385crc_distortion_after_squash(struct render_compute *render, const struct comp_render_dispatch_data *d)
386{
387 if (d->target.view_count > XRT_MAX_VIEWS) {
388 U_LOG_E("Only supports max %d views!", XRT_MAX_VIEWS);
389 assert(d->target.view_count <= XRT_MAX_VIEWS);
390 return;
391 }
392 VkSampler clamp_to_border_black = render->r->samplers.clamp_to_border_black;
393
394 // Data to fill in.
395 VkImageView src_image_views[XRT_MAX_VIEWS];
396 VkSampler src_samplers[XRT_MAX_VIEWS];
397 struct render_viewport_data target_viewport_datas[XRT_MAX_VIEWS];
398 struct xrt_normalized_rect src_norm_rects[XRT_MAX_VIEWS];
399 struct xrt_fov src_fovs[XRT_MAX_VIEWS];
400 struct xrt_pose world_poses_scanout_begin[XRT_MAX_VIEWS];
401 struct xrt_pose world_poses_scanout_end[XRT_MAX_VIEWS];
402
403 for (uint32_t i = 0; i < d->target.view_count; i++) {
404 // Data to be filled in.
405 VkImageView src_image_view;
406 struct render_viewport_data viewport_data;
407 struct xrt_normalized_rect src_norm_rect;
408
409 // Gather data.
410 src_image_view = d->views[i].squash_as_src.sample_view;
411 src_norm_rect = d->views[i].squash_as_src.norm_rect;
412 viewport_data = d->views[i].target.viewport_data;
413
414 // Fill in data.
415 src_image_views[i] = src_image_view;
416 src_norm_rects[i] = src_norm_rect;
417 src_samplers[i] = clamp_to_border_black;
418 target_viewport_datas[i] = viewport_data;
419
420 if (d->do_timewarp) {
421 world_poses_scanout_begin[i] = d->views[i].world_pose_scanout_begin;
422 world_poses_scanout_end[i] = d->views[i].world_pose_scanout_end;
423 src_fovs[i] = d->views[i].fov;
424 }
425 }
426
427 if (!d->do_timewarp) {
428 render_compute_projection_no_timewarp( //
429 render, //
430 src_samplers, //
431 src_image_views, //
432 src_norm_rects, //
433 d->target.cs.image, //
434 d->target.cs.storage_view, // target_image_view
435 target_viewport_datas); // views
436 } else {
437 render_compute_projection_scanout_compensation( //
438 render, //
439 src_samplers, //
440 src_image_views, //
441 src_norm_rects, //
442 src_fovs, //
443 world_poses_scanout_begin, //
444 world_poses_scanout_end, //
445 d->target.cs.image, //
446 d->target.cs.storage_view, // target_image_view
447 target_viewport_datas); // views
448 }
449}
450
451/// Fast path
452static void
453crc_distortion_fast_path(struct render_compute *render,
454 const struct comp_render_dispatch_data *d,
455 const struct comp_layer *layer,
456 const struct xrt_layer_projection_view_data *vds[XRT_MAX_VIEWS])
457{
458 if (d->target.view_count > XRT_MAX_VIEWS) {
459 U_LOG_E("Only supports max %d views!", XRT_MAX_VIEWS);
460 assert(d->target.view_count <= XRT_MAX_VIEWS);
461 return;
462 }
463
464 // Fetch from this data.
465 const struct xrt_layer_data *data = &layer->data;
466
467 VkSampler clamp_to_border_black = render->r->samplers.clamp_to_border_black;
468
469 // Data to fill in.
470 VkImageView src_image_views[XRT_MAX_VIEWS];
471 VkSampler src_samplers[XRT_MAX_VIEWS];
472 struct render_viewport_data target_viewport_datas[XRT_MAX_VIEWS];
473 struct xrt_normalized_rect src_norm_rects[XRT_MAX_VIEWS];
474 struct xrt_fov src_fovs[XRT_MAX_VIEWS];
475 struct xrt_pose src_poses[XRT_MAX_VIEWS];
476 struct xrt_pose world_poses_scanout_begin[XRT_MAX_VIEWS];
477 struct xrt_pose world_poses_scanout_end[XRT_MAX_VIEWS];
478
479 for (uint32_t i = 0; i < d->target.view_count; i++) {
480 // Data to be filled in.
481 VkImageView src_image_view;
482 struct render_viewport_data viewport_data;
483 struct xrt_normalized_rect src_norm_rect;
484 struct xrt_fov src_fov;
485 struct xrt_pose src_pose;
486 struct xrt_pose world_pose_scanout_begin;
487 struct xrt_pose world_pose_scanout_end;
488 uint32_t array_index = vds[i]->sub.array_index;
489 const struct comp_swapchain_image *image = get_layer_image(layer, i, vds[i]->sub.image_index);
490
491 // Gather data.
492 src_image_view = get_image_view(image, data->flags, array_index);
493 src_norm_rect = vds[i]->sub.norm_rect;
494 viewport_data = d->views[i].target.viewport_data;
495 src_fov = vds[i]->fov;
496 src_pose = vds[i]->pose;
497 world_pose_scanout_begin = d->views[i].world_pose_scanout_begin;
498 world_pose_scanout_end = d->views[i].world_pose_scanout_end;
499
500 // No layer squasher has handled this for us already
501 if (data->flip_y) {
502 src_norm_rect.y += src_norm_rect.h;
503 src_norm_rect.h = -src_norm_rect.h;
504 }
505
506 // Fill in data.
507 src_image_views[i] = src_image_view;
508 src_norm_rects[i] = src_norm_rect;
509 src_samplers[i] = clamp_to_border_black;
510 target_viewport_datas[i] = viewport_data;
511 src_fovs[i] = src_fov;
512 src_poses[i] = src_pose;
513 world_poses_scanout_begin[i] = world_pose_scanout_begin;
514 world_poses_scanout_end[i] = world_pose_scanout_end;
515 }
516
517 if (!d->do_timewarp) {
518 render_compute_projection_no_timewarp( //
519 render, //
520 src_samplers, //
521 src_image_views, //
522 src_norm_rects, //
523 d->target.cs.image, //
524 d->target.cs.storage_view, //
525 target_viewport_datas); //
526 } else {
527 render_compute_projection_timewarp( //
528 render, //
529 src_samplers, //
530 src_image_views, //
531 src_norm_rects, //
532 src_poses, //
533 src_fovs, //
534 world_poses_scanout_begin, //
535 world_poses_scanout_end, //
536 d->target.cs.image, //
537 d->target.cs.storage_view, //
538 target_viewport_datas); //
539 }
540}
541
542
543/*
544 *
545 * 'Exported' function(s).
546 *
547 */
548
549void
550comp_render_cs_layer(struct render_compute *render,
551 uint32_t view_index,
552 const struct comp_layer *layers,
553 const uint32_t layer_count,
554 const struct xrt_normalized_rect *pre_transform,
555 const struct xrt_pose *world_pose_scanout_begin,
556 const struct xrt_pose *world_pose_scanout_end,
557 const struct xrt_pose *eye_pose,
558 const VkImage target_image,
559 const VkImageView target_image_view,
560 const struct render_viewport_data *target_view,
561 bool do_timewarp)
562{
563 VkSampler clamp_to_edge = render->r->samplers.clamp_to_edge;
564 VkSampler clamp_to_border_black = render->r->samplers.clamp_to_border_black;
565
566 // Not the transform of the views, but the inverse: actual view matrices.
567 struct xrt_matrix_4x4 world_view_mat_scanout_begin, eye_view;
568 math_matrix_4x4_view_from_pose(world_pose_scanout_begin, &world_view_mat_scanout_begin);
569 math_matrix_4x4_view_from_pose(eye_pose, &eye_view);
570
571 struct render_buffer *ubo = &render->r->compute.layer.ubos[view_index];
572 struct render_compute_layer_ubo_data *ubo_data = ubo->mapped;
573
574 // Tightly pack layers in data struct.
575 uint32_t cur_layer = 0;
576
577 // Tightly pack color and optional depth images.
578 uint32_t cur_image = 0;
579 VkSampler src_samplers[RENDER_MAX_IMAGES_SIZE];
580 VkImageView src_image_views[RENDER_MAX_IMAGES_SIZE];
581
582 ubo_data->view = *target_view;
583 ubo_data->pre_transform = *pre_transform;
584
585 for (uint32_t c_layer_i = 0; c_layer_i < layer_count; c_layer_i++) {
586 const struct comp_layer *layer = &layers[c_layer_i];
587 const struct xrt_layer_data *data = &layer->data;
588
589 if (!is_layer_view_visible(data, view_index)) {
590 continue;
591 }
592
593 /*!
594 * Stop compositing layers if device's sampled image limit is
595 * reached. For most hardware this isn't a problem, most have
596 * well over 32 max samplers. But notably the RPi4 only have 16
597 * which is a limit we may run into. But if you got 16+ layers
598 * on a RPi4 you have more problems then max samplers.
599 */
600 uint32_t required_image_samplers;
601 switch (data->type) {
602 case XRT_LAYER_CYLINDER: required_image_samplers = 1; break;
603 case XRT_LAYER_EQUIRECT2: required_image_samplers = 1; break;
604 case XRT_LAYER_PROJECTION: required_image_samplers = 1; break;
605 case XRT_LAYER_PROJECTION_DEPTH: required_image_samplers = 2; break;
606 case XRT_LAYER_QUAD: required_image_samplers = 1; break;
607 default:
608 VK_ERROR(render->r->vk, "Skipping layer #%u, unknown type: %u", c_layer_i, data->type);
609 continue; // Skip this layer if don't know about it.
610 }
611
612 //! Exit loop if shader cannot receive more image samplers
613 if (cur_image + required_image_samplers > render->r->compute.layer.image_array_size) {
614 break;
615 }
616
617 switch (data->type) {
618 case XRT_LAYER_CYLINDER:
619 do_cs_cylinder_layer( //
620 layer, // layer
621 &eye_view, // eye_view_mat
622 &world_view_mat_scanout_begin, // world_view_mat
623 view_index, // view_index
624 cur_layer, // cur_layer
625 cur_image, // cur_image
626 clamp_to_edge, // clamp_to_edge
627 clamp_to_border_black, // clamp_to_border_black
628 src_samplers, // src_samplers
629 src_image_views, // src_image_views
630 ubo_data, // ubo_data
631 &cur_image); // out_cur_image
632 break;
633 case XRT_LAYER_EQUIRECT2:
634 do_cs_equirect2_layer( //
635 layer, // layer
636 &eye_view, // eye_view_mat
637 &world_view_mat_scanout_begin, // world_view_mat
638 view_index, // view_index
639 cur_layer, // cur_layer
640 cur_image, // cur_image
641 clamp_to_edge, // clamp_to_edge
642 clamp_to_border_black, // clamp_to_border_black
643 src_samplers, // src_samplers
644 src_image_views, // src_image_views
645 ubo_data, // ubo_data
646 &cur_image); // out_cur_image
647 break;
648 case XRT_LAYER_PROJECTION_DEPTH:
649 case XRT_LAYER_PROJECTION: {
650 do_cs_projection_layer( //
651 layer, // layer
652 world_pose_scanout_begin, // world_pose_scanout_begin
653 view_index, // view_index
654 cur_layer, // cur_layer
655 cur_image, // cur_image
656 clamp_to_edge, // clamp_to_edge
657 clamp_to_border_black, // clamp_to_border_black
658 src_samplers, // src_samplers
659 src_image_views, // src_image_views
660 ubo_data, // ubo_data
661 do_timewarp, // do_timewarp
662 &cur_image); // out_cur_image
663 } break;
664 case XRT_LAYER_QUAD: {
665 do_cs_quad_layer( //
666 layer, // layer
667 &eye_view, // eye_view_mat
668 &world_view_mat_scanout_begin, // world_view_mat_scanout_begin
669 view_index, // view_index
670 cur_layer, // cur_layer
671 cur_image, // cur_image
672 clamp_to_edge, // clamp_to_edge
673 clamp_to_border_black, // clamp_to_border_black
674 src_samplers, // src_samplers
675 src_image_views, // src_image_views
676 ubo_data, // ubo_data
677 &cur_image); // out_cur_image
678 } break;
679 default:
680 // Should not get here!
681 assert(false);
682 VK_ERROR(render->r->vk, "Should not get here!");
683 continue;
684 }
685
686 ubo_data->layer_data[cur_layer].layer_type = xrt_layer_to_cs_layer_type(data);
687 ubo_data->layer_data[cur_layer].unpremultiplied_alpha = is_layer_unpremultiplied(data);
688
689 // Finally okay to increment the current layer.
690 cur_layer++;
691 }
692
693 // Set the number of layers.
694 ubo_data->layer_count.value = cur_layer;
695
696 for (uint32_t i = cur_layer; i < RENDER_MAX_LAYERS; i++) {
697 ubo_data->layer_data[i].layer_type = LAYER_COMP_TYPE_NOOP; // Explicit no-op.
698 }
699
700 //! @todo: If Vulkan 1.2, use VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT and skip this
701 while (cur_image < render->r->compute.layer.image_array_size) {
702 src_samplers[cur_image] = clamp_to_edge;
703 src_image_views[cur_image] = render->r->mock.color.image_view;
704 cur_image++;
705 }
706
707 VkDescriptorSet descriptor_set = render->layer_descriptor_sets[view_index];
708
709 render_compute_layers( //
710 render, //
711 descriptor_set, //
712 ubo->buffer, //
713 src_samplers, //
714 src_image_views, //
715 cur_image, //
716 target_image_view, //
717 target_view, //
718 do_timewarp); //
719}
720
721void
722comp_render_cs_layers(struct render_compute *render,
723 const struct comp_layer *layers,
724 const uint32_t layer_count,
725 const struct comp_render_dispatch_data *d,
726 VkImageLayout transition_to)
727{
728 cmd_barrier_view_squash_images( //
729 render->r->vk, //
730 d, //
731 render->r->cmd, // cmd
732 0, // src_access_mask
733 VK_ACCESS_SHADER_WRITE_BIT, // dst_access_mask
734 VK_IMAGE_LAYOUT_UNDEFINED, // transition_from
735 VK_IMAGE_LAYOUT_GENERAL, // transition_to
736 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, // src_stage_mask
737 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); // dst_stage_mask
738
739 for (uint32_t view_index = 0; view_index < d->squash_view_count; view_index++) {
740 const struct comp_render_view_data *view = &d->views[view_index];
741
742 comp_render_cs_layer( //
743 render, //
744 view_index, //
745 layers, //
746 layer_count, //
747 &view->pre_transform, //
748 &view->world_pose_scanout_begin, //
749 &view->world_pose_scanout_end, //
750 &view->eye_pose, //
751 view->squash.image, //
752 view->squash.cs.storage_view, //
753 &view->squash.viewport_data, //
754 d->do_timewarp); //
755 }
756
757 cmd_barrier_view_squash_images( //
758 render->r->vk, //
759 d, //
760 render->r->cmd, // cmd
761 VK_ACCESS_SHADER_WRITE_BIT, // src_access_mask
762 VK_ACCESS_MEMORY_READ_BIT, // dst_access_mask
763 VK_IMAGE_LAYOUT_GENERAL, // transition_from
764 transition_to, //
765 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, // src_stage_mask
766 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); // dst_stage_mask
767}
768
769void
770comp_render_cs_dispatch(struct render_compute *render,
771 const struct comp_layer *layers,
772 const uint32_t layer_count,
773 const struct comp_render_dispatch_data *d)
774{
775 if (!d->target.initialized) {
776 VK_ERROR(render->r->vk, "Target hasn't been initialized, not rendering anything.");
777 assert(d->target.initialized);
778 return;
779 }
780
781 // Convenience.
782 bool fast_path = d->fast_path;
783
784 // Only used if fast_path is true.
785 const struct comp_layer *layer = &layers[0];
786
787 // Consistency check.
788 assert(!fast_path || layer_count >= 1);
789
790 // We want to read from the images afterwards.
791 VkImageLayout transition_to = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
792
793 if (fast_path && layer->data.type == XRT_LAYER_PROJECTION) {
794 // Fast path.
795 const struct xrt_layer_projection_data *proj = &layer->data.proj;
796 const struct xrt_layer_projection_view_data *vds[XRT_MAX_VIEWS];
797 for (uint32_t view = 0; view < d->target.view_count; ++view) {
798 vds[view] = &proj->v[view];
799 }
800 crc_distortion_fast_path( //
801 render, //
802 d, //
803 layer, //
804 vds); //
805
806 } else if (fast_path && layer->data.type == XRT_LAYER_PROJECTION_DEPTH) {
807 // Fast path.
808 const struct xrt_layer_projection_depth_data *depth = &layer->data.depth;
809 const struct xrt_layer_projection_view_data *vds[XRT_MAX_VIEWS];
810 for (uint32_t view = 0; view < d->target.view_count; ++view) {
811 vds[view] = &depth->v[view];
812 }
813 crc_distortion_fast_path( //
814 render, //
815 d, //
816 layer, //
817 vds); //
818
819 } else if (layer_count > 0) {
820 // Compute layer squasher
821 if (fast_path) {
822 U_LOG_W("Wanted fast path but no projection layer, falling back to layer squasher.");
823 }
824
825 /*
826 * Layer squashing.
827 */
828 comp_render_cs_layers( //
829 render, //
830 layers, //
831 layer_count, //
832 d, //
833 transition_to); //
834
835 /*
836 * Distortion.
837 */
838 crc_distortion_after_squash( //
839 render, //
840 d); //
841
842 } else {
843 // Just clear the screen
844 crc_clear_output( //
845 render, //
846 d); //
847 }
848}