The open source OpenXR runtime
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

c/render: Implement layer squashing for compute shader

Co-authored-by: Jakob Bornecrantz <jakob@collabora.com>
Co-authored-by: Fernando Velazquez Innella <finnella@magicleap.com>

+754 -2
+1
src/xrt/compositor/CMakeLists.txt
··· 120 120 set(SHADERS 121 121 shaders/clear.comp 122 122 shaders/distortion.comp 123 + shaders/layer.comp 123 124 shaders/mesh.frag 124 125 shaders/mesh.vert 125 126 shaders/layer.frag
+179
src/xrt/compositor/render/render_compute.c
··· 86 86 */ 87 87 88 88 XRT_MAYBE_UNUSED static void 89 + update_compute_layer_descriptor_set(struct vk_bundle *vk, 90 + uint32_t src_binding, 91 + VkSampler src_samplers[COMP_MAX_IMAGES], 92 + VkImageView src_image_views[COMP_MAX_IMAGES], 93 + uint32_t image_count, 94 + uint32_t target_binding, 95 + VkImageView target_image_view, 96 + uint32_t ubo_binding, 97 + VkBuffer ubo_buffer, 98 + VkDeviceSize ubo_size, 99 + VkDescriptorSet descriptor_set) 100 + { 101 + assert(image_count <= COMP_MAX_IMAGES); 102 + 103 + VkDescriptorImageInfo src_image_info[COMP_MAX_IMAGES]; 104 + for (uint32_t i = 0; i < image_count; i++) { 105 + src_image_info[i].sampler = src_samplers[i]; 106 + src_image_info[i].imageView = src_image_views[i]; 107 + src_image_info[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 108 + } 109 + 110 + VkDescriptorImageInfo target_image_info = { 111 + .imageView = target_image_view, 112 + .imageLayout = VK_IMAGE_LAYOUT_GENERAL, 113 + }; 114 + 115 + VkDescriptorBufferInfo buffer_info = { 116 + .buffer = ubo_buffer, 117 + .offset = 0, 118 + .range = ubo_size, 119 + }; 120 + 121 + VkWriteDescriptorSet write_descriptor_sets[3] = { 122 + { 123 + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 124 + .dstSet = descriptor_set, 125 + .dstBinding = src_binding, 126 + .descriptorCount = image_count, 127 + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 128 + .pImageInfo = src_image_info, 129 + }, 130 + { 131 + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 132 + .dstSet = descriptor_set, 133 + .dstBinding = target_binding, 134 + .descriptorCount = 1, 135 + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 136 + .pImageInfo = &target_image_info, 137 + }, 138 + { 139 + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 140 + .dstSet = descriptor_set, 141 + .dstBinding = ubo_binding, 142 + .descriptorCount = 1, 143 + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 144 + .pBufferInfo = &buffer_info, 145 + }, 146 + }; 147 + 148 + vk->vkUpdateDescriptorSets( // 149 + vk->device, // 150 + ARRAY_SIZE(write_descriptor_sets), // descriptorWriteCount 151 + write_descriptor_sets, // pDescriptorWrites 152 + 0, // descriptorCopyCount 153 + NULL); // pDescriptorCopies 154 + } 155 + 156 + XRT_MAYBE_UNUSED static void 89 157 update_compute_distortion_descriptor_set(struct vk_bundle *vk, 90 158 uint32_t src_binding, 91 159 VkSampler src_samplers[2], ··· 262 330 struct vk_bundle *vk = r->vk; 263 331 crc->r = r; 264 332 333 + C(vk_create_descriptor_set( // 334 + vk, // 335 + r->compute.descriptor_pool, // descriptor_pool 336 + r->compute.layer.descriptor_set_layout, // descriptor_set_layout 337 + &crc->descriptor_set)); // descriptor_set 338 + 265 339 C(vk_create_descriptor_set( // 266 340 vk, // 267 341 r->compute.descriptor_pool, // descriptor_pool ··· 326 400 struct vk_bundle *vk = vk_from_crc(crc); 327 401 328 402 // Reclaimed by vkResetDescriptorPool. 403 + crc->descriptor_set = VK_NULL_HANDLE; 329 404 crc->distortion_descriptor_set = VK_NULL_HANDLE; 330 405 331 406 vk->vkResetDescriptorPool(vk->device, crc->r->compute.descriptor_pool, 0); 332 407 333 408 crc->r = NULL; 409 + } 410 + 411 + void 412 + render_compute_layers(struct render_compute *crc, 413 + VkSampler src_samplers[COMP_MAX_IMAGES], 414 + VkImageView src_image_views[COMP_MAX_IMAGES], 415 + uint32_t image_count, 416 + VkImage target_image, 417 + VkImageView target_image_view, 418 + VkImageLayout transition_to, 419 + bool timewarp) 420 + { 421 + assert(crc->r != NULL); 422 + 423 + struct vk_bundle *vk = vk_from_crc(crc); 424 + struct render_resources *r = crc->r; 425 + 426 + struct render_compute_layer_ubo_data *ubo_data = 427 + (struct render_compute_layer_ubo_data *)crc->r->compute.layer.ubo.mapped; 428 + 429 + /* 430 + * Source, target and distortion images. 431 + */ 432 + 433 + VkImageSubresourceRange subresource_range = { 434 + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 435 + .baseMipLevel = 0, 436 + .levelCount = VK_REMAINING_MIP_LEVELS, 437 + .baseArrayLayer = 0, 438 + .layerCount = VK_REMAINING_ARRAY_LAYERS, 439 + }; 440 + 441 + vk_cmd_image_barrier_gpu_locked( // 442 + vk, // 443 + r->cmd, // 444 + target_image, // 445 + 0, // 446 + VK_ACCESS_SHADER_WRITE_BIT, // 447 + VK_IMAGE_LAYOUT_UNDEFINED, // 448 + VK_IMAGE_LAYOUT_GENERAL, // 449 + subresource_range); // 450 + 451 + update_compute_layer_descriptor_set( // 452 + vk, // 453 + r->compute.src_binding, // 454 + src_samplers, // 455 + src_image_views, // 456 + image_count, // 457 + r->compute.target_binding, // 458 + target_image_view, // 459 + r->compute.ubo_binding, // 460 + r->compute.layer.ubo.buffer, // 461 + VK_WHOLE_SIZE, // 462 + crc->descriptor_set); // 463 + 464 + vk->vkCmdBindPipeline( // 465 + crc->r->cmd, // commandBuffer 466 + VK_PIPELINE_BIND_POINT_COMPUTE, // pipelineBindPoint 467 + timewarp ? r->compute.layer.timewarp_pipeline : r->compute.layer.non_timewarp_pipeline); // pipeline 468 + 469 + vk->vkCmdBindDescriptorSets( // 470 + r->cmd, // commandBuffer 471 + VK_PIPELINE_BIND_POINT_COMPUTE, // pipelineBindPoint 472 + r->compute.layer.pipeline_layout, // layout 473 + 0, // firstSet 474 + 1, // descriptorSetCount 475 + &crc->descriptor_set, // pDescriptorSets 476 + 0, // dynamicOffsetCount 477 + NULL); // pDynamicOffsets 478 + 479 + 480 + uint32_t w = 0, h = 0; 481 + calc_dispatch_dims(ubo_data->views, &w, &h); 482 + assert(w != 0 && h != 0); 483 + 484 + vk->vkCmdDispatch( // 485 + r->cmd, // commandBuffer 486 + w, // groupCountX 487 + h, // groupCountY 488 + 2); // groupCountZ 489 + 490 + VkImageMemoryBarrier memoryBarrier = { 491 + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 492 + .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, 493 + .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT, 494 + .oldLayout = VK_IMAGE_LAYOUT_GENERAL, 495 + .newLayout = transition_to, 496 + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 497 + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 498 + .image = target_image, 499 + .subresourceRange = subresource_range, 500 + }; 501 + 502 + vk->vkCmdPipelineBarrier( // 503 + r->cmd, // 504 + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, // 505 + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // 506 + 0, // 507 + 0, // 508 + NULL, // 509 + 0, // 510 + NULL, // 511 + 1, // 512 + &memoryBarrier); // 334 513 } 335 514 336 515 void
+104
src/xrt/compositor/render/render_interface.h
··· 11 11 #pragma once 12 12 13 13 #define COMP_MAX_LAYERS 16 14 + #define COMP_VIEWS_PER_LAYER 2 15 + #define COMP_MAX_IMAGES 32 16 + 14 17 #include "xrt/xrt_compiler.h" 15 18 #include "xrt/xrt_defines.h" 16 19 ··· 76 79 struct render_shaders 77 80 { 78 81 VkShaderModule clear_comp; 82 + VkShaderModule layer_comp; 79 83 VkShaderModule distortion_comp; 80 84 81 85 VkShaderModule mesh_vert; ··· 310 314 311 315 struct 312 316 { 317 + //! Descriptor set layout for compute. 318 + VkDescriptorSetLayout descriptor_set_layout; 319 + 320 + //! Pipeline layout used for compute distortion. 321 + VkPipelineLayout pipeline_layout; 322 + 323 + //! Doesn't depend on target so is static. 324 + VkPipeline non_timewarp_pipeline; 325 + 326 + //! Doesn't depend on target so is static. 327 + VkPipeline timewarp_pipeline; 328 + 329 + //! Size of combined image sampler array 330 + uint32_t image_array_size; 331 + 332 + //! Target info. 333 + struct render_buffer ubo; 334 + } layer; 335 + 336 + struct 337 + { 313 338 //! Descriptor set layout for compute distortion. 314 339 VkDescriptorSetLayout descriptor_set_layout; 315 340 ··· 333 358 334 359 //! Target info. 335 360 struct render_buffer ubo; 361 + 362 + //! @todo other resources 336 363 } clear; 337 364 } compute; 338 365 ··· 673 700 struct render_resources *r; 674 701 675 702 //! Shared descriptor set between clear, projection and timewarp. 703 + VkDescriptorSet descriptor_set; 704 + 705 + //! Descriptor set for distortion. 676 706 VkDescriptorSet distortion_descriptor_set; 677 707 }; 678 708 679 709 /*! 710 + * UBO data that is sent to the compute layer shaders. 711 + * 712 + * Used in @ref render_compute 713 + */ 714 + struct render_compute_layer_ubo_data 715 + { 716 + struct render_viewport_data views[2]; 717 + struct xrt_normalized_rect pre_transforms[2]; 718 + struct xrt_normalized_rect post_transforms[COMP_MAX_LAYERS * COMP_VIEWS_PER_LAYER]; 719 + 720 + //! std140 uvec2, corresponds to enum xrt_layer_type and unpremultiplied alpha. 721 + struct 722 + { 723 + uint32_t val; 724 + uint32_t unpremultiplied; 725 + uint32_t padding[2]; 726 + } layer_type[COMP_MAX_LAYERS]; 727 + 728 + //! Which image/sampler(s) correspond to each layer. 729 + struct 730 + { 731 + uint32_t images[2]; 732 + //! @todo Implement separated samplers and images (and change to samplers[2]) 733 + uint32_t padding[2]; 734 + } images_samplers[COMP_MAX_LAYERS * 2]; 735 + 736 + 737 + /*! 738 + * For projection layers 739 + */ 740 + 741 + //! Timewarp matrices 742 + struct xrt_matrix_4x4 transforms[COMP_MAX_LAYERS * COMP_VIEWS_PER_LAYER]; 743 + 744 + 745 + /*! 746 + * For quad layers 747 + */ 748 + 749 + //! All quad transforms and coordinates are in view space 750 + struct 751 + { 752 + struct xrt_vec3 val; 753 + float padding; 754 + } quad_position[COMP_MAX_LAYERS * 2]; 755 + struct 756 + { 757 + struct xrt_vec3 val; 758 + float padding; 759 + } quad_normal[COMP_MAX_LAYERS * 2]; 760 + struct xrt_matrix_4x4 inverse_quad_transform[COMP_MAX_LAYERS * 2]; 761 + 762 + //! Quad extent in world scale 763 + struct 764 + { 765 + struct xrt_vec2 val; 766 + float padding[2]; 767 + } quad_extent[COMP_MAX_LAYERS]; 768 + }; 769 + 770 + /*! 680 771 * UBO data that is sent to the compute distortion shaders. 681 772 * 682 773 * Used in @ref render_compute ··· 722 813 */ 723 814 bool 724 815 render_compute_end(struct render_compute *crc); 816 + 817 + /*! 818 + * @public @memberof render_compute 819 + */ 820 + void 821 + render_compute_layers(struct render_compute *crc, // 822 + VkSampler src_samplers[COMP_MAX_IMAGES], // 823 + VkImageView src_image_views[COMP_MAX_IMAGES], // 824 + uint32_t image_count, // 825 + VkImage target_image, // 826 + VkImageView target_image_view, // 827 + VkImageLayout transition_to, // 828 + bool timewarp); // 725 829 726 830 /*! 727 831 * @public @memberof render_compute
+180 -2
src/xrt/compositor/render/render_resources.c
··· 182 182 */ 183 183 184 184 static VkResult 185 + create_compute_layer_descriptor_set_layout(struct vk_bundle *vk, 186 + uint32_t src_binding, 187 + uint32_t target_binding, 188 + uint32_t ubo_binding, 189 + uint32_t source_images_count, 190 + VkDescriptorSetLayout *out_descriptor_set_layout) 191 + { 192 + VkResult ret; 193 + 194 + VkDescriptorSetLayoutBinding set_layout_bindings[3] = { 195 + { 196 + .binding = src_binding, 197 + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 198 + .descriptorCount = source_images_count, 199 + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, 200 + }, 201 + { 202 + .binding = target_binding, 203 + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 204 + .descriptorCount = 1, 205 + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, 206 + }, 207 + { 208 + .binding = ubo_binding, 209 + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 210 + .descriptorCount = 1, 211 + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, 212 + }, 213 + }; 214 + 215 + VkDescriptorSetLayoutCreateInfo set_layout_info = { 216 + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 217 + .bindingCount = ARRAY_SIZE(set_layout_bindings), 218 + .pBindings = set_layout_bindings, 219 + }; 220 + 221 + VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE; 222 + ret = vk->vkCreateDescriptorSetLayout( // 223 + vk->device, // 224 + &set_layout_info, // 225 + NULL, // 226 + &descriptor_set_layout); // 227 + if (ret != VK_SUCCESS) { 228 + VK_ERROR(vk, "vkCreateDescriptorSetLayout failed: %s", vk_result_string(ret)); 229 + return ret; 230 + } 231 + 232 + *out_descriptor_set_layout = descriptor_set_layout; 233 + 234 + return VK_SUCCESS; 235 + } 236 + 237 + static VkResult 185 238 create_compute_distortion_descriptor_set_layout(struct vk_bundle *vk, 186 239 uint32_t src_binding, 187 240 uint32_t distortion_binding, ··· 240 293 return VK_SUCCESS; 241 294 } 242 295 296 + struct compute_layer_params 297 + { 298 + VkBool32 do_timewarp; 299 + VkBool32 do_color_correction; 300 + uint32_t max_layers; 301 + uint32_t views_per_layer; 302 + uint32_t image_array_size; 303 + }; 304 + 243 305 struct compute_distortion_params 244 306 { 245 307 uint32_t distortion_texel_count; ··· 247 309 }; 248 310 249 311 static VkResult 312 + create_compute_layer_pipeline(struct vk_bundle *vk, 313 + VkPipelineCache pipeline_cache, 314 + VkShaderModule shader, 315 + VkPipelineLayout pipeline_layout, 316 + const struct compute_layer_params *params, 317 + VkPipeline *out_compute_pipeline) 318 + { 319 + #define ENTRY(ID, FIELD) \ 320 + { \ 321 + .constantID = ID, \ 322 + .offset = offsetof(struct compute_layer_params, FIELD), \ 323 + sizeof(params->FIELD), \ 324 + } 325 + 326 + VkSpecializationMapEntry entries[] = { 327 + ENTRY(1, do_timewarp), // 328 + ENTRY(2, do_color_correction), // 329 + ENTRY(3, max_layers), // 330 + ENTRY(4, views_per_layer), // 331 + ENTRY(5, image_array_size), // 332 + }; 333 + #undef ENTRY 334 + 335 + VkSpecializationInfo specialization_info = { 336 + .mapEntryCount = ARRAY_SIZE(entries), 337 + .pMapEntries = entries, 338 + .dataSize = sizeof(*params), 339 + .pData = params, 340 + }; 341 + 342 + return vk_create_compute_pipeline( // 343 + vk, // vk_bundle 344 + pipeline_cache, // pipeline_cache 345 + shader, // shader 346 + pipeline_layout, // pipeline_layout 347 + &specialization_info, // specialization_info 348 + out_compute_pipeline); // out_compute_pipeline 349 + } 350 + 351 + static VkResult 250 352 create_compute_distortion_pipeline(struct vk_bundle *vk, 251 353 VkPipelineCache pipeline_cache, 252 354 VkShaderModule shader, ··· 705 807 r->compute.target_binding = 2; 706 808 r->compute.ubo_binding = 3; 707 809 810 + r->compute.layer.image_array_size = vk->features.max_per_stage_descriptor_sampled_images; 811 + if (r->compute.layer.image_array_size > COMP_MAX_IMAGES) { 812 + r->compute.layer.image_array_size = COMP_MAX_IMAGES; 813 + } 814 + 708 815 709 816 /* 710 817 * Mock, used as a default image empty image. ··· 841 948 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // clamp_mode 842 949 &r->compute.default_sampler)); // out_sampler 843 950 951 + 844 952 struct vk_descriptor_pool_info compute_pool_info = { 845 953 .uniform_per_descriptor_count = 1, 846 - .sampler_per_descriptor_count = 8, 954 + // layer images 955 + .sampler_per_descriptor_count = r->compute.layer.image_array_size + 6, 847 956 .storage_image_per_descriptor_count = 1, 848 957 .storage_buffer_per_descriptor_count = 0, 849 - .descriptor_count = 1, 958 + .descriptor_count = 2, 850 959 .freeable = false, 851 960 }; 852 961 ··· 857 966 858 967 859 968 /* 969 + * Layer pipeline 970 + */ 971 + 972 + C(create_compute_layer_descriptor_set_layout( // 973 + vk, // vk_bundle 974 + r->compute.src_binding, // src_binding, 975 + r->compute.target_binding, // target_binding, 976 + r->compute.ubo_binding, // ubo_binding, 977 + r->compute.layer.image_array_size, // source_images_count, 978 + &r->compute.layer.descriptor_set_layout)); // out_descriptor_set_layout 979 + 980 + C(vk_create_pipeline_layout( // 981 + vk, // vk_bundle 982 + r->compute.layer.descriptor_set_layout, // descriptor_set_layout 983 + &r->compute.layer.pipeline_layout)); // out_pipeline_layout 984 + 985 + struct compute_layer_params layer_params = { 986 + .do_timewarp = false, 987 + .do_color_correction = true, 988 + .max_layers = COMP_MAX_LAYERS, 989 + .views_per_layer = COMP_VIEWS_PER_LAYER, 990 + .image_array_size = r->compute.layer.image_array_size, 991 + }; 992 + 993 + C(create_compute_layer_pipeline( // 994 + vk, // vk_bundle 995 + r->pipeline_cache, // pipeline_cache 996 + r->shaders->layer_comp, // shader 997 + r->compute.layer.pipeline_layout, // pipeline_layout 998 + &layer_params, // params 999 + &r->compute.layer.non_timewarp_pipeline)); // out_compute_pipeline 1000 + 1001 + struct compute_layer_params layer_timewarp_params = { 1002 + .do_timewarp = true, 1003 + .do_color_correction = true, 1004 + .max_layers = COMP_MAX_LAYERS, 1005 + .views_per_layer = COMP_VIEWS_PER_LAYER, 1006 + .image_array_size = r->compute.layer.image_array_size, 1007 + }; 1008 + 1009 + C(create_compute_layer_pipeline( // 1010 + vk, // vk_bundle 1011 + r->pipeline_cache, // pipeline_cache 1012 + r->shaders->layer_comp, // shader 1013 + r->compute.layer.pipeline_layout, // pipeline_layout 1014 + &layer_timewarp_params, // params 1015 + &r->compute.layer.timewarp_pipeline)); // out_compute_pipeline 1016 + 1017 + size_t layer_ubo_size = sizeof(struct render_compute_layer_ubo_data); 1018 + 1019 + C(render_buffer_init( // 1020 + vk, // vk_bundle 1021 + &r->compute.layer.ubo, // buffer 1022 + ubo_usage_flags, // usage_flags 1023 + memory_property_flags, // memory_property_flags 1024 + layer_ubo_size)); // size 1025 + C(render_buffer_map( // 1026 + vk, // vk_bundle 1027 + &r->compute.layer.ubo)); // buffer 1028 + 1029 + 1030 + /* 860 1031 * Distortion pipeline 861 1032 */ 862 1033 ··· 1108 1279 render_buffer_close(vk, &r->mesh.ubos[1]); 1109 1280 1110 1281 D(DescriptorPool, r->compute.descriptor_pool); 1282 + 1283 + D(DescriptorSetLayout, r->compute.layer.descriptor_set_layout); 1284 + D(Pipeline, r->compute.layer.non_timewarp_pipeline); 1285 + D(Pipeline, r->compute.layer.timewarp_pipeline); 1286 + D(PipelineLayout, r->compute.layer.pipeline_layout); 1287 + 1111 1288 D(DescriptorSetLayout, r->compute.distortion.descriptor_set_layout); 1112 1289 D(Pipeline, r->compute.distortion.pipeline); 1113 1290 D(Pipeline, r->compute.distortion.timewarp_pipeline); ··· 1119 1296 1120 1297 render_distortion_buffer_close(r); 1121 1298 render_buffer_close(vk, &r->compute.clear.ubo); 1299 + render_buffer_close(vk, &r->compute.layer.ubo); 1122 1300 render_buffer_close(vk, &r->compute.distortion.ubo); 1123 1301 1124 1302 teardown_scratch_image(r);
+7
src/xrt/compositor/render/render_shaders.c
··· 24 24 #include "xrt/xrt_config_build.h" 25 25 26 26 #include "shaders/clear.comp.h" 27 + #include "shaders/layer.comp.h" 27 28 #include "shaders/distortion.comp.h" 28 29 #include "shaders/layer.frag.h" 29 30 #include "shaders/layer.vert.h" ··· 93 94 sizeof(shaders_clear_comp), // size 94 95 &s->clear_comp)); // out 95 96 97 + C(shader_load(vk, // vk_bundle 98 + shaders_layer_comp, // data 99 + sizeof(shaders_layer_comp), // size 100 + &s->layer_comp)); // out 101 + 96 102 C(shader_load(vk, // vk_bundle 97 103 shaders_distortion_comp, // data 98 104 sizeof(shaders_distortion_comp), // size ··· 161 167 { 162 168 D(clear_comp); 163 169 D(distortion_comp); 170 + D(layer_comp); 164 171 D(mesh_vert); 165 172 D(mesh_frag); 166 173 D(equirect1_vert);
+283
src/xrt/compositor/shaders/layer.comp
··· 1 + // Copyright 2021-2022, Collabora Ltd. 2 + // Author: Jakob Bornecrantz <jakob@collabora.com> 3 + // Author: Christoph Haag <christoph.haag@collabora.com> 4 + // SPDX-License-Identifier: BSL-1.0 5 + 6 + #version 460 7 + #extension GL_GOOGLE_include_directive : require 8 + 9 + #include "srgb.inc.glsl" 10 + 11 + //! @todo should this be a spcialization const? 12 + #define XRT_LAYER_STEREO_PROJECTION 0 13 + #define XRT_LAYER_STEREO_PROJECTION_DEPTH 1 14 + #define XRT_LAYER_QUAD 2 15 + #define XRT_LAYER_CUBE 3 16 + #define XRT_LAYER_CYLINDER 4 17 + #define XRT_LAYER_EQUIRECT1 5 18 + #define XRT_LAYER_EQUIRECT2 6 19 + 20 + // Should we do timewarp. 21 + layout(constant_id = 1) const bool do_timewarp = false; 22 + layout(constant_id = 2) const bool do_color_correction = true; 23 + layout(constant_id = 3) const int COMP_MAX_LAYERS = 16; 24 + layout(constant_id = 4) const int COMP_VIEWS_PER_LAYER = 2; 25 + layout(constant_id = 5) const int SAMPLER_ARRAY_SIZE = 16; 26 + 27 + layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; 28 + 29 + // layer 0 left color, layer 0 right color, [optional: layer 0 left depth, layer 0 right depth], layer 1 left, layer 1 right, ... 30 + layout(set = 0, binding = 0) uniform sampler2D source[SAMPLER_ARRAY_SIZE]; 31 + layout(set = 0, binding = 2) uniform writeonly restrict image2D target; 32 + layout(set = 0, binding = 3, std140) uniform restrict Config 33 + { 34 + ivec4 views[2]; 35 + vec4 pre_transform[2]; 36 + vec4 post_transform[COMP_MAX_LAYERS][2]; 37 + 38 + // corresponds to enum xrt_layer_type 39 + uvec2 layer_type_and_unpremultiplied[COMP_MAX_LAYERS]; 40 + 41 + // which image/sampler(s) correspond to each layer 42 + ivec2 images_samplers[COMP_MAX_LAYERS][2]; 43 + 44 + // for projection layers 45 + 46 + // timewarp matrices 47 + mat4 transform[COMP_MAX_LAYERS][2]; 48 + 49 + 50 + // for quad layers 51 + 52 + // all quad transforms and coordinates are in view space 53 + vec4 quad_position[COMP_MAX_LAYERS][2]; 54 + vec4 quad_normal[COMP_MAX_LAYERS][2]; 55 + mat4 inverse_quad_transform[COMP_MAX_LAYERS][2]; 56 + 57 + // quad extent in world scale 58 + vec2 quad_extent[COMP_MAX_LAYERS]; 59 + } ubo; 60 + 61 + 62 + vec2 position_to_view_uv(ivec2 extent, uint ix, uint iy) 63 + { 64 + // Turn the index into floating point. 65 + vec2 xy = vec2(float(ix), float(iy)); 66 + 67 + // The inverse of the extent of a view image is the pixel size in [0 .. 1] space. 68 + vec2 extent_pixel_size = vec2(1.0 / float(extent.x), 1.0 / float(extent.y)); 69 + 70 + // Per-target pixel we move the size of the pixels. 71 + vec2 view_uv = xy * extent_pixel_size; 72 + 73 + // Emulate a triangle sample position by offset half target pixel size. 74 + view_uv = view_uv + extent_pixel_size / 2.0; 75 + 76 + return view_uv; 77 + } 78 + 79 + vec2 transform_uv_subimage(vec2 uv, uint iz, uint layer) 80 + { 81 + vec2 values = uv; 82 + 83 + // To deal with OpenGL flip and sub image view. 84 + values.xy = values.xy * ubo.post_transform[layer][iz].zw + ubo.post_transform[layer][iz].xy; 85 + 86 + // Ready to be used. 87 + return values.xy; 88 + } 89 + 90 + vec2 transform_uv_timewarp(vec2 uv, uint view_index, uint layer) 91 + { 92 + vec4 values = vec4(uv, -1, 1); 93 + 94 + // From uv to tan angle (tanget space). 95 + values.xy = values.xy * ubo.pre_transform[view_index].zw + ubo.pre_transform[view_index].xy; 96 + values.y = -values.y; // Flip to OpenXR coordinate system. 97 + 98 + // Timewarp. 99 + values = ubo.transform[layer][view_index] * values; 100 + values.xy = values.xy * (1.0 / max(values.w, 0.00001)); 101 + 102 + // From [-1, 1] to [0, 1] 103 + values.xy = values.xy * 0.5 + 0.5; 104 + 105 + // To deal with OpenGL flip and sub image view. 106 + values.xy = values.xy * ubo.post_transform[layer][view_index].zw + ubo.post_transform[layer][view_index].xy; 107 + 108 + // Done. 109 + return values.xy; 110 + } 111 + 112 + vec2 transform_uv(vec2 uv, uint view_index, uint layer) 113 + { 114 + if (do_timewarp) { 115 + return transform_uv_timewarp(uv, view_index, layer); 116 + } else { 117 + return transform_uv_subimage(uv, view_index, layer); 118 + } 119 + } 120 + 121 + vec4 do_projection(uint view_index, vec2 view_uv, uint layer) 122 + { 123 + uint source_image_index = ubo.images_samplers[layer][view_index].x; 124 + 125 + // Do any transformation needed. 126 + vec2 uv = transform_uv(view_uv, view_index, layer); 127 + 128 + // Sample the source. 129 + vec4 colour = vec4(texture(source[source_image_index], uv).rgba); 130 + 131 + return colour; 132 + } 133 + 134 + vec3 get_direction(vec2 uv, uint view_index) 135 + { 136 + // Skip the DIM/STRETCH/OFFSET stuff and go directly to values 137 + vec4 values = vec4(uv, -1, 1); 138 + 139 + // From uv to tan angle (tangent space). 140 + values.xy = values.xy * ubo.pre_transform[view_index].zw + ubo.pre_transform[view_index].xy; 141 + values.y = -values.y; // Flip to OpenXR coordinate system. 142 + 143 + vec3 direction = normalize(values.xyz); 144 + return direction; 145 + } 146 + 147 + vec4 do_quad(uint view_index, vec2 view_uv, uint layer) 148 + { 149 + uint source_image_index = ubo.images_samplers[layer][view_index].x; 150 + 151 + // center point of the plane in view space. 152 + vec3 quad_position = ubo.quad_position[layer][view_index].xyz; 153 + 154 + // normal vector of the plane. 155 + vec3 normal = ubo.quad_normal[layer][view_index].xyz; 156 + normal = normalize(normal); 157 + 158 + // coordinate system is the view space, therefore the camera/eye position is in the origin. 159 + vec3 camera = vec3(0.0, 0.0, 0.0); 160 + 161 + // default color white should never be visible 162 + vec4 colour = vec4(1.0, 1.0, 1.0, 1.0); 163 + 164 + //! @todo can we get better "pixel stuck" on projection layers with timewarp uv? 165 + // never use the timewarp uv here because it depends on the projection layer pose 166 + vec2 uv = view_uv; 167 + 168 + /* 169 + * To fill in the view_uv texel on the target texture, animaginary ray is shot hrough texels on the target 170 + * texture. When this imaginary ray hits a quad layer, it means that when the respective color at the hit 171 + * intersection is picked for the current view_uv texel, the final image as seen through the headset will 172 + * show this view_uv texel at the respective location. 173 + */ 174 + vec3 direction = get_direction(uv, view_index); 175 + direction = normalize(direction); 176 + 177 + float denominator = dot(direction, normal); 178 + 179 + // denominator is negative when vectors point towards each other, 0 when perpendicular, 180 + // and positive when vectors point in a similar direction, i.e. direction vector faces quad backface, which we don't render. 181 + if (denominator < 0.00001) { 182 + // shortest distance between origin and plane defined by normal + quad_position 183 + float dist = dot(camera - quad_position, normal); 184 + 185 + // distance between origin and intersection point on the plane. 186 + float intersection_dist = (dot(camera, normal) + dist) / -denominator; 187 + 188 + // layer is behind camera as defined by direction vector 189 + if (intersection_dist < 0) { 190 + colour = vec4(0.0, 0.0, 0.0, 0.0); 191 + return colour; 192 + } 193 + 194 + vec3 intersection = camera + intersection_dist * direction; 195 + 196 + // ps for "plane space" 197 + vec2 intersection_ps = (ubo.inverse_quad_transform[layer][view_index] * vec4(intersection.xyz, 1.0)).xy; 198 + 199 + bool in_plane_bounds = 200 + intersection_ps.x >= - ubo.quad_extent[layer].x / 2. && // 201 + intersection_ps.x <= ubo.quad_extent[layer].x / 2. && // 202 + intersection_ps.y >= - ubo.quad_extent[layer].y / 2. && // 203 + intersection_ps.y <= ubo.quad_extent[layer].y / 2.; 204 + 205 + if (in_plane_bounds) { 206 + // intersection_ps is in [-quad_extent .. quad_extent]. Transform to [0 .. quad_extent], then scale to [ 0 .. 1 ] for sampling 207 + vec2 plane_uv = (intersection_ps.xy + ubo.quad_extent[layer] / 2.) / ubo.quad_extent[layer]; 208 + 209 + // sample on the desired subimage, not the entire texture 210 + plane_uv = plane_uv * ubo.post_transform[layer][view_index].zw + ubo.post_transform[layer][view_index].xy; 211 + 212 + colour = texture(source[source_image_index], plane_uv); 213 + } else { 214 + // intersection on infinite plane outside of plane bounds 215 + colour = vec4(0.0, 0.0, 0.0, 0.0); 216 + return colour; 217 + } 218 + } else { 219 + // no intersection with front face of infinite plane or perpendicular 220 + colour = vec4(0.0, 0.0, 0.0, 0.0); 221 + return colour; 222 + } 223 + 224 + return vec4(colour); 225 + } 226 + 227 + vec4 do_layers(vec2 view_uv, uint view_index) 228 + { 229 + vec4 accum = vec4(0, 0, 0, 0); 230 + for (uint layer = 0; layer < COMP_MAX_LAYERS; layer++) { 231 + bool use_layer = false; 232 + 233 + vec4 rgba = vec4(0, 0, 0, 0); 234 + switch (ubo.layer_type_and_unpremultiplied[layer].x) { 235 + case XRT_LAYER_STEREO_PROJECTION: 236 + case XRT_LAYER_STEREO_PROJECTION_DEPTH: 237 + rgba = do_projection(view_index, view_uv, layer); 238 + use_layer = true; 239 + break; 240 + case XRT_LAYER_QUAD: 241 + rgba = do_quad(view_index, view_uv, layer); 242 + use_layer = true; 243 + break; 244 + default: break; 245 + } 246 + 247 + if (use_layer) { 248 + if (ubo.layer_type_and_unpremultiplied[layer].y != 0) { 249 + // Unpremultipled blend factor of src.a. 250 + accum.rgb = mix(accum.rgb, rgba.rgb, rgba.a); 251 + } else { 252 + // Premultiplied bland foctor of 1. 253 + accum.rgb = (accum.rgb * (1 - rgba.a)) + rgba.rgb; 254 + } 255 + } 256 + } 257 + return accum; 258 + } 259 + 260 + void main() 261 + { 262 + uint ix = gl_GlobalInvocationID.x; 263 + uint iy = gl_GlobalInvocationID.y; 264 + uint iz = gl_GlobalInvocationID.z; 265 + 266 + ivec2 offset = ivec2(ubo.views[iz].xy); 267 + ivec2 extent = ivec2(ubo.views[iz].zw); 268 + 269 + if (ix >= extent.x || iy >= extent.y) { 270 + return; 271 + } 272 + 273 + vec2 view_uv = position_to_view_uv(extent, ix, iy); 274 + 275 + vec4 colour = do_layers(view_uv, iz); 276 + 277 + if (do_color_correction) { 278 + // Do colour correction here since there are no automatic conversion in hardware available. 279 + colour = vec4(from_linear_to_srgb(colour.rgb), 1); 280 + } 281 + 282 + imageStore(target, ivec2(offset.x + ix, offset.y + iy), colour); 283 + }