// Copyright 2019-2020, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file * @brief Shared resources for rendering. * @author Lubosz Sarnecki * @author Jakob Bornecrantz * @ingroup comp_main */ #include "main/comp_compositor.h" #include "render/comp_render.h" #include #define C(c) \ do { \ VkResult ret = c; \ if (ret != VK_SUCCESS) { \ return false; \ } \ } while (false) #define D(TYPE, thing) \ if (thing != VK_NULL_HANDLE) { \ vk->vkDestroy##TYPE(vk->device, thing, NULL); \ thing = VK_NULL_HANDLE; \ } static VkResult create_pipeline_cache(struct vk_bundle *vk, VkPipelineCache *out_pipeline_cache) { VkResult ret; VkPipelineCacheCreateInfo pipeline_cache_info = { .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, }; VkPipelineCache pipeline_cache; ret = vk->vkCreatePipelineCache(vk->device, // &pipeline_cache_info, // NULL, // &pipeline_cache); // if (ret != VK_SUCCESS) { VK_ERROR(vk, "vkCreatePipelineCache failed: %s", vk_result_string(ret)); return ret; } *out_pipeline_cache = pipeline_cache; return VK_SUCCESS; } static VkResult create_pipeline_layout(struct vk_bundle *vk, VkDescriptorSetLayout descriptor_set_layout, VkPipelineLayout *out_pipeline_layout) { VkResult ret; VkPipelineLayoutCreateInfo pipeline_layout_info = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .setLayoutCount = 1, .pSetLayouts = &descriptor_set_layout, }; VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; ret = vk->vkCreatePipelineLayout(vk->device, // &pipeline_layout_info, // NULL, // &pipeline_layout); // if (ret != VK_SUCCESS) { VK_ERROR(vk, "vkCreatePipelineLayout failed: %s", vk_result_string(ret)); return ret; } *out_pipeline_layout = pipeline_layout; return VK_SUCCESS; } static VkResult create_descriptor_pool(struct vk_bundle *vk, uint32_t num_uniform_per_desc, uint32_t num_sampler_per_desc, uint32_t num_storage_per_desc, uint32_t num_descs, bool freeable, VkDescriptorPool *out_descriptor_pool) { VkResult ret; uint32_t count = 0; VkDescriptorPoolSize pool_sizes[3] = {0}; if (num_uniform_per_desc > 0) { pool_sizes[count].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; pool_sizes[count].descriptorCount = num_uniform_per_desc * num_descs; count++; } if (num_sampler_per_desc > 0) { pool_sizes[count].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; pool_sizes[count].descriptorCount = num_sampler_per_desc * num_descs; count++; } if (num_storage_per_desc > 0) { pool_sizes[count].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; pool_sizes[count].descriptorCount = num_storage_per_desc * num_descs; count++; } assert(count > 0 && count <= ARRAY_SIZE(pool_sizes)); VkDescriptorPoolCreateFlags flags = 0; if (freeable) { flags |= VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; } VkDescriptorPoolCreateInfo descriptor_pool_info = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, .flags = flags, .maxSets = num_descs, .poolSizeCount = count, .pPoolSizes = pool_sizes, }; VkDescriptorPool descriptor_pool = VK_NULL_HANDLE; ret = vk->vkCreateDescriptorPool(vk->device, // &descriptor_pool_info, // NULL, // &descriptor_pool); // if (ret != VK_SUCCESS) { VK_ERROR(vk, "vkCreateRenderPass failed: %s", vk_result_string(ret)); return ret; } *out_descriptor_pool = descriptor_pool; return VK_SUCCESS; } /* * * Mesh * */ static VkResult create_mesh_descriptor_set_layout(struct vk_bundle *vk, uint32_t src_binding, uint32_t ubo_binding, VkDescriptorSetLayout *out_descriptor_set_layout) { VkResult ret; VkDescriptorSetLayoutBinding set_layout_bindings[2] = { { .binding = src_binding, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorCount = 1, .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, }, { .binding = ubo_binding, .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = 1, .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, }, }; VkDescriptorSetLayoutCreateInfo set_layout_info = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, .bindingCount = ARRAY_SIZE(set_layout_bindings), .pBindings = set_layout_bindings, }; VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE; ret = vk->vkCreateDescriptorSetLayout(vk->device, // &set_layout_info, // NULL, // &descriptor_set_layout); // if (ret != VK_SUCCESS) { VK_ERROR(vk, "vkCreateDescriptorSetLayout failed: %s", vk_result_string(ret)); return ret; } *out_descriptor_set_layout = descriptor_set_layout; return VK_SUCCESS; } static bool init_mesh_vertex_buffers(struct vk_bundle *vk, struct comp_buffer *vbo, struct comp_buffer *ibo, uint32_t num_vertices, uint32_t stride, void *vertices, uint32_t num_indices, void *indices) { // Using the same flags for all vbos. VkBufferUsageFlags vbo_usage_flags = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; VkBufferUsageFlags ibo_usage_flags = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; VkMemoryPropertyFlags memory_property_flags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; // Distortion vbo and ibo sizes. VkDeviceSize vbo_size = stride * num_vertices; VkDeviceSize ibo_size = sizeof(int) * num_indices; // Don't create vbo if size is zero. if (vbo_size == 0) { return true; } C(comp_buffer_init(vk, // vk_bundle vbo, // buffer vbo_usage_flags, // usage_flags memory_property_flags, // memory_property_flags vbo_size)); // size C(comp_buffer_write(vk, // vk_bundle vbo, // buffer vertices, // data vbo_size)); // size // Don't create index buffer if size is zero. if (ibo_size == 0) { return true; } C(comp_buffer_init(vk, // vk_bundle ibo, // buffer ibo_usage_flags, // usage_flags memory_property_flags, // memory_property_flags ibo_size)); // size C(comp_buffer_write(vk, // vk_bundle ibo, // buffer indices, // data ibo_size)); // size return true; } /* * * 'Exported' renderer functions. * */ bool comp_resources_init(struct comp_compositor *c, struct comp_resources *r) { struct vk_bundle *vk = &c->vk; struct xrt_device *xdev = c->xdev; /* * Constants */ r->mesh.src_binding = 0; r->mesh.ubo_binding = 1; struct xrt_hmd_parts *parts = xdev->hmd; r->mesh.num_vertices = parts->distortion.mesh.num_vertices; r->mesh.stride = parts->distortion.mesh.stride; r->mesh.num_indices[0] = parts->distortion.mesh.num_indices[0]; r->mesh.num_indices[1] = parts->distortion.mesh.num_indices[1]; r->mesh.total_num_indices = parts->distortion.mesh.total_num_indices; r->mesh.offset_indices[0] = parts->distortion.mesh.offset_indices[0]; r->mesh.offset_indices[1] = parts->distortion.mesh.offset_indices[1]; /* * Shared */ C(create_pipeline_cache(vk, &r->pipeline_cache)); /* * Mesh static. */ C(create_descriptor_pool(vk, // vk_bundle 1, // num_uniform_per_desc 1, // num_sampler_per_desc 0, // num_storage_per_desc 16 * 2, // num_descs true, // freeable &r->mesh_descriptor_pool)); // out_descriptor_pool C(create_mesh_descriptor_set_layout(vk, // vk_bundle r->mesh.src_binding, // src_binding r->mesh.ubo_binding, // ubo_binding &r->mesh.descriptor_set_layout)); // out_mesh_descriptor_set_layout C(create_pipeline_layout(vk, // vk_bundle r->mesh.descriptor_set_layout, // descriptor_set_layout &r->mesh.pipeline_layout)); // out_pipeline_layout if (!init_mesh_vertex_buffers(vk, // &r->mesh.vbo, // &r->mesh.ibo, // r->mesh.num_vertices, // r->mesh.stride, // parts->distortion.mesh.vertices, // r->mesh.total_num_indices, // parts->distortion.mesh.indices)) { // return false; } /* * Done */ U_LOG_I("New renderer initialized!"); return true; } void comp_resources_close(struct comp_compositor *c, struct comp_resources *r) { struct vk_bundle *vk = &c->vk; D(DescriptorSetLayout, r->mesh.descriptor_set_layout); D(PipelineLayout, r->mesh.pipeline_layout); D(PipelineCache, r->pipeline_cache); D(DescriptorPool, r->mesh_descriptor_pool); comp_buffer_close(vk, &r->mesh.vbo); comp_buffer_close(vk, &r->mesh.ibo); }