| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "flutter/vulkan/vulkan_backbuffer.h" |
| |
| #include <limits> |
| |
| #include "flutter/vulkan/vulkan_proc_table.h" |
| #include "third_party/skia/include/gpu/vk/GrVkTypes.h" |
| #include "vulkan/vulkan.h" |
| |
| namespace vulkan { |
| |
| VulkanBackbuffer::VulkanBackbuffer(const VulkanProcTable& p_vk, |
| const VulkanHandle<VkDevice>& device, |
| const VulkanHandle<VkCommandPool>& pool) |
| : vk(p_vk), |
| device_(device), |
| usage_command_buffer_(p_vk, device, pool), |
| render_command_buffer_(p_vk, device, pool), |
| valid_(false) { |
| if (!usage_command_buffer_.IsValid() || !render_command_buffer_.IsValid()) { |
| FML_DLOG(INFO) << "Command buffers were not valid."; |
| return; |
| } |
| |
| if (!CreateSemaphores()) { |
| FML_DLOG(INFO) << "Could not create semaphores."; |
| return; |
| } |
| |
| if (!CreateFences()) { |
| FML_DLOG(INFO) << "Could not create fences."; |
| return; |
| } |
| |
| valid_ = true; |
| } |
| |
| VulkanBackbuffer::~VulkanBackbuffer() { |
| FML_ALLOW_UNUSED_LOCAL(WaitFences()); |
| } |
| |
| bool VulkanBackbuffer::IsValid() const { |
| return valid_; |
| } |
| |
| bool VulkanBackbuffer::CreateSemaphores() { |
| const VkSemaphoreCreateInfo create_info = { |
| .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, |
| .pNext = nullptr, |
| .flags = 0, |
| }; |
| |
| auto semaphore_collect = [this](VkSemaphore semaphore) { |
| vk.DestroySemaphore(device_, semaphore, nullptr); |
| }; |
| |
| for (size_t i = 0; i < semaphores_.size(); i++) { |
| VkSemaphore semaphore = VK_NULL_HANDLE; |
| |
| if (VK_CALL_LOG_ERROR(vk.CreateSemaphore(device_, &create_info, nullptr, |
| &semaphore)) != VK_SUCCESS) { |
| return false; |
| } |
| |
| semaphores_[i] = {semaphore, semaphore_collect}; |
| } |
| |
| return true; |
| } |
| |
| bool VulkanBackbuffer::CreateFences() { |
| const VkFenceCreateInfo create_info = { |
| .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, |
| .pNext = nullptr, |
| .flags = VK_FENCE_CREATE_SIGNALED_BIT, |
| }; |
| |
| auto fence_collect = [this](VkFence fence) { |
| vk.DestroyFence(device_, fence, nullptr); |
| }; |
| |
| for (size_t i = 0; i < use_fences_.size(); i++) { |
| VkFence fence = VK_NULL_HANDLE; |
| |
| if (VK_CALL_LOG_ERROR(vk.CreateFence(device_, &create_info, nullptr, |
| &fence)) != VK_SUCCESS) { |
| return false; |
| } |
| |
| use_fences_[i] = {fence, fence_collect}; |
| } |
| |
| return true; |
| } |
| |
| bool VulkanBackbuffer::WaitFences() { |
| VkFence fences[use_fences_.size()]; |
| |
| for (size_t i = 0; i < use_fences_.size(); i++) { |
| fences[i] = use_fences_[i]; |
| } |
| |
| return VK_CALL_LOG_ERROR(vk.WaitForFences( |
| device_, static_cast<uint32_t>(use_fences_.size()), fences, true, |
| std::numeric_limits<uint64_t>::max())) == VK_SUCCESS; |
| } |
| |
| bool VulkanBackbuffer::ResetFences() { |
| VkFence fences[use_fences_.size()]; |
| |
| for (size_t i = 0; i < use_fences_.size(); i++) { |
| fences[i] = use_fences_[i]; |
| } |
| |
| return VK_CALL_LOG_ERROR(vk.ResetFences( |
| device_, static_cast<uint32_t>(use_fences_.size()), fences)) == |
| VK_SUCCESS; |
| } |
| |
| const VulkanHandle<VkFence>& VulkanBackbuffer::GetUsageFence() const { |
| return use_fences_[0]; |
| } |
| |
| const VulkanHandle<VkFence>& VulkanBackbuffer::GetRenderFence() const { |
| return use_fences_[1]; |
| } |
| |
| const VulkanHandle<VkSemaphore>& VulkanBackbuffer::GetUsageSemaphore() const { |
| return semaphores_[0]; |
| } |
| |
| const VulkanHandle<VkSemaphore>& VulkanBackbuffer::GetRenderSemaphore() const { |
| return semaphores_[1]; |
| } |
| |
| VulkanCommandBuffer& VulkanBackbuffer::GetUsageCommandBuffer() { |
| return usage_command_buffer_; |
| } |
| |
| VulkanCommandBuffer& VulkanBackbuffer::GetRenderCommandBuffer() { |
| return render_command_buffer_; |
| } |
| |
| } // namespace vulkan |