The open source OpenXR runtime
0
fork

Configure Feed

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

c/layers: Implement layer renderer.

Implements a layer renderer capable of handling multiple quad
and projection layers rendered in it's own Vulkan pipeline.

authored by

Lubosz Sarnecki and committed by
Jakob Bornecrantz
aedd4d9f fc271ad5

+1151
+6
src/xrt/compositor/CMakeLists.txt
··· 8 8 shaders/none.frag 9 9 shaders/panotools.frag 10 10 shaders/vive.frag 11 + shaders/quad.frag 12 + shaders/quad.vert 11 13 ) 12 14 13 15 set(CLIENT_SOURCE_FILES ··· 30 32 main/comp_vk_swapchain.c 31 33 main/comp_vk_swapchain.h 32 34 main/comp_window.h 35 + main/comp_layer.h 36 + main/comp_layer.c 37 + main/comp_layer_renderer.h 38 + main/comp_layer_renderer.c 33 39 ) 34 40 35 41 if (XRT_VULKAN_ENABLE_VALIDATION)
+6
src/xrt/compositor/main/comp_compositor.h
··· 66 66 struct comp_swapchain_image images[XRT_MAX_SWAPCHAIN_IMAGES]; 67 67 }; 68 68 69 + enum comp_layer_type 70 + { 71 + COMP_LAYER_STEREO_PROJECTION, 72 + COMP_LAYER_QUAD, 73 + }; 74 + 69 75 /*! 70 76 * A stereo projection layer. 71 77 *
+251
src/xrt/compositor/main/comp_layer.c
··· 1 + // Copyright 2020, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Compositor quad rendering. 6 + * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 7 + * @ingroup comp_main 8 + */ 9 + 10 + #include "comp_layer.h" 11 + 12 + #include "util/u_misc.h" 13 + #include "math/m_api.h" 14 + 15 + #include <stdio.h> 16 + 17 + // clang-format off 18 + // Projection layers span from -1 to 1, the vertex buffer and quad layers 19 + // from -0.5 to 0.5, so this scale matrix needs to be applied for proj layers. 20 + static struct xrt_matrix_4x4 proj_scale = { 21 + .v = { 22 + 2, 0, 0, 0, 23 + 0, 2, 0, 0, 24 + 0, 0, 1, 0, 25 + 0, 0, 0, 1 26 + } 27 + }; 28 + // clang-format on 29 + 30 + void 31 + comp_layer_set_flip_y(struct comp_render_layer *self, bool flip_y) 32 + { 33 + for (uint32_t i = 0; i < 2; i++) 34 + self->transformation[i].flip_y = flip_y; 35 + } 36 + 37 + void 38 + comp_layer_set_model_matrix(struct comp_render_layer *self, 39 + const struct xrt_matrix_4x4 *m) 40 + { 41 + memcpy(&self->model_matrix, m, sizeof(struct xrt_matrix_4x4)); 42 + } 43 + 44 + static void 45 + _update_mvp_matrix(struct comp_render_layer *self, 46 + uint32_t eye, 47 + const struct xrt_matrix_4x4 *vp) 48 + { 49 + math_matrix_4x4_multiply(vp, &self->model_matrix, 50 + &self->transformation[eye].mvp); 51 + memcpy(self->transformation_ubos[eye].data, &self->transformation[eye], 52 + sizeof(struct layer_transformation)); 53 + } 54 + 55 + static bool 56 + _init_ubos(struct comp_render_layer *self) 57 + { 58 + VkBufferUsageFlags usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; 59 + VkMemoryPropertyFlags properties = 60 + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 61 + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | 62 + VK_MEMORY_PROPERTY_HOST_CACHED_BIT; 63 + 64 + for (uint32_t i = 0; i < 2; i++) { 65 + math_matrix_4x4_identity(&self->transformation[i].mvp); 66 + 67 + if (!vk_buffer_init( 68 + self->vk, sizeof(struct layer_transformation), usage, 69 + properties, &self->transformation_ubos[i].handle, 70 + &self->transformation_ubos[i].memory)) 71 + return false; 72 + 73 + VkResult res = self->vk->vkMapMemory( 74 + self->vk->device, self->transformation_ubos[i].memory, 0, 75 + VK_WHOLE_SIZE, 0, &self->transformation_ubos[i].data); 76 + vk_check_error("vkMapMemory", res, false); 77 + 78 + memcpy(self->transformation_ubos[i].data, 79 + &self->transformation[i], 80 + sizeof(struct layer_transformation)); 81 + } 82 + return true; 83 + } 84 + 85 + static void 86 + _update_descriptor(struct vk_bundle *vk, 87 + VkDescriptorSet set, 88 + VkBuffer transformation_buffer, 89 + VkSampler sampler, 90 + VkImageView image_view) 91 + { 92 + VkWriteDescriptorSet *sets = (VkWriteDescriptorSet[]){ 93 + { 94 + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 95 + .dstSet = set, 96 + .dstBinding = 0, 97 + .descriptorCount = 1, 98 + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 99 + .pBufferInfo = 100 + &(VkDescriptorBufferInfo){ 101 + .buffer = transformation_buffer, 102 + .offset = 0, 103 + .range = VK_WHOLE_SIZE, 104 + }, 105 + .pTexelBufferView = NULL, 106 + }, 107 + { 108 + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 109 + .dstSet = set, 110 + .dstBinding = 1, 111 + .descriptorCount = 1, 112 + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 113 + .pImageInfo = 114 + &(VkDescriptorImageInfo){ 115 + .sampler = sampler, 116 + .imageView = image_view, 117 + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 118 + }, 119 + .pBufferInfo = NULL, 120 + .pTexelBufferView = NULL, 121 + }, 122 + }; 123 + 124 + vk->vkUpdateDescriptorSets(vk->device, 2, sets, 0, NULL); 125 + } 126 + 127 + void 128 + comp_layer_update_descriptors(struct comp_render_layer *self, 129 + VkSampler sampler, 130 + VkImageView image_view) 131 + { 132 + for (uint32_t eye = 0; eye < 2; eye++) 133 + _update_descriptor(self->vk, self->descriptor_sets[eye], 134 + self->transformation_ubos[eye].handle, 135 + sampler, image_view); 136 + } 137 + 138 + void 139 + comp_layer_update_stereo_descriptors(struct comp_render_layer *self, 140 + VkSampler left_sampler, 141 + VkSampler right_sampler, 142 + VkImageView left_image_view, 143 + VkImageView right_image_view) 144 + { 145 + _update_descriptor(self->vk, self->descriptor_sets[0], 146 + self->transformation_ubos[0].handle, left_sampler, 147 + left_image_view); 148 + 149 + _update_descriptor(self->vk, self->descriptor_sets[1], 150 + self->transformation_ubos[1].handle, right_sampler, 151 + right_image_view); 152 + } 153 + 154 + static bool 155 + _init(struct comp_render_layer *self, 156 + struct vk_bundle *vk, 157 + enum comp_layer_type type, 158 + VkDescriptorSetLayout *layout) 159 + { 160 + self->vk = vk; 161 + 162 + self->type = type; 163 + 164 + self->visible = true; 165 + 166 + math_matrix_4x4_identity(&self->model_matrix); 167 + 168 + if (!_init_ubos(self)) 169 + return false; 170 + 171 + uint32_t set_count = 2; 172 + 173 + VkDescriptorPoolSize pool_sizes[] = { 174 + { 175 + .descriptorCount = set_count, 176 + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 177 + }, 178 + { 179 + .descriptorCount = set_count, 180 + .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 181 + }, 182 + }; 183 + 184 + if (!vk_init_descriptor_pool(self->vk, pool_sizes, 185 + ARRAY_SIZE(pool_sizes), set_count, 186 + &self->descriptor_pool)) 187 + return false; 188 + 189 + for (uint32_t eye = 0; eye < set_count; eye++) 190 + if (!vk_allocate_descriptor_sets( 191 + self->vk, self->descriptor_pool, 1, layout, 192 + &self->descriptor_sets[eye])) 193 + return false; 194 + 195 + return true; 196 + } 197 + 198 + void 199 + comp_layer_draw(struct comp_render_layer *self, 200 + uint32_t eye, 201 + VkPipeline pipeline, 202 + VkPipelineLayout pipeline_layout, 203 + VkCommandBuffer cmd_buffer, 204 + const struct vk_buffer *vertex_buffer, 205 + const struct xrt_matrix_4x4 *vp) 206 + { 207 + if (!self->visible) 208 + return; 209 + 210 + self->vk->vkCmdBindPipeline(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, 211 + pipeline); 212 + 213 + switch (self->type) { 214 + case COMP_LAYER_STEREO_PROJECTION: 215 + _update_mvp_matrix(self, eye, &proj_scale); 216 + break; 217 + case COMP_LAYER_QUAD: _update_mvp_matrix(self, eye, vp); break; 218 + } 219 + 220 + self->vk->vkCmdBindDescriptorSets( 221 + cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, 222 + &self->descriptor_sets[eye], 0, NULL); 223 + 224 + VkDeviceSize offsets[1] = {0}; 225 + self->vk->vkCmdBindVertexBuffers(cmd_buffer, 0, 1, 226 + &vertex_buffer->handle, &offsets[0]); 227 + 228 + self->vk->vkCmdDraw(cmd_buffer, vertex_buffer->size, 1, 0, 0); 229 + } 230 + 231 + struct comp_render_layer * 232 + comp_layer_create(struct vk_bundle *vk, 233 + enum comp_layer_type type, 234 + VkDescriptorSetLayout *layout) 235 + { 236 + struct comp_render_layer *q = U_TYPED_CALLOC(struct comp_render_layer); 237 + 238 + _init(q, vk, type, layout); 239 + 240 + return q; 241 + } 242 + 243 + void 244 + comp_layer_destroy(struct comp_render_layer *self) 245 + { 246 + for (uint32_t eye = 0; eye < 2; eye++) 247 + vk_buffer_destroy(&self->transformation_ubos[eye], self->vk); 248 + 249 + self->vk->vkDestroyDescriptorPool(self->vk->device, 250 + self->descriptor_pool, NULL); 251 + }
+72
src/xrt/compositor/main/comp_layer.h
··· 1 + // Copyright 2020, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Compositor quad rendering. 6 + * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 7 + * @ingroup comp_main 8 + */ 9 + 10 + #pragma once 11 + 12 + #include "vk/vk_helpers.h" 13 + #include "comp_compositor.h" 14 + 15 + struct layer_transformation 16 + { 17 + struct xrt_matrix_4x4 mvp; 18 + bool flip_y; 19 + }; 20 + 21 + struct comp_render_layer 22 + { 23 + struct vk_bundle *vk; 24 + 25 + bool visible; 26 + 27 + enum comp_layer_type type; 28 + 29 + struct layer_transformation transformation[2]; 30 + struct vk_buffer transformation_ubos[2]; 31 + 32 + VkDescriptorPool descriptor_pool; 33 + VkDescriptorSet descriptor_sets[2]; 34 + 35 + struct xrt_matrix_4x4 model_matrix; 36 + }; 37 + 38 + struct comp_render_layer * 39 + comp_layer_create(struct vk_bundle *vk, 40 + enum comp_layer_type type, 41 + VkDescriptorSetLayout *layout); 42 + 43 + void 44 + comp_layer_draw(struct comp_render_layer *self, 45 + uint32_t eye, 46 + VkPipeline pipeline, 47 + VkPipelineLayout pipeline_layout, 48 + VkCommandBuffer cmd_buffer, 49 + const struct vk_buffer *vertex_buffer, 50 + const struct xrt_matrix_4x4 *vp); 51 + 52 + void 53 + comp_layer_set_model_matrix(struct comp_render_layer *self, 54 + const struct xrt_matrix_4x4 *m); 55 + 56 + void 57 + comp_layer_destroy(struct comp_render_layer *self); 58 + 59 + void 60 + comp_layer_update_descriptors(struct comp_render_layer *self, 61 + VkSampler sampler, 62 + VkImageView image_view); 63 + 64 + void 65 + comp_layer_update_stereo_descriptors(struct comp_render_layer *self, 66 + VkSampler left_sampler, 67 + VkSampler right_sampler, 68 + VkImageView left_image_view, 69 + VkImageView right_image_view); 70 + 71 + void 72 + comp_layer_set_flip_y(struct comp_render_layer *self, bool flip_y);
+681
src/xrt/compositor/main/comp_layer_renderer.c
··· 1 + // Copyright 2020, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Compositor quad rendering. 6 + * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 7 + * @ingroup comp_main 8 + */ 9 + 10 + #include "comp_layer_renderer.h" 11 + 12 + #include <stdio.h> 13 + 14 + #include "util/u_misc.h" 15 + #include "math/m_api.h" 16 + 17 + #include "shaders/quad.frag.h" 18 + #include "shaders/quad.vert.h" 19 + 20 + 21 + struct comp_layer_vertex 22 + { 23 + float position[3]; 24 + float uv[2]; 25 + }; 26 + 27 + static const VkClearColorValue background_color = { 28 + .float32 = {0.3f, 0.3f, 0.3f, 1.0f}, 29 + }; 30 + 31 + static bool 32 + _init_render_pass(struct vk_bundle *vk, 33 + VkFormat format, 34 + VkImageLayout final_layout, 35 + VkSampleCountFlagBits sample_count, 36 + VkRenderPass *out_render_pass) 37 + { 38 + VkAttachmentDescription *attachments = (VkAttachmentDescription[]){ 39 + { 40 + .format = format, 41 + .samples = sample_count, 42 + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 43 + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, 44 + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, 45 + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 46 + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 47 + .finalLayout = final_layout, 48 + .flags = 0, 49 + }, 50 + }; 51 + 52 + VkRenderPassCreateInfo renderpass_info = { 53 + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 54 + .flags = 0, 55 + .attachmentCount = 1, 56 + .pAttachments = attachments, 57 + .subpassCount = 1, 58 + .pSubpasses = 59 + &(VkSubpassDescription){ 60 + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, 61 + .colorAttachmentCount = 1, 62 + .pColorAttachments = 63 + &(VkAttachmentReference){ 64 + .attachment = 0, 65 + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 66 + }, 67 + .pDepthStencilAttachment = NULL, 68 + .pResolveAttachments = NULL, 69 + }, 70 + .dependencyCount = 0, 71 + .pDependencies = NULL, 72 + }; 73 + 74 + VkResult res = vk->vkCreateRenderPass(vk->device, &renderpass_info, 75 + NULL, out_render_pass); 76 + vk_check_error("vkCreateRenderPass", res, false); 77 + 78 + return true; 79 + } 80 + 81 + static bool 82 + _init_descriptor_layout(struct comp_layer_renderer *self) 83 + { 84 + struct vk_bundle *vk = self->vk; 85 + 86 + VkDescriptorSetLayoutCreateInfo info = { 87 + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 88 + .bindingCount = 2, 89 + .pBindings = 90 + (VkDescriptorSetLayoutBinding[]){ 91 + // transformation buffer 92 + { 93 + .binding = 0, 94 + .descriptorCount = 1, 95 + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 96 + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, 97 + }, 98 + // quad texture 99 + { 100 + .binding = 1, 101 + .descriptorCount = 1, 102 + .descriptorType = 103 + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 104 + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, 105 + }, 106 + }, 107 + }; 108 + 109 + VkResult res = vk->vkCreateDescriptorSetLayout( 110 + vk->device, &info, NULL, &self->descriptor_set_layout); 111 + 112 + vk_check_error("vkCreateDescriptorSetLayout", res, false); 113 + 114 + return true; 115 + } 116 + 117 + static bool 118 + _init_pipeline_layout(struct comp_layer_renderer *self) 119 + { 120 + struct vk_bundle *vk = self->vk; 121 + 122 + VkPipelineLayoutCreateInfo info = { 123 + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 124 + .setLayoutCount = 1, 125 + .pSetLayouts = &self->descriptor_set_layout, 126 + .pushConstantRangeCount = 0, 127 + .pPushConstantRanges = NULL, 128 + }; 129 + 130 + VkResult res = vk->vkCreatePipelineLayout(vk->device, &info, NULL, 131 + &self->pipeline_layout); 132 + 133 + vk_check_error("vkCreatePipelineLayout", res, false); 134 + 135 + return true; 136 + } 137 + 138 + static bool 139 + _init_pipeline_cache(struct comp_layer_renderer *self) 140 + { 141 + struct vk_bundle *vk = self->vk; 142 + 143 + VkPipelineCacheCreateInfo info = { 144 + .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, 145 + }; 146 + 147 + VkResult res = vk->vkCreatePipelineCache(vk->device, &info, NULL, 148 + &self->pipeline_cache); 149 + 150 + vk_check_error("vkCreatePipelineCache", res, false); 151 + 152 + return true; 153 + } 154 + 155 + struct __attribute__((__packed__)) comp_pipeline_config 156 + { 157 + VkPrimitiveTopology topology; 158 + uint32_t stride; 159 + const VkVertexInputAttributeDescription *attribs; 160 + uint32_t attrib_count; 161 + const VkPipelineDepthStencilStateCreateInfo *depth_stencil_state; 162 + const VkPipelineColorBlendAttachmentState *blend_attachments; 163 + const VkPipelineRasterizationStateCreateInfo *rasterization_state; 164 + }; 165 + 166 + static VkPipelineShaderStageCreateInfo 167 + _shader_load(struct vk_bundle *vk, 168 + const uint32_t *code, 169 + size_t size, 170 + VkShaderStageFlagBits flags) 171 + { 172 + VkResult ret; 173 + 174 + VkShaderModuleCreateInfo info = { 175 + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 176 + .codeSize = size, 177 + .pCode = code, 178 + }; 179 + 180 + VkShaderModule module; 181 + ret = vk->vkCreateShaderModule(vk->device, &info, NULL, &module); 182 + if (ret != VK_SUCCESS) { 183 + VK_DEBUG(vk, "vkCreateShaderModule failed %u", ret); 184 + } 185 + 186 + return (VkPipelineShaderStageCreateInfo){ 187 + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 188 + .stage = flags, 189 + .module = module, 190 + .pName = "main", 191 + }; 192 + } 193 + 194 + static bool 195 + _init_graphics_pipeline(struct comp_layer_renderer *self) 196 + { 197 + struct vk_bundle *vk = self->vk; 198 + 199 + struct comp_pipeline_config config = { 200 + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 201 + .stride = sizeof(struct comp_layer_vertex), 202 + .attribs = 203 + (VkVertexInputAttributeDescription[]){ 204 + {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}, 205 + {1, 0, VK_FORMAT_R32G32_SFLOAT, 206 + offsetof(struct comp_layer_vertex, uv)}, 207 + }, 208 + .attrib_count = 2, 209 + .depth_stencil_state = 210 + &(VkPipelineDepthStencilStateCreateInfo){ 211 + .sType = 212 + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, 213 + .depthTestEnable = VK_FALSE, 214 + .depthWriteEnable = VK_FALSE, 215 + .depthCompareOp = VK_COMPARE_OP_NEVER, 216 + }, 217 + .blend_attachments = 218 + &(VkPipelineColorBlendAttachmentState){ 219 + .blendEnable = VK_FALSE, 220 + .colorWriteMask = 0xf, 221 + }, 222 + .rasterization_state = 223 + &(VkPipelineRasterizationStateCreateInfo){ 224 + .sType = 225 + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, 226 + .polygonMode = VK_POLYGON_MODE_FILL, 227 + .cullMode = VK_CULL_MODE_BACK_BIT, 228 + .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, 229 + .lineWidth = 1.0f, 230 + }, 231 + }; 232 + 233 + VkPipelineShaderStageCreateInfo shader_stages[2] = { 234 + _shader_load(vk, shaders_quad_vert, sizeof(shaders_quad_vert), 235 + VK_SHADER_STAGE_VERTEX_BIT), 236 + _shader_load(vk, shaders_quad_frag, sizeof(shaders_quad_frag), 237 + VK_SHADER_STAGE_FRAGMENT_BIT), 238 + }; 239 + 240 + VkGraphicsPipelineCreateInfo pipeline_info = { 241 + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, 242 + .layout = self->pipeline_layout, 243 + .pVertexInputState = 244 + &(VkPipelineVertexInputStateCreateInfo){ 245 + .sType = 246 + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 247 + .pVertexAttributeDescriptions = config.attribs, 248 + .vertexBindingDescriptionCount = 1, 249 + .pVertexBindingDescriptions = 250 + &(VkVertexInputBindingDescription){ 251 + .binding = 0, 252 + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, 253 + .stride = config.stride, 254 + }, 255 + .vertexAttributeDescriptionCount = config.attrib_count, 256 + }, 257 + .pInputAssemblyState = 258 + &(VkPipelineInputAssemblyStateCreateInfo){ 259 + .sType = 260 + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 261 + .topology = config.topology, 262 + .primitiveRestartEnable = VK_FALSE, 263 + }, 264 + .pViewportState = 265 + &(VkPipelineViewportStateCreateInfo){ 266 + .sType = 267 + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 268 + .viewportCount = 1, 269 + .scissorCount = 1, 270 + }, 271 + .pRasterizationState = config.rasterization_state, 272 + .pMultisampleState = 273 + &(VkPipelineMultisampleStateCreateInfo){ 274 + .sType = 275 + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, 276 + .rasterizationSamples = self->sample_count, 277 + .minSampleShading = 0.0f, 278 + .pSampleMask = &(uint32_t){0xFFFFFFFF}, 279 + .alphaToCoverageEnable = VK_FALSE, 280 + }, 281 + .pDepthStencilState = config.depth_stencil_state, 282 + .pColorBlendState = 283 + &(VkPipelineColorBlendStateCreateInfo){ 284 + .sType = 285 + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, 286 + .logicOpEnable = VK_FALSE, 287 + .attachmentCount = 1, 288 + .blendConstants = {0, 0, 0, 0}, 289 + .pAttachments = config.blend_attachments, 290 + }, 291 + .stageCount = 2, 292 + .pStages = shader_stages, 293 + .renderPass = self->render_pass, 294 + .pDynamicState = 295 + &(VkPipelineDynamicStateCreateInfo){ 296 + .sType = 297 + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, 298 + .dynamicStateCount = 2, 299 + .pDynamicStates = 300 + (VkDynamicState[]){ 301 + VK_DYNAMIC_STATE_VIEWPORT, 302 + VK_DYNAMIC_STATE_SCISSOR, 303 + }, 304 + }, 305 + .subpass = VK_NULL_HANDLE, 306 + }; 307 + 308 + VkResult res; 309 + res = vk->vkCreateGraphicsPipelines(vk->device, self->pipeline_cache, 1, 310 + &pipeline_info, NULL, 311 + &self->pipeline); 312 + 313 + vk_check_error("vkCreateGraphicsPipelines", res, false); 314 + 315 + vk->vkDestroyShaderModule(vk->device, shader_stages[0].module, NULL); 316 + vk->vkDestroyShaderModule(vk->device, shader_stages[1].module, NULL); 317 + 318 + return true; 319 + } 320 + 321 + // clang-format off 322 + float plane_vertices[6 * 5] = { 323 + -0.5, -0.5, 0, 0, 1, 324 + 0.5, -0.5, 0, 1, 1, 325 + 0.5, 0.5, 0, 1, 0, 326 + 0.5, 0.5, 0, 1, 0, 327 + -0.5, 0.5, 0, 0, 0, 328 + -0.5, -0.5, 0, 0, 1, 329 + }; 330 + // clang-format on 331 + 332 + static bool 333 + _init_vertex_buffer(struct comp_layer_renderer *self) 334 + { 335 + struct vk_bundle *vk = self->vk; 336 + 337 + VkBufferUsageFlags usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; 338 + VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 339 + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; 340 + 341 + if (!vk_buffer_init(vk, sizeof(float) * ARRAY_SIZE(plane_vertices), 342 + usage, properties, &self->vertex_buffer.handle, 343 + &self->vertex_buffer.memory)) 344 + return false; 345 + 346 + self->vertex_buffer.size = 6; 347 + 348 + void *tmp; 349 + VkResult res = vk->vkMapMemory(vk->device, self->vertex_buffer.memory, 350 + 0, VK_WHOLE_SIZE, 0, &tmp); 351 + vk_check_error("vkMapMemory", res, false); 352 + 353 + memcpy(tmp, plane_vertices, sizeof(float) * ARRAY_SIZE(plane_vertices)); 354 + 355 + VkMappedMemoryRange memory_range = { 356 + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 357 + .memory = self->vertex_buffer.memory, 358 + .size = VK_WHOLE_SIZE, 359 + }; 360 + 361 + res = vk->vkFlushMappedMemoryRanges(vk->device, 1, &memory_range); 362 + vk_check_error("vkFlushMappedMemoryRanges", res, false); 363 + 364 + vk->vkUnmapMemory(vk->device, self->vertex_buffer.memory); 365 + 366 + return true; 367 + } 368 + 369 + static void 370 + _render_eye(struct comp_layer_renderer *self, 371 + uint32_t eye, 372 + VkCommandBuffer cmd_buffer, 373 + VkPipelineLayout pipeline_layout) 374 + { 375 + struct xrt_matrix_4x4 vp; 376 + math_matrix_4x4_multiply(&self->mat_projection[eye], 377 + &self->mat_view[eye], &vp); 378 + 379 + for (uint32_t i = 0; i < self->num_layers; i++) 380 + comp_layer_draw(self->layers[i], eye, self->pipeline, 381 + pipeline_layout, cmd_buffer, 382 + &self->vertex_buffer, &vp); 383 + } 384 + 385 + static bool 386 + _init_frame_buffer(struct comp_layer_renderer *self, 387 + VkFormat format, 388 + VkRenderPass rp, 389 + uint32_t eye) 390 + { 391 + struct vk_bundle *vk = self->vk; 392 + 393 + VkImageUsageFlags usage = 394 + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; 395 + 396 + VkResult res = vk_create_image_simple(vk, self->extent, format, usage, 397 + &self->framebuffers[eye].memory, 398 + &self->framebuffers[eye].image); 399 + vk_check_error("vk_create_image_simple", res, false); 400 + 401 + vk_create_sampler(vk, &self->framebuffers[eye].sampler); 402 + 403 + VkImageSubresourceRange subresource_range = { 404 + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 405 + .baseMipLevel = 0, 406 + .levelCount = 1, 407 + .baseArrayLayer = 0, 408 + .layerCount = 1, 409 + }; 410 + 411 + res = vk_create_view(vk, self->framebuffers[eye].image, format, 412 + subresource_range, &self->framebuffers[eye].view); 413 + 414 + vk_check_error("vk_create_view", res, false); 415 + 416 + VkFramebufferCreateInfo framebuffer_info = { 417 + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 418 + .renderPass = rp, 419 + .attachmentCount = 1, 420 + .pAttachments = (VkImageView[]){self->framebuffers[eye].view}, 421 + .width = self->extent.width, 422 + .height = self->extent.height, 423 + .layers = 1, 424 + }; 425 + 426 + res = vk->vkCreateFramebuffer(vk->device, &framebuffer_info, NULL, 427 + &self->framebuffers[eye].handle); 428 + vk_check_error("vkCreateFramebuffer", res, false); 429 + 430 + return true; 431 + } 432 + 433 + void 434 + comp_layer_renderer_allocate_layers(struct comp_layer_renderer *self, 435 + uint32_t num_layers) 436 + { 437 + struct vk_bundle *vk = self->vk; 438 + 439 + self->num_layers = num_layers; 440 + self->layers = 441 + U_TYPED_ARRAY_CALLOC(struct comp_render_layer *, self->num_layers); 442 + 443 + for (uint32_t i = 0; i < self->num_layers; i++) { 444 + self->layers[i] = comp_layer_create( 445 + vk, COMP_LAYER_QUAD, &self->descriptor_set_layout); 446 + } 447 + } 448 + 449 + void 450 + comp_layer_renderer_destroy_layers(struct comp_layer_renderer *self) 451 + { 452 + for (uint32_t i = 0; i < self->num_layers; i++) 453 + comp_layer_destroy(self->layers[i]); 454 + if (self->layers != NULL) 455 + free(self->layers); 456 + self->layers = NULL; 457 + self->num_layers = 0; 458 + } 459 + 460 + static bool 461 + _init(struct comp_layer_renderer *self, 462 + struct vk_bundle *vk, 463 + VkExtent2D extent, 464 + VkFormat format) 465 + { 466 + self->vk = vk; 467 + 468 + self->near = 0.001f; 469 + self->far = 100.0f; 470 + self->sample_count = VK_SAMPLE_COUNT_1_BIT; 471 + 472 + self->num_layers = 0; 473 + 474 + self->extent = extent; 475 + 476 + for (uint32_t i = 0; i < 2; i++) { 477 + math_matrix_4x4_identity(&self->mat_projection[i]); 478 + math_matrix_4x4_identity(&self->mat_view[i]); 479 + } 480 + 481 + if (!_init_render_pass(vk, format, 482 + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 483 + self->sample_count, &self->render_pass)) 484 + return false; 485 + 486 + for (uint32_t i = 0; i < 2; i++) 487 + if (!_init_frame_buffer(self, format, self->render_pass, i)) 488 + return false; 489 + 490 + if (!_init_descriptor_layout(self)) 491 + return false; 492 + if (!_init_pipeline_layout(self)) 493 + return false; 494 + if (!_init_pipeline_cache(self)) 495 + return false; 496 + if (!_init_graphics_pipeline(self)) 497 + return false; 498 + if (!_init_vertex_buffer(self)) 499 + return false; 500 + 501 + return true; 502 + } 503 + 504 + struct comp_layer_renderer * 505 + comp_layer_renderer_create(struct vk_bundle *vk, 506 + VkExtent2D extent, 507 + VkFormat format) 508 + { 509 + struct comp_layer_renderer *r = 510 + U_TYPED_CALLOC(struct comp_layer_renderer); 511 + _init(r, vk, extent, format); 512 + return r; 513 + } 514 + 515 + void 516 + _render_pass_begin(struct vk_bundle *vk, 517 + VkRenderPass render_pass, 518 + VkExtent2D extent, 519 + VkClearColorValue clear_color, 520 + VkFramebuffer frame_buffer, 521 + VkCommandBuffer cmd_buffer) 522 + { 523 + VkRenderPassBeginInfo render_pass_info = { 524 + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 525 + .renderPass = render_pass, 526 + .framebuffer = frame_buffer, 527 + .renderArea = 528 + { 529 + .offset = 530 + { 531 + .x = 0, 532 + .y = 0, 533 + }, 534 + .extent = extent, 535 + }, 536 + .clearValueCount = 1, 537 + .pClearValues = 538 + (VkClearValue[]){ 539 + { 540 + .color = clear_color, 541 + }, 542 + { 543 + .depthStencil = 544 + { 545 + .depth = 1.0f, 546 + .stencil = 0, 547 + }, 548 + }, 549 + }, 550 + }; 551 + 552 + vk->vkCmdBeginRenderPass(cmd_buffer, &render_pass_info, 553 + VK_SUBPASS_CONTENTS_INLINE); 554 + } 555 + 556 + static void 557 + _render_stereo(struct comp_layer_renderer *self, 558 + struct vk_bundle *vk, 559 + VkCommandBuffer cmd_buffer) 560 + { 561 + VkViewport viewport = { 562 + 0.0f, 0.0f, self->extent.width, self->extent.height, 0.0f, 1.0f, 563 + }; 564 + vk->vkCmdSetViewport(cmd_buffer, 0, 1, &viewport); 565 + VkRect2D scissor = { 566 + .offset = {0, 0}, 567 + .extent = self->extent, 568 + }; 569 + vk->vkCmdSetScissor(cmd_buffer, 0, 1, &scissor); 570 + 571 + for (uint32_t eye = 0; eye < 2; eye++) { 572 + _render_pass_begin(vk, self->render_pass, self->extent, 573 + background_color, 574 + self->framebuffers[eye].handle, cmd_buffer); 575 + 576 + _render_eye(self, eye, cmd_buffer, self->pipeline_layout); 577 + 578 + vk->vkCmdEndRenderPass(cmd_buffer); 579 + } 580 + } 581 + 582 + void 583 + comp_layer_renderer_draw(struct comp_layer_renderer *self) 584 + { 585 + struct vk_bundle *vk = self->vk; 586 + 587 + VkCommandBuffer cmd_buffer; 588 + if (vk_init_cmd_buffer(vk, &cmd_buffer) != VK_SUCCESS) 589 + return; 590 + 591 + _render_stereo(self, vk, cmd_buffer); 592 + 593 + VkResult res = vk_submit_cmd_buffer(vk, cmd_buffer); 594 + vk_check_error("vk_submit_cmd_buffer", res, ); 595 + } 596 + 597 + static void 598 + _destroy_framebuffer(struct comp_layer_renderer *self, uint32_t i) 599 + { 600 + struct vk_bundle *vk = self->vk; 601 + vk->vkDestroyImageView(vk->device, self->framebuffers[i].view, NULL); 602 + vk->vkDestroyImage(vk->device, self->framebuffers[i].image, NULL); 603 + vk->vkFreeMemory(vk->device, self->framebuffers[i].memory, NULL); 604 + vk->vkDestroyFramebuffer(vk->device, self->framebuffers[i].handle, 605 + NULL); 606 + vk->vkDestroySampler(vk->device, self->framebuffers[i].sampler, NULL); 607 + } 608 + 609 + void 610 + comp_layer_renderer_destroy(struct comp_layer_renderer *self) 611 + { 612 + struct vk_bundle *vk = self->vk; 613 + 614 + if (vk->device == VK_NULL_HANDLE) 615 + return; 616 + 617 + vk->vkDeviceWaitIdle(vk->device); 618 + 619 + comp_layer_renderer_destroy_layers(self); 620 + 621 + for (uint32_t i = 0; i < 2; i++) 622 + _destroy_framebuffer(self, i); 623 + 624 + vk->vkDestroyRenderPass(vk->device, self->render_pass, NULL); 625 + 626 + vk->vkDestroyPipelineLayout(vk->device, self->pipeline_layout, NULL); 627 + vk->vkDestroyDescriptorSetLayout(vk->device, 628 + self->descriptor_set_layout, NULL); 629 + vk->vkDestroyPipeline(vk->device, self->pipeline, NULL); 630 + 631 + for (uint32_t i = 0; i < ARRAY_SIZE(self->shader_modules); i++) 632 + vk->vkDestroyShaderModule(vk->device, self->shader_modules[i], 633 + NULL); 634 + 635 + vk_buffer_destroy(&self->vertex_buffer, vk); 636 + 637 + vk->vkDestroyPipelineCache(vk->device, self->pipeline_cache, NULL); 638 + } 639 + 640 + void 641 + comp_layer_renderer_set_fov(struct comp_layer_renderer *self, 642 + const struct xrt_fov *fov, 643 + uint32_t view_id) 644 + { 645 + const float tan_left = tanf(fov->angle_left); 646 + const float tan_right = tanf(fov->angle_right); 647 + 648 + const float tan_down = tanf(fov->angle_down); 649 + const float tan_up = tanf(fov->angle_up); 650 + 651 + const float tan_width = tan_right - tan_left; 652 + const float tan_height = tan_up - tan_down; 653 + 654 + const float a11 = 2 / tan_width; 655 + const float a22 = 2 / tan_height; 656 + 657 + const float a31 = (tan_right + tan_left) / tan_width; 658 + const float a32 = (tan_up + tan_down) / tan_height; 659 + const float a33 = -self->far / (self->far - self->near); 660 + 661 + const float a43 = -(self->far * self->near) / (self->far - self->near); 662 + 663 + // clang-format off 664 + self->mat_projection[view_id] = (struct xrt_matrix_4x4) { 665 + .v = { 666 + a11, 0, 0, 0, 667 + 0, a22, 0, 0, 668 + a31, a32, a33, -1, 669 + 0, 0, a43, 0, 670 + } 671 + }; 672 + // clang-format on 673 + } 674 + 675 + void 676 + comp_layer_renderer_set_pose(struct comp_layer_renderer *self, 677 + const struct xrt_pose *pose, 678 + uint32_t view_id) 679 + { 680 + math_matrix_4x4_view_from_pose(pose, &self->mat_view[view_id]); 681 + }
+83
src/xrt/compositor/main/comp_layer_renderer.h
··· 1 + // Copyright 2020, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Compositor quad rendering. 6 + * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 7 + * @ingroup comp_main 8 + */ 9 + 10 + /*! 11 + * Holds associated vulkan objects and state to render quads. 12 + * 13 + * @ingroup comp_main 14 + */ 15 + 16 + #pragma once 17 + 18 + #include "comp_layer.h" 19 + 20 + struct comp_layer_renderer 21 + { 22 + struct vk_bundle *vk; 23 + 24 + struct 25 + { 26 + VkImage image; 27 + VkDeviceMemory memory; 28 + VkImageView view; 29 + VkSampler sampler; 30 + VkFramebuffer handle; 31 + } framebuffers[2]; 32 + 33 + VkRenderPass render_pass; 34 + 35 + VkExtent2D extent; 36 + 37 + VkSampleCountFlagBits sample_count; 38 + 39 + VkShaderModule shader_modules[2]; 40 + VkPipeline pipeline; 41 + VkDescriptorSetLayout descriptor_set_layout; 42 + VkPipelineLayout pipeline_layout; 43 + VkPipelineCache pipeline_cache; 44 + 45 + struct xrt_matrix_4x4 mat_view[2]; 46 + struct xrt_matrix_4x4 mat_projection[2]; 47 + 48 + struct vk_buffer vertex_buffer; 49 + 50 + float near; 51 + float far; 52 + 53 + struct comp_render_layer **layers; 54 + uint32_t num_layers; 55 + }; 56 + 57 + struct comp_layer_renderer * 58 + comp_layer_renderer_create(struct vk_bundle *vk, 59 + VkExtent2D extent, 60 + VkFormat format); 61 + 62 + void 63 + comp_layer_renderer_destroy(struct comp_layer_renderer *self); 64 + 65 + void 66 + comp_layer_renderer_draw(struct comp_layer_renderer *self); 67 + 68 + void 69 + comp_layer_renderer_set_fov(struct comp_layer_renderer *self, 70 + const struct xrt_fov *fov, 71 + uint32_t view_id); 72 + 73 + void 74 + comp_layer_renderer_set_pose(struct comp_layer_renderer *self, 75 + const struct xrt_pose *pose, 76 + uint32_t view_id); 77 + 78 + void 79 + comp_layer_renderer_allocate_layers(struct comp_layer_renderer *self, 80 + uint32_t num_layers); 81 + 82 + void 83 + comp_layer_renderer_destroy_layers(struct comp_layer_renderer *self);
+2
src/xrt/compositor/meson.build
··· 26 26 'main/comp_vk_swapchain.c', 27 27 'main/comp_vk_swapchain.h', 28 28 'main/comp_window.h', 29 + 'main/comp_layer_renderer.c', 30 + 'main/comp_layer.c', 29 31 ] 30 32 31 33 compile_args = []
+2
src/xrt/compositor/shaders/meson.build
··· 5 5 'none.frag', 6 6 'panotools.frag', 7 7 'vive.frag', 8 + 'quad.vert', 9 + 'quad.frag' 8 10 ] 9 11 10 12 shader_headers = []
+18
src/xrt/compositor/shaders/quad.frag
··· 1 + // Copyright 2020 Collabora Ltd. 2 + // Author: Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 3 + // SPDX-License-Identifier: BSL-1.0 4 + 5 + #version 460 6 + 7 + layout (location = 0) in vec2 uv; 8 + 9 + layout (binding = 1) uniform sampler2D image; 10 + 11 + layout (location = 0) out vec4 out_color; 12 + 13 + void main () 14 + { 15 + vec4 texture_color = texture (image, uv); 16 + out_color = texture_color; 17 + } 18 +
+30
src/xrt/compositor/shaders/quad.vert
··· 1 + // Copyright 2020 Collabora Ltd. 2 + // Author: Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 3 + // SPDX-License-Identifier: BSL-1.0 4 + 5 + #version 460 6 + 7 + layout (binding = 0) uniform Transformation { 8 + mat4 mvp; 9 + bool flip_y; 10 + } transformation; 11 + 12 + layout (location = 0) in vec3 position; 13 + layout (location = 1) in vec2 uv; 14 + 15 + layout (location = 0) out vec2 out_uv; 16 + 17 + 18 + out gl_PerVertex { 19 + vec4 gl_Position; 20 + }; 21 + 22 + void main() { 23 + gl_Position = transformation.mvp * vec4 (position, 1.0f); 24 + gl_Position.y = -gl_Position.y; 25 + out_uv = uv; 26 + 27 + if (transformation.flip_y) { 28 + out_uv.y = 1.0 - out_uv.y; 29 + } 30 + }