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