The open source OpenXR runtime
1// Copyright 2019-2023, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief The NEW compositor rendering code header.
6 * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
7 * @author Jakob Bornecrantz <jakob@collabora.com>
8 * @ingroup comp_render
9 */
10
11#pragma once
12
13#include "xrt/xrt_compiler.h"
14#include "xrt/xrt_defines.h"
15
16#include "vk/vk_helpers.h"
17#include "vk/vk_cmd_pool.h"
18
19
20#ifdef __cplusplus
21extern "C" {
22#endif
23
24
25/*!
26 * @defgroup comp_render Compositor render code
27 * @ingroup comp
28 *
29 * @brief Rendering helper that is used by the compositor to render.
30 */
31
32/*!
33 * @addtogroup comp_render
34 * @{
35 */
36
37/*
38 *
39 * Defines
40 *
41 */
42
43/*!
44 * The value `minUniformBufferOffsetAlignment` is defined by the Vulkan spec as
45 * having a max value of 256. Use this value to safely figure out sizes and
46 * alignment of UBO sub-allocation. It is also the max for 'nonCoherentAtomSize`
47 * which if we need to do flushing is what we need to align UBOs to.
48 *
49 * https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html
50 * https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#limits-minmax
51 */
52#define RENDER_ALWAYS_SAFE_UBO_ALIGNMENT (256)
53
54/*!
55 * Max number of layers for layer squasher, can be different from
56 * @ref XRT_MAX_LAYERS as the render module is separate from the compositor.
57 */
58#define RENDER_MAX_LAYERS (XRT_MAX_LAYERS)
59
60/*!
61 * Max number of images that can be given at a single time to the layer
62 * squasher in a single dispatch.
63 */
64#define RENDER_MAX_IMAGES_SIZE (RENDER_MAX_LAYERS * XRT_MAX_VIEWS)
65#define RENDER_MAX_IMAGES_COUNT(RENDER_RESOURCES) (RENDER_MAX_LAYERS * RENDER_RESOURCES->view_count)
66
67/*!
68 * Maximum number of times that the layer squasher shader can run per
69 * @ref render_compute. Since you run the layer squasher shader once per view
70 * this is essentially the same as number of views. But if you were to do
71 * two or more different compositions it is not the maximum number of views per
72 * composition (which is this number divided by number of composition).
73 */
74#define RENDER_MAX_LAYER_RUNS_SIZE (XRT_MAX_VIEWS)
75#define RENDER_MAX_LAYER_RUNS_COUNT(RENDER_RESOURCES) (RENDER_RESOURCES->view_count)
76
77//! Distortion image dimension in pixels
78#define RENDER_DISTORTION_IMAGE_DIMENSIONS (128)
79
80//! How many distortion images we have, one for each channel (3 rgb) and per view.
81#define RENDER_DISTORTION_IMAGES_SIZE (3 * XRT_MAX_VIEWS)
82#define RENDER_DISTORTION_IMAGES_COUNT(RENDER_RESOURCES) (3 * RENDER_RESOURCES->view_count)
83
84//! The binding that the layer projection and quad shader have their UBO on.
85#define RENDER_BINDING_LAYER_SHARED_UBO 0
86
87//! The binding that the shared layer fragment shader has its source on.
88#define RENDER_BINDING_LAYER_SHARED_SRC 1
89
90
91/*
92 *
93 * Util functions.
94 *
95 */
96
97/*!
98 * Create a simplified projection matrix for timewarp.
99 */
100void
101render_calc_time_warp_projection(const struct xrt_fov *fov, struct xrt_matrix_4x4 *result);
102
103/*!
104 * Calculates a timewarp matrix which takes in NDC coords and gives out results
105 * in [-1, 1] space that needs a perspective divide.
106 */
107void
108render_calc_time_warp_matrix(const struct xrt_pose *src_pose,
109 const struct xrt_fov *src_fov,
110 const struct xrt_pose *new_pose,
111 struct xrt_matrix_4x4 *matrix);
112
113/*!
114 * This function constructs a transformation in the form of a normalized rect
115 * that lets you go from a UV coordinate on a projection plane to the a point on
116 * the tangent plane. An example is that the UV coordinate `(0, 0)` would be
117 * transformed to `(tan(angle_left), tan(fov.angle_up))`. The tangent plane (aka
118 * tangent space) is really the tangent of the angle, aka length at unit distance.
119 *
120 * For the trivial case of an fov with 45 degrees angles, that is where the
121 * tangent length are `1` (aka `tan(45)`), the transformation would go from
122 * `[0 .. 1]` to `[-1 .. 1]` the expected returns are `x = -1`, `y = -1`,
123 * `w = 2` and `h = 2`.
124 *
125 * param fov The fov of the projection image.
126 * param[out] out_rect Transformation from UV to tangent lengths.
127 */
128void
129render_calc_uv_to_tangent_lengths_rect(const struct xrt_fov *fov, struct xrt_normalized_rect *out_rect);
130
131
132/*
133 *
134 * Shaders.
135 *
136 */
137
138/*!
139 * Holds all shaders.
140 */
141struct render_shaders
142{
143 VkShaderModule blit_comp;
144 VkShaderModule clear_comp;
145 VkShaderModule layer_comp;
146 VkShaderModule distortion_comp;
147
148 VkShaderModule mesh_vert;
149 VkShaderModule mesh_frag;
150
151
152 /*
153 * New layer renderer.
154 */
155
156 VkShaderModule layer_cylinder_vert;
157 VkShaderModule layer_cylinder_frag;
158
159 VkShaderModule layer_equirect2_vert;
160 VkShaderModule layer_equirect2_frag;
161
162 VkShaderModule layer_projection_vert;
163 VkShaderModule layer_quad_vert;
164 VkShaderModule layer_shared_frag;
165};
166
167/*!
168 * Loads all of the shaders that the compositor uses.
169 */
170bool
171render_shaders_load(struct render_shaders *s, struct vk_bundle *vk);
172
173/*!
174 * Unload and cleanup shaders.
175 */
176void
177render_shaders_fini(struct render_shaders *s, struct vk_bundle *vk);
178
179
180/*
181 *
182 * Buffer
183 *
184 */
185
186/*!
187 * Helper struct holding a buffer and its memory.
188 */
189struct render_buffer
190{
191 //! Backing memory.
192 VkDeviceMemory memory;
193
194 //! Buffer.
195 VkBuffer buffer;
196
197 //! Size requested for the buffer.
198 VkDeviceSize size;
199
200 //! Size of the memory allocation.
201 VkDeviceSize allocation_size;
202
203 //! Alignment of the buffer.
204 VkDeviceSize alignment;
205
206 void *mapped;
207};
208
209/*!
210 * Initialize a buffer.
211 */
212VkResult
213render_buffer_init(struct vk_bundle *vk,
214 struct render_buffer *buffer,
215 VkBufferUsageFlags usage_flags,
216 VkMemoryPropertyFlags memory_property_flags,
217 VkDeviceSize size);
218
219/*!
220 * Initialize a buffer, making it exportable.
221 */
222VkResult
223render_buffer_init_exportable(struct vk_bundle *vk,
224 struct render_buffer *buffer,
225 VkBufferUsageFlags usage_flags,
226 VkMemoryPropertyFlags memory_property_flags,
227 VkDeviceSize size);
228
229/*!
230 * Frees all resources that this buffer has, but does not free the buffer itself.
231 */
232void
233render_buffer_fini(struct vk_bundle *vk, struct render_buffer *buffer);
234
235/*!
236 * Maps the memory, sets render_buffer::mapped to the memory.
237 */
238VkResult
239render_buffer_map(struct vk_bundle *vk, struct render_buffer *buffer);
240
241/*!
242 * Unmaps the memory.
243 */
244void
245render_buffer_unmap(struct vk_bundle *vk, struct render_buffer *buffer);
246
247/*!
248 * Maps the buffer, and copies the given data to the buffer.
249 */
250VkResult
251render_buffer_map_and_write(struct vk_bundle *vk, struct render_buffer *buffer, void *data, VkDeviceSize size);
252
253/*!
254 * Writes the given data to the buffer, will map it temporarily if not mapped.
255 */
256VkResult
257render_buffer_write(struct vk_bundle *vk, struct render_buffer *buffer, void *data, VkDeviceSize size);
258
259
260/*
261 *
262 * Sub-alloc.
263 *
264 */
265
266/*!
267 * Per frame sub-allocation into a buffer, used to reduce the number of UBO
268 * objects we need to create. There is no way to free a sub-allocation, this is
269 * done implicitly at the end of the frame when @ref render_sub_alloc_tracker is
270 * zeroed out.
271 *
272 * @see render_sub_alloc_tracker
273 */
274struct render_sub_alloc
275{
276 /*!
277 * The buffer this is allocated from, it is the caller's responsibility
278 * to keep it alive for as long as the sub-allocation is used.
279 */
280 VkBuffer buffer;
281
282 //! Size of sub-allocation.
283 VkDeviceSize size;
284
285 //! Offset into buffer.
286 VkDeviceSize offset;
287};
288
289/*!
290 * A per-frame tracker of sub-allocation out of a buffer, used to reduce the
291 * number of UBO objects we need to create. This code is designed with one
292 * constraint in mind, that the lifetime of a sub-allocation is only for one
293 * frame and is discarded at the end of it, but also alive for the entire frame.
294 * This removes the need to free individual sub-allocation, or even track them
295 * beyond filling the UBO data and descriptor sets.
296 *
297 * @see render_sub_alloc
298 */
299struct render_sub_alloc_tracker
300{
301 /*!
302 * The buffer to allocate from, it is the caller's responsibility to keep
303 * it alive for as long as the sub-allocations are in used.
304 */
305 VkBuffer buffer;
306
307 //! Start of memory, if buffer was mapped with initialised.
308 void *mapped;
309
310 //! Total size of buffer.
311 VkDeviceSize total_size;
312
313 //! Currently used memory.
314 VkDeviceSize used;
315};
316
317/*!
318 * Init a @ref render_sub_alloc_tracker struct from a @ref render_buffer, the
319 * caller is responsible for keeping @p buffer alive while the sub allocator
320 * is being used.
321 */
322void
323render_sub_alloc_tracker_init(struct render_sub_alloc_tracker *rsat, struct render_buffer *buffer);
324
325/*!
326 * Allocate enough memory (with constraints of UBOs) of @p size, return the
327 * pointer to the mapped memory or null if the buffer wasn't allocated.
328 */
329XRT_CHECK_RESULT VkResult
330render_sub_alloc_ubo_alloc_and_get_ptr(struct vk_bundle *vk,
331 struct render_sub_alloc_tracker *rsat,
332 VkDeviceSize size,
333 void **out_ptr,
334 struct render_sub_alloc *out_rsa);
335
336/*!
337 * Allocate enough memory (with constraints of UBOs) to hold the memory in @p ptr
338 * and copy that memory to the buffer using the CPU.
339 */
340XRT_CHECK_RESULT VkResult
341render_sub_alloc_ubo_alloc_and_write(struct vk_bundle *vk,
342 struct render_sub_alloc_tracker *rsat,
343 const void *ptr,
344 VkDeviceSize size,
345 struct render_sub_alloc *out_rsa);
346
347
348/*
349 *
350 * Resources
351 *
352 */
353
354/*!
355 * Holds all pools and static resources for rendering.
356 */
357struct render_resources
358{
359 //! The count of views that we are rendering to.
360 uint32_t view_count;
361
362 //! Vulkan resources.
363 struct vk_bundle *vk;
364
365 /*
366 * Loaded resources.
367 */
368
369 //! All shaders loaded.
370 struct render_shaders *shaders;
371
372
373 /*
374 * Shared pools and caches.
375 */
376
377 //! Pool used for distortion image uploads.
378 struct vk_cmd_pool distortion_pool;
379
380 //! Shared for all rendering.
381 VkPipelineCache pipeline_cache;
382
383 VkCommandPool cmd_pool;
384
385 VkQueryPool query_pool;
386
387
388 /*
389 * Static
390 */
391
392 //! Command buffer for recording everything.
393 VkCommandBuffer cmd;
394
395 struct
396 {
397 //! Sampler for mock/null images.
398 VkSampler mock;
399
400 //! Sampler that repeats the texture in all directions.
401 VkSampler repeat;
402
403 //! Sampler that clamps the coordinates to the edge in all directions.
404 VkSampler clamp_to_edge;
405
406 //! Sampler that clamps color samples to black in all directions.
407 VkSampler clamp_to_border_black;
408 } samplers;
409
410 struct
411 {
412 //! Pool for shaders that uses one ubo and sampler.
413 VkDescriptorPool ubo_and_src_descriptor_pool;
414
415 /*!
416 * Shared UBO buffer that we sub-allocate out of, this is to
417 * have fewer buffers that the kernel needs to validate on
418 * command submission time.
419 *
420 * https://registry.khronos.org/vulkan/site/guide/latest/memory_allocation.html
421 */
422 struct render_buffer shared_ubo;
423
424 struct
425 {
426 struct
427 {
428 //! For projection and quad layer.
429 VkDescriptorSetLayout descriptor_set_layout;
430
431 //! For projection and quad layer.
432 VkPipelineLayout pipeline_layout;
433 } shared;
434 } layer;
435 } gfx;
436
437 struct
438 {
439 //! The binding index for the source texture.
440 uint32_t src_binding;
441
442 //! The binding index for the UBO.
443 uint32_t ubo_binding;
444
445 //! Descriptor set layout for mesh distortion.
446 VkDescriptorSetLayout descriptor_set_layout;
447
448 //! Pipeline layout used for mesh.
449 VkPipelineLayout pipeline_layout;
450
451 struct render_buffer vbo;
452 struct render_buffer ibo;
453
454 uint32_t vertex_count;
455 uint32_t index_counts[XRT_MAX_VIEWS];
456 uint32_t stride;
457 uint32_t index_offsets[XRT_MAX_VIEWS];
458 uint32_t index_count_total;
459
460 //! Info UBOs.
461 struct render_buffer ubos[XRT_MAX_VIEWS];
462 } mesh;
463
464 /*!
465 * Used as a default image empty image when none is given or to pad
466 * out fixed sized descriptor sets.
467 */
468 struct
469 {
470 struct
471 {
472 VkImage image;
473 VkImageView image_view;
474 VkDeviceMemory memory;
475 } color;
476 } mock;
477
478 struct
479 {
480 //! Descriptor pool for compute work.
481 VkDescriptorPool descriptor_pool;
482
483 //! The source projection view binding point.
484 uint32_t src_binding;
485
486 //! Image storing the distortion.
487 uint32_t distortion_binding;
488
489 //! Writing the image out too.
490 uint32_t target_binding;
491
492 //! Uniform data binding.
493 uint32_t ubo_binding;
494
495 struct
496 {
497 //! Descriptor set layout for compute.
498 VkDescriptorSetLayout descriptor_set_layout;
499
500 //! Pipeline layout used for compute distortion.
501 VkPipelineLayout pipeline_layout;
502
503 //! Doesn't depend on target so is static.
504 VkPipeline non_timewarp_pipeline;
505
506 //! Doesn't depend on target so is static.
507 VkPipeline timewarp_pipeline;
508
509 //! Size of combined image sampler array
510 uint32_t image_array_size;
511
512 //! Target info.
513 struct render_buffer ubos[RENDER_MAX_LAYER_RUNS_SIZE];
514 } layer;
515
516 struct
517 {
518 //! Descriptor set layout for compute distortion.
519 VkDescriptorSetLayout descriptor_set_layout;
520
521 //! Pipeline layout used for compute distortion, shared with clear.
522 VkPipelineLayout pipeline_layout;
523
524 //! Doesn't depend on target so is static.
525 VkPipeline pipeline;
526
527 //! Doesn't depend on target so is static.
528 VkPipeline timewarp_pipeline;
529
530 //! Target info.
531 struct render_buffer ubo;
532 } distortion;
533
534 struct
535 {
536 //! Doesn't depend on target so is static.
537 VkPipeline pipeline;
538
539 //! Target info.
540 struct render_buffer ubo;
541
542 //! @todo other resources
543 } clear;
544 } compute;
545
546 struct
547 {
548 //! Transform to go from UV to tangle angles.
549 struct xrt_normalized_rect uv_to_tanangle[XRT_MAX_VIEWS];
550
551 //! Backing memory to distortion images.
552 VkDeviceMemory device_memories[RENDER_DISTORTION_IMAGES_SIZE];
553
554 //! Distortion images.
555 VkImage images[RENDER_DISTORTION_IMAGES_SIZE];
556
557 //! The views into the distortion images.
558 VkImageView image_views[RENDER_DISTORTION_IMAGES_SIZE];
559
560 //! Whether distortion images have been pre-rotated 90 degrees.
561 bool pre_rotated;
562 } distortion;
563};
564
565/*!
566 * Allocate pools and static resources.
567 *
568 * @ingroup comp_main
569 *
570 * @public @memberof render_resources
571 */
572bool
573render_resources_init(struct render_resources *r,
574 struct render_shaders *shaders,
575 struct vk_bundle *vk,
576 struct xrt_device *xdev);
577
578/*!
579 * Free all pools and static resources, does not free the struct itself.
580 *
581 * @public @memberof render_resources
582 */
583void
584render_resources_fini(struct render_resources *r);
585
586/*!
587 * Creates or recreates the compute distortion textures if necessary.
588 *
589 * @see render_distortion_images_fini
590 * @public @memberof render_resources
591 */
592bool
593render_distortion_images_ensure(struct render_resources *r,
594 struct vk_bundle *vk,
595 struct xrt_device *xdev,
596 bool pre_rotate);
597
598/*!
599 * Free distortion images.
600 *
601 * @see render_distortion_images_ensure
602 * @public @memberof render_resources
603 */
604void
605render_distortion_images_fini(struct render_resources *r);
606
607/*!
608 * Returns the timestamps for when the latest GPU work started and stopped that
609 * was submitted using @ref render_gfx or @ref render_compute cmd buf builders.
610 *
611 * Returned in the same time domain as returned by @ref os_monotonic_get_ns .
612 * Behaviour for this function is undefined if the GPU has not completed before
613 * calling this function, so make sure to call vkQueueWaitIdle or wait on the
614 * fence that the work was submitted with have fully completed. See other
615 * limitation mentioned for @ref vk_convert_timestamps_to_host_ns .
616 *
617 * @see vk_convert_timestamps_to_host_ns
618 *
619 * @public @memberof render_resources
620 */
621bool
622render_resources_get_timestamps(struct render_resources *r, uint64_t *out_gpu_start_ns, uint64_t *out_gpu_end_ns);
623
624/*!
625 * Returns the duration for the latest GPU work that was submitted using
626 * @ref render_gfx or @ref render_compute cmd buf builders.
627 *
628 * Behaviour for this function is undefined if the GPU has not completed before
629 * calling this function, so make sure to call vkQueueWaitIdle or wait on the
630 * fence that the work was submitted with have fully completed.
631 *
632 * @public @memberof render_resources
633 */
634bool
635render_resources_get_duration(struct render_resources *r, uint64_t *out_gpu_duration_ns);
636
637
638/*
639 *
640 * Scratch images.
641 *
642 */
643
644/*!
645 * Small helper struct to hold a scratch image, intended to be used with the
646 * compute pipeline where both srgb and unorm views are needed.
647 */
648struct render_scratch_color_image
649{
650 VkDeviceMemory device_memory;
651 VkImage image;
652 VkImageView srgb_view;
653 VkImageView unorm_view;
654};
655
656/*!
657 * Helper struct to hold scratch images.
658 */
659struct render_scratch_images
660{
661 VkExtent2D extent;
662
663 struct render_scratch_color_image color[XRT_MAX_VIEWS];
664};
665
666/*!
667 * Ensure that the scratch images are created and have the given extent.
668 *
669 * @public @memberof render_scratch_images
670 */
671bool
672render_scratch_images_ensure(struct render_resources *r, struct render_scratch_images *rsi, VkExtent2D extent);
673
674/*!
675 * Close all resources on the given @ref render_scratch_images.
676 *
677 * @public @memberof render_scratch_images
678 */
679void
680render_scratch_images_fini(struct render_resources *r, struct render_scratch_images *rsi);
681
682
683/*
684 *
685 * Shared between both gfx and compute.
686 *
687 */
688
689/*!
690 * The pure data information about a view that the renderer is rendering to.
691 */
692struct render_viewport_data
693{
694 uint32_t x, y;
695 uint32_t w, h;
696};
697
698
699/*
700 *
701 * Render pass
702 *
703 */
704
705/*!
706 * A render pass, while not depending on a @p VkFramebuffer, does depend on the
707 * format of the target image(s), and other options for the render pass. These
708 * are used to create a @p VkRenderPass, all @p VkFramebuffer(s) and
709 * @p VkPipeline depends on the @p VkRenderPass so hang off this struct.
710 */
711struct render_gfx_render_pass
712{
713 struct render_resources *r;
714
715 //! The format of the image(s) we are rendering to.
716 VkFormat format;
717
718 //! Sample count for this render pass.
719 VkSampleCountFlagBits sample_count;
720
721 //! Load op used on the attachment(s).
722 VkAttachmentLoadOp load_op;
723
724 //! Final layout of the target image(s).
725 VkImageLayout final_layout;
726
727 //! Render pass used for rendering.
728 VkRenderPass render_pass;
729
730 struct
731 {
732 //! Pipeline layout used for mesh, without timewarp.
733 VkPipeline pipeline;
734
735 //! Pipeline layout used for mesh, with timewarp.
736 VkPipeline pipeline_timewarp;
737 } mesh;
738
739 struct
740 {
741 VkPipeline cylinder_premultiplied_alpha;
742 VkPipeline cylinder_unpremultiplied_alpha;
743
744 VkPipeline equirect2_premultiplied_alpha;
745 VkPipeline equirect2_unpremultiplied_alpha;
746
747 VkPipeline proj_premultiplied_alpha;
748 VkPipeline proj_unpremultiplied_alpha;
749
750 VkPipeline quad_premultiplied_alpha;
751 VkPipeline quad_unpremultiplied_alpha;
752 } layer;
753};
754
755/*!
756 * Creates all resources held by the render pass.
757 *
758 * @public @memberof render_gfx_render_pass
759 */
760bool
761render_gfx_render_pass_init(struct render_gfx_render_pass *rgrp,
762 struct render_resources *r,
763 VkFormat format,
764 VkAttachmentLoadOp load_op,
765 VkImageLayout final_layout);
766
767/*!
768 * Frees all resources held by the render pass, does not free the struct itself.
769 *
770 * @public @memberof render_gfx_render_pass
771 */
772void
773render_gfx_render_pass_fini(struct render_gfx_render_pass *rgrp);
774
775
776/*
777 *
778 * Rendering target
779 *
780 */
781
782/*!
783 * Each rendering (@ref render_gfx) render to one or more targets
784 * (@ref render_gfx_target_resources), the target points to one render pass and
785 * its pipelines (@ref render_gfx_render_pass). It is up to the code using
786 * these to do reuse of render passes and ensure they match.
787 *
788 * @see comp_render_gfx
789 */
790struct render_gfx_target_resources
791{
792 //! Collections of static resources.
793 struct render_resources *r;
794
795 //! Render pass.
796 struct render_gfx_render_pass *rgrp;
797
798 // The extent of the framebuffer.
799 VkExtent2D extent;
800
801 //! Framebuffer for this target, depends on given VkImageView.
802 VkFramebuffer framebuffer;
803};
804
805/*!
806 * Init a target resource struct, caller has to keep target alive until closed.
807 *
808 * @public @memberof render_gfx_target_resources
809 */
810bool
811render_gfx_target_resources_init(struct render_gfx_target_resources *rtr,
812 struct render_resources *r,
813 struct render_gfx_render_pass *rgrp,
814 VkImageView target,
815 VkExtent2D extent);
816
817/*!
818 * Frees all resources held by the target, does not free the struct itself.
819 *
820 * @public @memberof render_gfx_target_resources
821 */
822void
823render_gfx_target_resources_fini(struct render_gfx_target_resources *rtr);
824
825
826/*
827 *
828 * Rendering
829 *
830 */
831
832/*!
833 * The low-level resources and operations to perform layer squashing and/or
834 * mesh distortion for a single frame using graphics shaders.
835 *
836 * It uses a two-stage process to render a frame. This means
837 * consumers iterate layers (or other operations) **twice**, within each target and view.
838 * There is a preparation stage, where the uniform buffer is sub-allocated and written.
839 * This must be completed for all layers before the actual draw stage begins.
840 * The second stage is recording the draw commands into a command buffer.
841 *
842 * You must make equivalent calls in the same order between the two stages. The second stage
843 * additionally has @ref render_gfx_begin_target, @ref render_gfx_end_target,
844 * @ref render_gfx_begin_view, and @ref render_gfx_end_view lacked by the first stage,
845 * but if you exclude those functions, the others must line up.
846 *
847 * Furthermore, the struct needs to be kept alive until the work has been waited on,
848 * or you get validation warnings. Either wait on the `VkFence` for the submit, or call
849 * `vkDeviceWaitIdle`/`vkQueueWaitIdle` on the device/queue.
850 *
851 * @see comp_render_gfx
852 */
853struct render_gfx
854{
855 //! Resources that we are based on.
856 struct render_resources *r;
857
858 //! Shared buffer that we sub-allocate UBOs from.
859 struct render_sub_alloc_tracker ubo_tracker;
860
861 //! The current target we are rendering to, can change during command building.
862 struct render_gfx_target_resources *rtr;
863};
864
865/*!
866 * Init struct and create resources needed for rendering.
867 *
868 * @public @memberof render_gfx
869 */
870bool
871render_gfx_init(struct render_gfx *render, struct render_resources *r);
872
873/*!
874 * Begins the rendering, takes the vk_bundle's pool lock and leaves it locked.
875 *
876 * @public @memberof render_gfx
877 */
878bool
879render_gfx_begin(struct render_gfx *render);
880
881/*!
882 * Frees any unneeded resources and ends the command buffer so it can be used,
883 * also unlocks the vk_bundle's pool lock that was taken by begin.
884 *
885 * @public @memberof render_gfx
886 */
887bool
888render_gfx_end(struct render_gfx *render);
889
890/*!
891 * Frees all resources held by the rendering, does not free the struct itself.
892 *
893 * @public @memberof render_gfx
894 */
895void
896render_gfx_fini(struct render_gfx *render);
897
898
899/*
900 *
901 * Drawing
902 *
903 */
904
905/*!
906 * UBO data that is sent to the mesh shaders.
907 *
908 * @relates render_gfx
909 */
910struct render_gfx_mesh_ubo_data
911{
912 struct xrt_matrix_2x2 vertex_rot;
913 struct xrt_normalized_rect post_transform;
914
915 // Only used for timewarp.
916 struct xrt_normalized_rect pre_transform;
917 struct xrt_matrix_4x4 transform;
918};
919
920/*!
921 * UBO data that is sent to the layer cylinder shader.
922 *
923 * @relates render_gfx
924 */
925struct render_gfx_layer_cylinder_data
926{
927 struct xrt_normalized_rect post_transform;
928 struct xrt_matrix_4x4 mvp;
929 float radius;
930 float central_angle;
931 float aspect_ratio;
932 float _pad;
933};
934
935/*!
936 * UBO data that is sent to the layer equirect2 shader.
937 *
938 * @relates render_gfx
939 */
940struct render_gfx_layer_equirect2_data
941{
942 struct xrt_normalized_rect post_transform;
943 struct xrt_matrix_4x4 mv_inverse;
944
945 //! See @ref render_calc_uv_to_tangent_lengths_rect.
946 struct xrt_normalized_rect to_tangent;
947
948 float radius;
949 float central_horizontal_angle;
950 float upper_vertical_angle;
951 float lower_vertical_angle;
952};
953
954/*!
955 * UBO data that is sent to the layer projection shader.
956 *
957 * @relates render_gfx
958 */
959struct render_gfx_layer_projection_data
960{
961 struct xrt_normalized_rect post_transform;
962 struct xrt_normalized_rect to_tanget;
963 struct xrt_matrix_4x4 mvp;
964};
965
966/*!
967 * UBO data that is sent to the layer quad shader.
968 *
969 * @relates render_gfx
970 */
971struct render_gfx_layer_quad_data
972{
973 struct xrt_normalized_rect post_transform;
974 struct xrt_matrix_4x4 mvp;
975};
976
977/*!
978 * @name Preparation functions - first stage
979 * @{
980 */
981
982/*!
983 * Allocate needed resources for one mesh shader dispatch, will also update the
984 * descriptor set, UBO will be filled out with the given @p data argument.
985 *
986 * Uses the @ref render_sub_alloc_tracker of the @ref render_gfx and the
987 * descriptor pool of @ref render_resources, both of which will be reset once
988 * closed, so don't save any reference to these objects beyond the frame.
989 *
990 * @public @memberof render_gfx
991 */
992XRT_CHECK_RESULT VkResult
993render_gfx_mesh_alloc_and_write(struct render_gfx *render,
994 const struct render_gfx_mesh_ubo_data *data,
995 VkSampler src_sampler,
996 VkImageView src_image_view,
997 VkDescriptorSet *out_descriptor_set);
998
999/*!
1000 * Allocate and write a UBO and descriptor_set to be used for cylinder layer
1001 * rendering, the content of @p data need to be valid at the time of the call.
1002 *
1003 * @public @memberof render_gfx
1004 */
1005XRT_CHECK_RESULT VkResult
1006render_gfx_layer_cylinder_alloc_and_write(struct render_gfx *render,
1007 const struct render_gfx_layer_cylinder_data *data,
1008 VkSampler src_sampler,
1009 VkImageView src_image_view,
1010 VkDescriptorSet *out_descriptor_set);
1011
1012/*!
1013 * Allocate and write a UBO and descriptor_set to be used for equirect2 layer
1014 * rendering, the content of @p data need to be valid at the time of the call.
1015 *
1016 * @public @memberof render_gfx
1017 */
1018XRT_CHECK_RESULT VkResult
1019render_gfx_layer_equirect2_alloc_and_write(struct render_gfx *render,
1020 const struct render_gfx_layer_equirect2_data *data,
1021 VkSampler src_sampler,
1022 VkImageView src_image_view,
1023 VkDescriptorSet *out_descriptor_set);
1024
1025/*!
1026 * Allocate and write a UBO and descriptor_set to be used for projection layer
1027 * rendering, the content of @p data need to be valid at the time of the call.
1028 *
1029 * @public @memberof render_gfx
1030 */
1031XRT_CHECK_RESULT VkResult
1032render_gfx_layer_projection_alloc_and_write(struct render_gfx *render,
1033 const struct render_gfx_layer_projection_data *data,
1034 VkSampler src_sampler,
1035 VkImageView src_image_view,
1036 VkDescriptorSet *out_descriptor_set);
1037
1038/*!
1039 * Allocate and write a UBO and descriptor_set to be used for quad layer
1040 * rendering, the content of @p data need to be valid at the time of the call.
1041 *
1042 * @public @memberof render_gfx
1043 */
1044XRT_CHECK_RESULT VkResult
1045render_gfx_layer_quad_alloc_and_write(struct render_gfx *render,
1046 const struct render_gfx_layer_quad_data *data,
1047 VkSampler src_sampler,
1048 VkImageView src_image_view,
1049 VkDescriptorSet *out_descriptor_set);
1050
1051
1052/*!
1053 * @}
1054 */
1055
1056/*!
1057 * @name Drawing functions - second stage
1058 * @{
1059 */
1060
1061/*!
1062 * This function allocates everything to start a single rendering. This is the
1063 * first function you call when you start the drawiing stage, you follow up with a call
1064 * to @ref render_gfx_begin_view.
1065 *
1066 * @public @memberof render_gfx
1067 */
1068bool
1069render_gfx_begin_target(struct render_gfx *render,
1070 struct render_gfx_target_resources *rtr,
1071 const VkClearColorValue *color);
1072
1073/*!
1074 * @pre successful @ref render_gfx_begin_target call,
1075 * no @ref render_gfx_begin_view without matching @ref render_gfx_end_view
1076 * @public @memberof render_gfx
1077 */
1078void
1079render_gfx_end_target(struct render_gfx *render);
1080
1081/*!
1082 * @pre successful @ref render_gfx_begin_target call
1083 * @public @memberof render_gfx
1084 */
1085void
1086render_gfx_begin_view(struct render_gfx *render, uint32_t view, const struct render_viewport_data *viewport_data);
1087
1088/*!
1089 * @pre successful @ref render_gfx_begin_view call without a matching call to this function
1090 * @public @memberof render_gfx
1091 */
1092void
1093render_gfx_end_view(struct render_gfx *render);
1094
1095/*!
1096 * Dispatch one mesh shader instance, using the give @p mesh_index as source for
1097 * mesh geometry, timewarp selectable via @p do_timewarp.
1098 *
1099 * Must have successfully called @ref render_gfx_mesh_alloc_and_write
1100 * before @ref render_gfx_begin_target to allocate @p descriptor_set and UBO.
1101 *
1102 * @pre successful @ref render_gfx_mesh_alloc_and_write call, successful @ref render_gfx_begin_view call
1103 * @public @memberof render_gfx
1104 */
1105void
1106render_gfx_mesh_draw(struct render_gfx *render, uint32_t mesh_index, VkDescriptorSet descriptor_set, bool do_timewarp);
1107
1108/*!
1109 * Dispatch a cylinder layer shader into the current target and view.
1110 *
1111 * Must have successfully called @ref render_gfx_layer_cylinder_alloc_and_write
1112 * before @ref render_gfx_begin_target to allocate @p descriptor_set and UBO.
1113 *
1114 * @public @memberof render_gfx
1115 */
1116void
1117render_gfx_layer_cylinder(struct render_gfx *render, bool premultiplied_alpha, VkDescriptorSet descriptor_set);
1118
1119/*!
1120 * Dispatch a equirect2 layer shader into the current target and view.
1121 *
1122 * Must have successfully called @ref render_gfx_layer_equirect2_alloc_and_write
1123 * before @ref render_gfx_begin_target to allocate @p descriptor_set and UBO.
1124 *
1125 * @public @memberof render_gfx
1126 */
1127void
1128render_gfx_layer_equirect2(struct render_gfx *render, bool premultiplied_alpha, VkDescriptorSet descriptor_set);
1129
1130/*!
1131 * Dispatch a projection layer shader into the current target and view.
1132 *
1133 * Must have successfully called @ref render_gfx_layer_projection_alloc_and_write
1134 * before @ref render_gfx_begin_target to allocate @p descriptor_set and UBO.
1135 *
1136 * @public @memberof render_gfx
1137 */
1138void
1139render_gfx_layer_projection(struct render_gfx *render, bool premultiplied_alpha, VkDescriptorSet descriptor_set);
1140
1141/*!
1142 * Dispatch a quad layer shader into the current target and view.
1143 *
1144 * Must have successfully called @ref render_gfx_layer_quad_alloc_and_write
1145 * before @ref render_gfx_begin_target to allocate @p descriptor_set and UBO.
1146 *
1147 * @public @memberof render_gfx
1148 */
1149void
1150render_gfx_layer_quad(struct render_gfx *render, bool premultiplied_alpha, VkDescriptorSet descriptor_set);
1151
1152/*!
1153 * @}
1154 */
1155
1156
1157/*
1158 *
1159 * Compute distortion.
1160 *
1161 */
1162
1163/*!
1164 * The semi-low level resources and operations required to squash layers and/or
1165 * apply distortion for a single frame using compute shaders.
1166 *
1167 * Unlike @ref render_gfx, this is a single stage process, and you pass all layers at a single time.
1168 *
1169 * @see comp_render_cs
1170 */
1171struct render_compute
1172{
1173 //! Shared resources.
1174 struct render_resources *r;
1175
1176 //! Layer descriptor set.
1177 VkDescriptorSet layer_descriptor_sets[RENDER_MAX_LAYER_RUNS_SIZE];
1178
1179 /*!
1180 * Shared descriptor set, used for the clear and distortion shaders. It
1181 * is used in the functions @ref render_compute_projection_timewarp,
1182 * @ref render_compute_projection, and @ref render_compute_clear.
1183 */
1184 VkDescriptorSet shared_descriptor_set;
1185};
1186
1187/*!
1188 * Push data that is sent to the blit shader.
1189 *
1190 * @relates render_compute
1191 */
1192struct render_compute_blit_push_data
1193{
1194 struct xrt_normalized_rect source_rect;
1195 struct xrt_rect target_rect;
1196};
1197
1198/*!
1199 * UBO data that is sent to the compute layer shaders.
1200 *
1201 * @relates render_compute
1202 */
1203struct render_compute_layer_ubo_data
1204{
1205 struct render_viewport_data view;
1206
1207 struct
1208 {
1209 uint32_t value;
1210 uint32_t padding[3];
1211 } layer_count;
1212
1213 struct xrt_normalized_rect pre_transform;
1214 struct xrt_normalized_rect post_transforms[RENDER_MAX_LAYERS];
1215
1216 //! std140 uvec2, corresponds to enum xrt_layer_type and unpremultiplied alpha.
1217 struct
1218 {
1219 uint32_t val;
1220 uint32_t unpremultiplied;
1221 uint32_t padding[XRT_MAX_VIEWS];
1222 } layer_type[RENDER_MAX_LAYERS];
1223
1224 //! Which image/sampler(s) correspond to each layer.
1225 struct
1226 {
1227 uint32_t images[XRT_MAX_VIEWS];
1228 //! @todo Implement separated samplers and images (and change to samplers[2])
1229 uint32_t padding[XRT_MAX_VIEWS];
1230 } images_samplers[RENDER_MAX_LAYERS];
1231
1232 //! Shared between cylinder and equirect2.
1233 struct xrt_matrix_4x4 mv_inverse[RENDER_MAX_LAYERS];
1234
1235
1236 /*!
1237 * For cylinder layer
1238 */
1239 struct
1240 {
1241 float radius;
1242 float central_angle;
1243 float aspect_ratio;
1244 float padding;
1245 } cylinder_data[RENDER_MAX_LAYERS];
1246
1247
1248 /*!
1249 * For equirect2 layers
1250 */
1251 struct
1252 {
1253 float radius;
1254 float central_horizontal_angle;
1255 float upper_vertical_angle;
1256 float lower_vertical_angle;
1257 } eq2_data[RENDER_MAX_LAYERS];
1258
1259
1260 /*!
1261 * For projection layers
1262 */
1263
1264 //! Timewarp matrices
1265 struct xrt_matrix_4x4 transforms_timewarp[RENDER_MAX_LAYERS];
1266
1267 /*!
1268 * For quad layers
1269 */
1270
1271 //! All quad transforms and coordinates are in view space
1272 struct
1273 {
1274 struct xrt_vec3 val;
1275 float padding;
1276 } quad_position[RENDER_MAX_LAYERS];
1277 struct
1278 {
1279 struct xrt_vec3 val;
1280 float padding;
1281 } quad_normal[RENDER_MAX_LAYERS];
1282 struct xrt_matrix_4x4 inverse_quad_transform[RENDER_MAX_LAYERS];
1283
1284 //! Quad extent in world scale
1285 struct
1286 {
1287 struct xrt_vec2 val;
1288 float padding[XRT_MAX_VIEWS];
1289 } quad_extent[RENDER_MAX_LAYERS];
1290};
1291
1292/*!
1293 * UBO data that is sent to the compute distortion shaders.
1294 *
1295 * @relates render_compute
1296 */
1297struct render_compute_distortion_ubo_data
1298{
1299 struct render_viewport_data views[XRT_MAX_VIEWS];
1300 struct xrt_normalized_rect pre_transforms[XRT_MAX_VIEWS];
1301 struct xrt_normalized_rect post_transforms[XRT_MAX_VIEWS];
1302 struct xrt_matrix_4x4 transform_timewarp_scanout_begin[XRT_MAX_VIEWS];
1303 struct xrt_matrix_4x4 transform_timewarp_scanout_end[XRT_MAX_VIEWS];
1304};
1305
1306/*!
1307 * Init struct and create resources needed for compute rendering.
1308 *
1309 * @public @memberof render_compute
1310 */
1311bool
1312render_compute_init(struct render_compute *render, struct render_resources *r);
1313
1314/*!
1315 * Frees all resources held by the compute rendering, does not free the struct itself.
1316 *
1317 * @public @memberof render_compute
1318 */
1319void
1320render_compute_fini(struct render_compute *render);
1321
1322/*!
1323 * Begin the compute command buffer building, takes the vk_bundle's pool lock
1324 * and leaves it locked.
1325 *
1326 * @public @memberof render_compute
1327 */
1328bool
1329render_compute_begin(struct render_compute *render);
1330
1331/*!
1332 * Frees any unneeded resources and ends the command buffer so it can be used,
1333 * also unlocks the vk_bundle's pool lock that was taken by begin.
1334 *
1335 * @public @memberof render_compute
1336 */
1337bool
1338render_compute_end(struct render_compute *render);
1339
1340/*!
1341 * Updates the given @p descriptor_set and dispatches the layer shader. Unlike
1342 * other dispatch functions below this function doesn't do any layer barriers
1343 * before or after dispatching, this is to allow the callee to batch any such
1344 * image transitions.
1345 *
1346 * Expected layouts:
1347 * * Source images: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
1348 * * Target image: VK_IMAGE_LAYOUT_GENERAL
1349 *
1350 * @public @memberof render_compute
1351 */
1352void
1353render_compute_layers(struct render_compute *render,
1354 VkDescriptorSet descriptor_set,
1355 VkBuffer ubo,
1356 VkSampler src_samplers[RENDER_MAX_IMAGES_SIZE],
1357 VkImageView src_image_views[RENDER_MAX_IMAGES_SIZE],
1358 uint32_t num_srcs,
1359 VkImageView target_image_view,
1360 const struct render_viewport_data *view,
1361 bool timewarp);
1362
1363/*!
1364 * @public @memberof render_compute
1365 */
1366void
1367render_compute_projection_timewarp(struct render_compute *render,
1368 VkSampler src_samplers[XRT_MAX_VIEWS],
1369 VkImageView src_image_views[XRT_MAX_VIEWS],
1370 const struct xrt_normalized_rect src_rects[XRT_MAX_VIEWS],
1371 const struct xrt_pose src_poses[XRT_MAX_VIEWS],
1372 const struct xrt_fov src_fovs[XRT_MAX_VIEWS],
1373 const struct xrt_pose new_poses_scanout_begin[XRT_MAX_VIEWS],
1374 const struct xrt_pose new_poses_scanout_end[XRT_MAX_VIEWS],
1375 VkImage target_image,
1376 VkImageView target_image_view,
1377 const struct render_viewport_data views[XRT_MAX_VIEWS]);
1378
1379/*!
1380 * @public @memberof render_compute
1381 */
1382void
1383render_compute_projection_scanout_compensation(struct render_compute *render,
1384 VkSampler src_samplers[XRT_MAX_VIEWS],
1385 VkImageView src_image_views[XRT_MAX_VIEWS],
1386 const struct xrt_normalized_rect src_rects[XRT_MAX_VIEWS],
1387 const struct xrt_fov src_fovs[XRT_MAX_VIEWS],
1388 const struct xrt_pose new_poses_scanout_begin[XRT_MAX_VIEWS],
1389 const struct xrt_pose new_poses_scanout_end[XRT_MAX_VIEWS],
1390 VkImage target_image,
1391 VkImageView target_image_view,
1392 const struct render_viewport_data views[XRT_MAX_VIEWS]);
1393
1394/*!
1395 * @public @memberof render_compute
1396 */
1397void
1398render_compute_projection_no_timewarp(struct render_compute *render,
1399 VkSampler src_samplers[XRT_MAX_VIEWS],
1400 VkImageView src_image_views[XRT_MAX_VIEWS],
1401 const struct xrt_normalized_rect src_rects[XRT_MAX_VIEWS],
1402 VkImage target_image,
1403 VkImageView target_image_view,
1404 const struct render_viewport_data views[XRT_MAX_VIEWS]);
1405
1406/*!
1407 * @public @memberof render_compute
1408 */
1409void
1410render_compute_clear(struct render_compute *render,
1411 VkImage target_image,
1412 VkImageView target_image_view,
1413 const struct render_viewport_data views[XRT_MAX_VIEWS]);
1414
1415
1416
1417/*!
1418 * @}
1419 */
1420
1421
1422#ifdef __cplusplus
1423}
1424#endif