The open source OpenXR runtime
1// Copyright 2019-2023, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief The compositor compute based rendering code.
6 * @author Jakob Bornecrantz <jakob@collabora.com>
7 * @ingroup comp_render
8 */
9
10#include "math/m_api.h"
11#include "math/m_matrix_4x4_f64.h"
12
13#include "vk/vk_mini_helpers.h"
14
15#include "render/render_interface.h"
16
17
18/*
19 *
20 * Helper functions.
21 *
22 */
23
24/*!
25 * Get the @ref vk_bundle from @ref render_compute.
26 */
27static inline struct vk_bundle *
28vk_from_render(struct render_compute *render)
29{
30 return render->r->vk;
31}
32
33static uint32_t
34uint_divide_and_round_up(uint32_t a, uint32_t b)
35{
36 return (a + (b - 1)) / b;
37}
38
39static void
40calc_dispatch_dims_1_view(const struct render_viewport_data views, uint32_t *out_w, uint32_t *out_h)
41{
42 // Power of two divide and round up.
43 uint32_t w = uint_divide_and_round_up(views.w, 8);
44 uint32_t h = uint_divide_and_round_up(views.h, 8);
45
46 *out_w = w;
47 *out_h = h;
48}
49
50/*
51 * For dispatching compute to the view, calculate the number of groups.
52 */
53static void
54calc_dispatch_dims_views(const struct render_viewport_data views[XRT_MAX_VIEWS],
55 uint32_t view_count,
56 uint32_t *out_w,
57 uint32_t *out_h)
58{
59#define IMAX(a, b) ((a) > (b) ? (a) : (b))
60 uint32_t w = 0;
61 uint32_t h = 0;
62 for (uint32_t i = 0; i < view_count; ++i) {
63 w = IMAX(w, views[i].w);
64 h = IMAX(h, views[i].h);
65 }
66#undef IMAX
67
68 // Power of two divide and round up.
69 w = uint_divide_and_round_up(w, 8);
70 h = uint_divide_and_round_up(h, 8);
71
72 *out_w = w;
73 *out_h = h;
74}
75
76
77/*
78 *
79 * Vulkan helpers.
80 *
81 */
82
83XRT_MAYBE_UNUSED static void
84update_compute_layer_descriptor_set(struct vk_bundle *vk,
85 uint32_t src_binding,
86 VkSampler src_samplers[RENDER_MAX_IMAGES_SIZE],
87 VkImageView src_image_views[RENDER_MAX_IMAGES_SIZE],
88 uint32_t image_count,
89 uint32_t target_binding,
90 VkImageView target_image_view,
91 uint32_t ubo_binding,
92 VkBuffer ubo_buffer,
93 VkDeviceSize ubo_size,
94 VkDescriptorSet descriptor_set)
95{
96 VkDescriptorImageInfo src_image_info[RENDER_MAX_IMAGES_SIZE];
97 for (uint32_t i = 0; i < image_count; i++) {
98 src_image_info[i].sampler = src_samplers[i];
99 src_image_info[i].imageView = src_image_views[i];
100 src_image_info[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
101 }
102
103 VkDescriptorImageInfo target_image_info = {
104 .imageView = target_image_view,
105 .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
106 };
107
108 VkDescriptorBufferInfo buffer_info = {
109 .buffer = ubo_buffer,
110 .offset = 0,
111 .range = ubo_size,
112 };
113
114 VkWriteDescriptorSet write_descriptor_sets[3] = {
115 {
116 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
117 .dstSet = descriptor_set,
118 .dstBinding = src_binding,
119 .descriptorCount = image_count,
120 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
121 .pImageInfo = src_image_info,
122 },
123 {
124 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
125 .dstSet = descriptor_set,
126 .dstBinding = target_binding,
127 .descriptorCount = 1,
128 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
129 .pImageInfo = &target_image_info,
130 },
131 {
132 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
133 .dstSet = descriptor_set,
134 .dstBinding = ubo_binding,
135 .descriptorCount = 1,
136 .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
137 .pBufferInfo = &buffer_info,
138 },
139 };
140
141 vk->vkUpdateDescriptorSets( //
142 vk->device, //
143 ARRAY_SIZE(write_descriptor_sets), // descriptorWriteCount
144 write_descriptor_sets, // pDescriptorWrites
145 0, // descriptorCopyCount
146 NULL); // pDescriptorCopies
147}
148
149XRT_MAYBE_UNUSED static void
150update_compute_shared_descriptor_set(struct vk_bundle *vk,
151 uint32_t src_binding,
152 VkSampler src_samplers[XRT_MAX_VIEWS],
153 VkImageView src_image_views[XRT_MAX_VIEWS],
154 uint32_t distortion_binding,
155 VkSampler distortion_samplers[3 * XRT_MAX_VIEWS],
156 VkImageView distortion_image_views[3 * XRT_MAX_VIEWS],
157 uint32_t target_binding,
158 VkImageView target_image_view,
159 uint32_t ubo_binding,
160 VkBuffer ubo_buffer,
161 VkDeviceSize ubo_size,
162 VkDescriptorSet descriptor_set,
163 uint32_t view_count)
164{
165 VkDescriptorImageInfo src_image_info[XRT_MAX_VIEWS];
166 for (uint32_t i = 0; i < view_count; ++i) {
167 src_image_info[i].sampler = src_samplers[i];
168 src_image_info[i].imageView = src_image_views[i];
169 src_image_info[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
170 }
171
172 VkDescriptorImageInfo distortion_image_info[3 * XRT_MAX_VIEWS];
173 for (uint32_t i = 0; i < 3 * view_count; ++i) {
174 distortion_image_info[i].sampler = distortion_samplers[i];
175 distortion_image_info[i].imageView = distortion_image_views[i];
176 distortion_image_info[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
177 }
178
179 VkDescriptorImageInfo target_image_info = {
180 .imageView = target_image_view,
181 .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
182 };
183
184 VkDescriptorBufferInfo buffer_info = {
185 .buffer = ubo_buffer,
186 .offset = 0,
187 .range = ubo_size,
188 };
189
190 VkWriteDescriptorSet write_descriptor_sets[4] = {
191 {
192 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
193 .dstSet = descriptor_set,
194 .dstBinding = src_binding,
195 .descriptorCount = view_count,
196 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
197 .pImageInfo = src_image_info,
198 },
199 {
200 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
201 .dstSet = descriptor_set,
202 .dstBinding = distortion_binding,
203 .descriptorCount = 3 * view_count,
204 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
205 .pImageInfo = distortion_image_info,
206 },
207 {
208 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
209 .dstSet = descriptor_set,
210 .dstBinding = target_binding,
211 .descriptorCount = 1,
212 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
213 .pImageInfo = &target_image_info,
214 },
215 {
216 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
217 .dstSet = descriptor_set,
218 .dstBinding = ubo_binding,
219 .descriptorCount = 1,
220 .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
221 .pBufferInfo = &buffer_info,
222 },
223 };
224
225 vk->vkUpdateDescriptorSets( //
226 vk->device, //
227 ARRAY_SIZE(write_descriptor_sets), // descriptorWriteCount
228 write_descriptor_sets, // pDescriptorWrites
229 0, // descriptorCopyCount
230 NULL); // pDescriptorCopies
231}
232
233XRT_MAYBE_UNUSED static void
234update_compute_descriptor_set_target(struct vk_bundle *vk,
235 uint32_t target_binding,
236 VkImageView target_image_view,
237 uint32_t ubo_binding,
238 VkBuffer ubo_buffer,
239 VkDeviceSize ubo_size,
240 VkDescriptorSet descriptor_set,
241 uint32_t view_count)
242{
243 VkDescriptorImageInfo target_image_info = {
244 .imageView = target_image_view,
245 .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
246 };
247
248 VkDescriptorBufferInfo buffer_info = {
249 .buffer = ubo_buffer,
250 .offset = 0,
251 .range = ubo_size,
252 };
253
254 VkWriteDescriptorSet write_descriptor_sets[2] = {
255 {
256 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
257 .dstSet = descriptor_set,
258 .dstBinding = target_binding,
259 .descriptorCount = 1,
260 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
261 .pImageInfo = &target_image_info,
262 },
263 {
264 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
265 .dstSet = descriptor_set,
266 .dstBinding = ubo_binding,
267 .descriptorCount = 1,
268 .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
269 .pBufferInfo = &buffer_info,
270 },
271 };
272
273 vk->vkUpdateDescriptorSets( //
274 vk->device, //
275 ARRAY_SIZE(write_descriptor_sets), // descriptorWriteCount
276 write_descriptor_sets, // pDescriptorWrites
277 0, // descriptorCopyCount
278 NULL); // pDescriptorCopies
279}
280
281static void
282dispatch_project_pipeline(struct render_compute *render,
283 VkSampler src_samplers[XRT_MAX_VIEWS],
284 VkImageView src_image_views[XRT_MAX_VIEWS],
285 const struct xrt_normalized_rect src_norm_rects[XRT_MAX_VIEWS],
286 VkImage target_image,
287 VkImageView target_image_view,
288 const struct render_viewport_data views[XRT_MAX_VIEWS],
289 VkPipeline pipeline)
290{
291 struct vk_bundle *vk = vk_from_render(render);
292 struct render_resources *r = render->r;
293
294
295 /*
296 * UBO
297 */
298
299 struct render_compute_distortion_ubo_data *data =
300 (struct render_compute_distortion_ubo_data *)r->compute.distortion.ubo.mapped;
301 for (uint32_t i = 0; i < render->r->view_count; ++i) {
302 data->views[i] = views[i];
303 data->post_transforms[i] = src_norm_rects[i];
304 }
305
306
307 /*
308 * Source, target and distortion images.
309 */
310
311 VkImageSubresourceRange subresource_range = {
312 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
313 .baseMipLevel = 0,
314 .levelCount = VK_REMAINING_MIP_LEVELS,
315 .baseArrayLayer = 0,
316 .layerCount = VK_REMAINING_ARRAY_LAYERS,
317 };
318
319 vk_cmd_image_barrier_gpu_locked( //
320 vk, //
321 r->cmd, //
322 target_image, //
323 0, //
324 VK_ACCESS_SHADER_WRITE_BIT, //
325 VK_IMAGE_LAYOUT_UNDEFINED, //
326 VK_IMAGE_LAYOUT_GENERAL, //
327 subresource_range); //
328
329 VkSampler sampler = r->samplers.clamp_to_edge;
330 VkSampler distortion_samplers[3 * XRT_MAX_VIEWS];
331 for (uint32_t i = 0; i < render->r->view_count; ++i) {
332 distortion_samplers[3 * i + 0] = sampler;
333 distortion_samplers[3 * i + 1] = sampler;
334 distortion_samplers[3 * i + 2] = sampler;
335 }
336
337 update_compute_shared_descriptor_set( //
338 vk, //
339 r->compute.src_binding, //
340 src_samplers, //
341 src_image_views, //
342 r->compute.distortion_binding, //
343 distortion_samplers, //
344 r->distortion.image_views, //
345 r->compute.target_binding, //
346 target_image_view, //
347 r->compute.ubo_binding, //
348 r->compute.distortion.ubo.buffer, //
349 VK_WHOLE_SIZE, //
350 render->shared_descriptor_set, //
351 render->r->view_count); //
352
353 vk->vkCmdBindPipeline( //
354 r->cmd, //
355 VK_PIPELINE_BIND_POINT_COMPUTE, // pipelineBindPoint
356 pipeline); // pipeline
357
358 vk->vkCmdBindDescriptorSets( //
359 r->cmd, //
360 VK_PIPELINE_BIND_POINT_COMPUTE, // pipelineBindPoint
361 r->compute.distortion.pipeline_layout, // layout
362 0, // firstSet
363 1, // descriptorSetCount
364 &render->shared_descriptor_set, // pDescriptorSets
365 0, // dynamicOffsetCount
366 NULL); // pDynamicOffsets
367
368
369 uint32_t w = 0, h = 0;
370 calc_dispatch_dims_views(views, render->r->view_count, &w, &h);
371 assert(w != 0 && h != 0);
372
373 vk->vkCmdDispatch( //
374 r->cmd, //
375 w, // groupCountX
376 h, // groupCountY
377 2); // groupCountZ
378
379 VkImageMemoryBarrier memoryBarrier = {
380 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
381 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
382 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
383 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
384 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
385 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
386 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
387 .image = target_image,
388 .subresourceRange = subresource_range,
389 };
390
391 vk->vkCmdPipelineBarrier( //
392 r->cmd, //
393 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, //
394 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, //
395 0, //
396 0, //
397 NULL, //
398 0, //
399 NULL, //
400 1, //
401 &memoryBarrier); //
402}
403
404
405/*
406 *
407 * 'Exported' functions.
408 *
409 */
410
411bool
412render_compute_init(struct render_compute *render, struct render_resources *r)
413{
414 VkResult ret;
415
416 assert(render->r == NULL);
417
418 struct vk_bundle *vk = r->vk;
419 render->r = r;
420
421 for (uint32_t i = 0; i < RENDER_MAX_LAYER_RUNS_COUNT(r); i++) {
422 ret = vk_create_descriptor_set( //
423 vk, // vk_bundle
424 r->compute.descriptor_pool, // descriptor_pool
425 r->compute.layer.descriptor_set_layout, // descriptor_set_layout
426 &render->layer_descriptor_sets[i]); // descriptor_set
427 VK_CHK_WITH_RET(ret, "vk_create_descriptor_set", false);
428
429 VK_NAME_DESCRIPTOR_SET(vk, render->layer_descriptor_sets[i], "render_compute layer descriptor set");
430 }
431
432 ret = vk_create_descriptor_set( //
433 vk, // vk_bundle
434 r->compute.descriptor_pool, // descriptor_pool
435 r->compute.distortion.descriptor_set_layout, // descriptor_set_layout
436 &render->shared_descriptor_set); // descriptor_set
437 VK_CHK_WITH_RET(ret, "vk_create_descriptor_set", false);
438
439 VK_NAME_DESCRIPTOR_SET(vk, render->shared_descriptor_set, "render_compute shared descriptor set");
440
441 return true;
442}
443
444bool
445render_compute_begin(struct render_compute *render)
446{
447 VkResult ret;
448 struct vk_bundle *vk = vk_from_render(render);
449
450 ret = vk->vkResetCommandPool(vk->device, render->r->cmd_pool, 0);
451 VK_CHK_WITH_RET(ret, "vkResetCommandPool", false);
452
453 VkCommandBufferBeginInfo begin_info = {
454 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
455 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
456 };
457
458 ret = vk->vkBeginCommandBuffer( //
459 render->r->cmd, //
460 &begin_info); //
461 VK_CHK_WITH_RET(ret, "vkBeginCommandBuffer", false);
462
463 vk->vkCmdResetQueryPool( //
464 render->r->cmd, //
465 render->r->query_pool, //
466 0, // firstQuery
467 2); // queryCount
468
469 vk->vkCmdWriteTimestamp( //
470 render->r->cmd, //
471 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // pipelineStage
472 render->r->query_pool, //
473 0); // query
474
475 return true;
476}
477
478bool
479render_compute_end(struct render_compute *render)
480{
481 struct vk_bundle *vk = vk_from_render(render);
482 VkResult ret;
483
484 vk->vkCmdWriteTimestamp( //
485 render->r->cmd, //
486 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, // pipelineStage
487 render->r->query_pool, //
488 1); // query
489
490 ret = vk->vkEndCommandBuffer(render->r->cmd);
491 VK_CHK_WITH_RET(ret, "vkEndCommandBuffer", false);
492
493 return true;
494}
495
496void
497render_compute_fini(struct render_compute *render)
498{
499 assert(render->r != NULL);
500
501 struct vk_bundle *vk = vk_from_render(render);
502
503 // Reclaimed by vkResetDescriptorPool.
504 render->shared_descriptor_set = VK_NULL_HANDLE;
505 for (uint32_t i = 0; i < ARRAY_SIZE(render->layer_descriptor_sets); i++) {
506 render->layer_descriptor_sets[i] = VK_NULL_HANDLE;
507 }
508
509 vk->vkResetDescriptorPool(vk->device, render->r->compute.descriptor_pool, 0);
510
511 render->r = NULL;
512}
513
514void
515render_compute_layers(struct render_compute *render,
516 VkDescriptorSet descriptor_set,
517 VkBuffer ubo,
518 VkSampler src_samplers[RENDER_MAX_IMAGES_SIZE],
519 VkImageView src_image_views[RENDER_MAX_IMAGES_SIZE],
520 uint32_t num_srcs,
521 VkImageView target_image_view,
522 const struct render_viewport_data *view,
523 bool do_timewarp)
524{
525 assert(render->r != NULL);
526
527 struct vk_bundle *vk = vk_from_render(render);
528 struct render_resources *r = render->r;
529
530
531 /*
532 * Source, target and distortion images.
533 */
534
535 update_compute_layer_descriptor_set( //
536 vk, //
537 r->compute.src_binding, //
538 src_samplers, //
539 src_image_views, //
540 num_srcs, //
541 r->compute.target_binding, //
542 target_image_view, //
543 r->compute.ubo_binding, //
544 ubo, //
545 VK_WHOLE_SIZE, //
546 descriptor_set); //
547
548 VkPipeline pipeline = do_timewarp ? r->compute.layer.timewarp_pipeline : r->compute.layer.non_timewarp_pipeline;
549 vk->vkCmdBindPipeline( //
550 render->r->cmd, //
551 VK_PIPELINE_BIND_POINT_COMPUTE, // pipelineBindPoint
552 pipeline); // pipeline
553
554 vk->vkCmdBindDescriptorSets( //
555 r->cmd, //
556 VK_PIPELINE_BIND_POINT_COMPUTE, // pipelineBindPoint
557 r->compute.layer.pipeline_layout, // layout
558 0, // firstSet
559 1, // descriptorSetCount
560 &descriptor_set, // pDescriptorSets
561 0, // dynamicOffsetCount
562 NULL); // pDynamicOffsets
563
564
565 uint32_t w = 0, h = 0;
566 calc_dispatch_dims_1_view(*view, &w, &h);
567 assert(w != 0 && h != 0);
568
569 vk->vkCmdDispatch( //
570 r->cmd, //
571 w, // groupCountX
572 h, // groupCountY
573 1); // groupCountZ
574}
575
576void
577render_compute_projection_timewarp(struct render_compute *render,
578 VkSampler src_samplers[XRT_MAX_VIEWS],
579 VkImageView src_image_views[XRT_MAX_VIEWS],
580 const struct xrt_normalized_rect src_norm_rects[XRT_MAX_VIEWS],
581 const struct xrt_pose src_poses[XRT_MAX_VIEWS],
582 const struct xrt_fov src_fovs[XRT_MAX_VIEWS],
583 const struct xrt_pose new_poses_scanout_begin[XRT_MAX_VIEWS],
584 const struct xrt_pose new_poses_scanout_end[XRT_MAX_VIEWS],
585 VkImage target_image,
586 VkImageView target_image_view,
587 const struct render_viewport_data views[XRT_MAX_VIEWS])
588{
589 assert(render->r != NULL);
590 struct render_resources *r = render->r;
591
592
593 /*
594 * UBO
595 */
596
597 struct xrt_matrix_4x4 time_warp_matrix_scanout_begin[XRT_MAX_VIEWS];
598 struct xrt_matrix_4x4 time_warp_matrix_scanout_end[XRT_MAX_VIEWS];
599 for (uint32_t i = 0; i < render->r->view_count; ++i) {
600 render_calc_time_warp_matrix( //
601 &src_poses[i], //
602 &src_fovs[i], //
603 &new_poses_scanout_begin[i], //
604 &time_warp_matrix_scanout_begin[i]); //
605
606 render_calc_time_warp_matrix( //
607 &src_poses[i], //
608 &src_fovs[i], //
609 &new_poses_scanout_end[i], //
610 &time_warp_matrix_scanout_end[i]); //
611 }
612
613 struct render_compute_distortion_ubo_data *data =
614 (struct render_compute_distortion_ubo_data *)r->compute.distortion.ubo.mapped;
615 for (uint32_t i = 0; i < render->r->view_count; ++i) {
616 data->views[i] = views[i];
617 data->pre_transforms[i] = r->distortion.uv_to_tanangle[i];
618 data->transform_timewarp_scanout_begin[i] = time_warp_matrix_scanout_begin[i];
619 data->transform_timewarp_scanout_end[i] = time_warp_matrix_scanout_end[i];
620 data->post_transforms[i] = src_norm_rects[i];
621 }
622
623 dispatch_project_pipeline(render, src_samplers, src_image_views, src_norm_rects, target_image,
624 target_image_view, views, r->compute.distortion.timewarp_pipeline);
625}
626
627
628/*
629 * This function is intended to be used on content already timewarped to new_poses_scanout_begin.
630 * It performs only the timewarp nesscary to compensate for the time delta between the start and end of
631 * scanout.
632 */
633void
634render_compute_projection_scanout_compensation(struct render_compute *render,
635 VkSampler src_samplers[XRT_MAX_VIEWS],
636 VkImageView src_image_views[XRT_MAX_VIEWS],
637 const struct xrt_normalized_rect src_rects[XRT_MAX_VIEWS],
638 const struct xrt_fov src_fovs[XRT_MAX_VIEWS],
639 const struct xrt_pose new_poses_scanout_begin[XRT_MAX_VIEWS],
640 const struct xrt_pose new_poses_scanout_end[XRT_MAX_VIEWS],
641 VkImage target_image,
642 VkImageView target_image_view,
643 const struct render_viewport_data views[XRT_MAX_VIEWS])
644{
645 assert(render->r != NULL);
646 struct render_resources *r = render->r;
647
648
649 /*
650 * UBO
651 */
652
653 struct xrt_matrix_4x4 time_warp_matrix_scanout_begin[XRT_MAX_VIEWS];
654 struct xrt_matrix_4x4 time_warp_matrix_scanout_end[XRT_MAX_VIEWS];
655 for (uint32_t i = 0; i < render->r->view_count; ++i) {
656 render_calc_time_warp_projection(&src_fovs[i], &time_warp_matrix_scanout_begin[i]);
657
658 render_calc_time_warp_matrix( //
659 &new_poses_scanout_begin[i], //
660 &src_fovs[i], //
661 &new_poses_scanout_end[i], //
662 &time_warp_matrix_scanout_end[i]); //
663 }
664
665 struct render_compute_distortion_ubo_data *data =
666 (struct render_compute_distortion_ubo_data *)r->compute.distortion.ubo.mapped;
667 for (uint32_t i = 0; i < render->r->view_count; ++i) {
668 data->views[i] = views[i];
669 data->pre_transforms[i] = r->distortion.uv_to_tanangle[i];
670 data->transform_timewarp_scanout_begin[i] = time_warp_matrix_scanout_begin[i];
671 data->transform_timewarp_scanout_end[i] = time_warp_matrix_scanout_end[i];
672 data->post_transforms[i] = src_rects[i];
673 }
674
675 dispatch_project_pipeline(render, src_samplers, src_image_views, src_rects, target_image, target_image_view,
676 views, r->compute.distortion.timewarp_pipeline);
677}
678
679void
680render_compute_projection_no_timewarp(struct render_compute *render,
681 VkSampler src_samplers[XRT_MAX_VIEWS],
682 VkImageView src_image_views[XRT_MAX_VIEWS],
683 const struct xrt_normalized_rect src_rects[XRT_MAX_VIEWS],
684 VkImage target_image,
685 VkImageView target_image_view,
686 const struct render_viewport_data views[XRT_MAX_VIEWS])
687{
688 assert(render->r != NULL);
689 struct render_resources *r = render->r;
690
691 dispatch_project_pipeline(render, src_samplers, src_image_views, src_rects, target_image, target_image_view,
692 views, r->compute.distortion.pipeline);
693}
694
695void
696render_compute_clear(struct render_compute *render,
697 VkImage target_image,
698 VkImageView target_image_view,
699 const struct render_viewport_data views[XRT_MAX_VIEWS])
700{
701 assert(render->r != NULL);
702
703 struct vk_bundle *vk = vk_from_render(render);
704 struct render_resources *r = render->r;
705
706
707 /*
708 * UBO
709 */
710
711 // Calculate transforms.
712 struct xrt_matrix_4x4 transforms[XRT_MAX_VIEWS];
713 for (uint32_t i = 0; i < render->r->view_count; i++) {
714 math_matrix_4x4_identity(&transforms[i]);
715 }
716
717 struct render_compute_distortion_ubo_data *data =
718 (struct render_compute_distortion_ubo_data *)r->compute.clear.ubo.mapped;
719 for (uint32_t i = 0; i < render->r->view_count; ++i) {
720 data->views[i] = views[i];
721 }
722
723 /*
724 * Source, target and distortion images.
725 */
726
727 VkImageSubresourceRange subresource_range = {
728 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
729 .baseMipLevel = 0,
730 .levelCount = VK_REMAINING_MIP_LEVELS,
731 .baseArrayLayer = 0,
732 .layerCount = VK_REMAINING_ARRAY_LAYERS,
733 };
734
735 vk_cmd_image_barrier_gpu_locked( //
736 vk, //
737 r->cmd, //
738 target_image, //
739 0, //
740 VK_ACCESS_SHADER_WRITE_BIT, //
741 VK_IMAGE_LAYOUT_UNDEFINED, //
742 VK_IMAGE_LAYOUT_GENERAL, //
743 subresource_range); //
744
745 VkSampler sampler = r->samplers.mock;
746 VkSampler src_samplers[XRT_MAX_VIEWS];
747 VkImageView src_image_views[XRT_MAX_VIEWS];
748 VkSampler distortion_samplers[3 * XRT_MAX_VIEWS];
749 for (uint32_t i = 0; i < render->r->view_count; ++i) {
750 src_samplers[i] = sampler;
751 src_image_views[i] = r->mock.color.image_view;
752 distortion_samplers[3 * i + 0] = sampler;
753 distortion_samplers[3 * i + 1] = sampler;
754 distortion_samplers[3 * i + 2] = sampler;
755 }
756
757 update_compute_shared_descriptor_set( //
758 vk, //
759 r->compute.src_binding, //
760 src_samplers, //
761 src_image_views, //
762 r->compute.distortion_binding, //
763 distortion_samplers, //
764 r->distortion.image_views, //
765 r->compute.target_binding, //
766 target_image_view, //
767 r->compute.ubo_binding, //
768 r->compute.clear.ubo.buffer, //
769 VK_WHOLE_SIZE, // ubo_size
770 render->shared_descriptor_set, // descriptor_set
771 render->r->view_count); //
772
773 vk->vkCmdBindPipeline( //
774 r->cmd, //
775 VK_PIPELINE_BIND_POINT_COMPUTE, // pipelineBindPoint
776 r->compute.clear.pipeline); // pipeline
777
778 vk->vkCmdBindDescriptorSets( //
779 r->cmd, //
780 VK_PIPELINE_BIND_POINT_COMPUTE, // pipelineBindPoint
781 r->compute.distortion.pipeline_layout, // layout
782 0, // firstSet
783 1, // descriptorSetCount
784 &render->shared_descriptor_set, // pDescriptorSets
785 0, // dynamicOffsetCount
786 NULL); // pDynamicOffsets
787
788
789 uint32_t w = 0, h = 0;
790 calc_dispatch_dims_views(views, render->r->view_count, &w, &h);
791 assert(w != 0 && h != 0);
792
793 vk->vkCmdDispatch( //
794 r->cmd, //
795 w, // groupCountX
796 h, // groupCountY
797 2); // groupCountZ
798
799 VkImageMemoryBarrier memoryBarrier = {
800 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
801 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
802 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
803 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
804 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
805 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
806 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
807 .image = target_image,
808 .subresourceRange = subresource_range,
809 };
810
811 vk->vkCmdPipelineBarrier( //
812 r->cmd, //
813 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, //
814 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, //
815 0, //
816 0, //
817 NULL, //
818 0, //
819 NULL, //
820 1, //
821 &memoryBarrier); //
822}