diff options
Diffstat (limited to 'chromium/gpu/vulkan/vulkan_swap_chain.cc')
-rw-r--r-- | chromium/gpu/vulkan/vulkan_swap_chain.cc | 418 |
1 files changed, 254 insertions, 164 deletions
diff --git a/chromium/gpu/vulkan/vulkan_swap_chain.cc b/chromium/gpu/vulkan/vulkan_swap_chain.cc index c88b19f8ded..4d7eede7033 100644 --- a/chromium/gpu/vulkan/vulkan_swap_chain.cc +++ b/chromium/gpu/vulkan/vulkan_swap_chain.cc @@ -5,6 +5,11 @@ #include "gpu/vulkan/vulkan_swap_chain.h" #include "base/bind.h" +#include "base/logging.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" +#include "base/threading/scoped_blocking_call.h" +#include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "gpu/vulkan/vulkan_command_buffer.h" #include "gpu/vulkan/vulkan_command_pool.h" @@ -17,7 +22,7 @@ namespace { VkSemaphore CreateSemaphore(VkDevice vk_device) { // Generic semaphore creation structure. - VkSemaphoreCreateInfo semaphore_create_info = { + constexpr VkSemaphoreCreateInfo semaphore_create_info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; VkSemaphore vk_semaphore; @@ -30,11 +35,17 @@ VkSemaphore CreateSemaphore(VkDevice vk_device) { } // namespace -VulkanSwapChain::VulkanSwapChain() {} +VulkanSwapChain::VulkanSwapChain() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +} VulkanSwapChain::~VulkanSwapChain() { +#if DCHECK_IS_ON() + base::AutoLock auto_lock(lock_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(images_.empty()); DCHECK_EQ(static_cast<VkSwapchainKHR>(VK_NULL_HANDLE), swap_chain_); +#endif } bool VulkanSwapChain::Initialize( @@ -46,8 +57,12 @@ bool VulkanSwapChain::Initialize( VkSurfaceTransformFlagBitsKHR pre_transform, bool use_protected_memory, std::unique_ptr<VulkanSwapChain> old_swap_chain) { + base::AutoLock auto_lock(lock_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(device_queue); DCHECK(!use_protected_memory || device_queue->allow_protected_memory()); + + task_runner_ = base::ThreadTaskRunnerHandle::Get(); use_protected_memory_ = use_protected_memory; device_queue_ = device_queue; is_incremental_present_supported_ = @@ -57,100 +72,67 @@ bool VulkanSwapChain::Initialize( return InitializeSwapChain(surface, surface_format, image_size, min_image_count, pre_transform, use_protected_memory, std::move(old_swap_chain)) && - InitializeSwapImages(surface_format); + InitializeSwapImages(surface_format) && AcquireNextImage(); } void VulkanSwapChain::Destroy() { + base::AutoLock auto_lock(lock_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + WaitUntilPostSubBufferAsyncFinished(); + DCHECK(!is_writing_); DestroySwapImages(); DestroySwapChain(); } -gfx::SwapResult VulkanSwapChain::PresentBuffer(const gfx::Rect& rect) { - DCHECK(acquired_image_); - DCHECK(end_write_semaphore_ != VK_NULL_HANDLE); - - VkResult result = VK_SUCCESS; - VkDevice device = device_queue_->GetVulkanDevice(); - VkQueue queue = device_queue_->GetVulkanQueue(); - auto* fence_helper = device_queue_->GetFenceHelper(); - - auto& current_image_data = images_[*acquired_image_]; - if (current_image_data.layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) { - { - current_image_data.command_buffer->Clear(); - ScopedSingleUseCommandBufferRecorder recorder( - *current_image_data.command_buffer); - current_image_data.command_buffer->TransitionImageLayout( - current_image_data.image, current_image_data.layout, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - } - current_image_data.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - VkSemaphore vk_semaphore = CreateSemaphore(device); - // Submit our command_buffer for the current buffer. It sets the image - // layout for presenting. - if (!current_image_data.command_buffer->Submit(1, &end_write_semaphore_, 1, - &vk_semaphore)) { - vkDestroySemaphore(device, vk_semaphore, nullptr /* pAllocator */); - return gfx::SwapResult::SWAP_FAILED; - } - current_image_data.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - fence_helper->EnqueueSemaphoreCleanupForSubmittedWork(end_write_semaphore_); - end_write_semaphore_ = vk_semaphore; - } - - VkPresentInfoKHR present_info = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR}; - present_info.waitSemaphoreCount = 1; - present_info.pWaitSemaphores = &end_write_semaphore_; - present_info.swapchainCount = 1; - present_info.pSwapchains = &swap_chain_; - present_info.pImageIndices = &acquired_image_.value(); - - VkRectLayerKHR rect_layer; - VkPresentRegionKHR present_region; - VkPresentRegionsKHR present_regions = {VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR}; - if (is_incremental_present_supported_) { - rect_layer.offset = {rect.x(), rect.y()}; - rect_layer.extent = {rect.width(), rect.height()}; - rect_layer.layer = 0; +gfx::SwapResult VulkanSwapChain::PostSubBuffer(const gfx::Rect& rect) { + base::AutoLock auto_lock(lock_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!has_pending_post_sub_buffer_); - present_region.rectangleCount = 1; - present_region.pRectangles = &rect_layer; - - present_regions.swapchainCount = 1; - present_regions.pRegions = &present_region; - - present_info.pNext = &present_regions; - } + if (!PresentBuffer(rect)) + return gfx::SwapResult::SWAP_FAILED; - result = vkQueuePresentKHR(queue, &present_info); - if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { - LOG(DFATAL) << "vkQueuePresentKHR() failed: " << result; + if (!AcquireNextImage()) return gfx::SwapResult::SWAP_FAILED; - } - current_image_data.is_acquired = false; - LOG_IF(ERROR, result == VK_SUBOPTIMAL_KHR) << "Swapchian is suboptimal."; + return gfx::SwapResult::SWAP_ACK; +} - if (current_image_data.present_begin_semaphore != VK_NULL_HANDLE) { - // |present_begin_semaphore| for the previous present for this image can be - // safely destroyed after semaphore got from vkAcquireNextImageHKR() is - // passed. That acquired semaphore should be already waited on for a - // submitted GPU work. So we can safely enqueue the - // |present_begin_semaphore| for cleanup here (the enqueued semaphore will - // be destroyed when all submitted GPU work is finished). - fence_helper->EnqueueSemaphoreCleanupForSubmittedWork( - current_image_data.present_begin_semaphore); +void VulkanSwapChain::PostSubBufferAsync( + const gfx::Rect& rect, + PostSubBufferCompletionCallback callback) { + base::AutoLock auto_lock(lock_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!has_pending_post_sub_buffer_); + + if (!PresentBuffer(rect)) { + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), gfx::SwapResult::SWAP_FAILED)); + return; } - // We are not sure when the semaphore is not used by present engine, so don't - // destroy the semaphore until the image is returned from present engine. - current_image_data.present_begin_semaphore = end_write_semaphore_; - end_write_semaphore_ = VK_NULL_HANDLE; - in_present_images_.emplace_back(*acquired_image_); - acquired_image_.reset(); - return gfx::SwapResult::SWAP_ACK; + DCHECK_EQ(state_, VK_SUCCESS); + + has_pending_post_sub_buffer_ = true; + + post_sub_buffer_task_runner_->PostTask( + FROM_HERE, + base::BindOnce( + [](VulkanSwapChain* self, PostSubBufferCompletionCallback callback) { + base::AutoLock auto_lock(self->lock_); + DCHECK(self->has_pending_post_sub_buffer_); + auto swap_result = self->AcquireNextImage() + ? gfx::SwapResult::SWAP_ACK + : gfx::SwapResult::SWAP_FAILED; + self->task_runner_->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), swap_result)); + self->has_pending_post_sub_buffer_ = false; + self->condition_variable_.Signal(); + }, + base::Unretained(this), std::move(callback))); } bool VulkanSwapChain::InitializeSwapChain( @@ -161,29 +143,35 @@ bool VulkanSwapChain::InitializeSwapChain( VkSurfaceTransformFlagBitsKHR pre_transform, bool use_protected_memory, std::unique_ptr<VulkanSwapChain> old_swap_chain) { - DCHECK(!acquired_image_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + VkDevice device = device_queue_->GetVulkanDevice(); VkResult result = VK_SUCCESS; - VkSwapchainCreateInfoKHR swap_chain_create_info = {}; - swap_chain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swap_chain_create_info.flags = - use_protected_memory ? VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR : 0; - swap_chain_create_info.surface = surface; - swap_chain_create_info.minImageCount = min_image_count, - swap_chain_create_info.imageFormat = surface_format.format; - swap_chain_create_info.imageColorSpace = surface_format.colorSpace; - swap_chain_create_info.imageExtent.width = image_size.width(); - swap_chain_create_info.imageExtent.height = image_size.height(); - swap_chain_create_info.imageArrayLayers = 1; - swap_chain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - swap_chain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swap_chain_create_info.preTransform = pre_transform; - swap_chain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swap_chain_create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; - swap_chain_create_info.clipped = true; - swap_chain_create_info.oldSwapchain = - old_swap_chain ? old_swap_chain->swap_chain_ : VK_NULL_HANDLE; + VkSwapchainCreateInfoKHR swap_chain_create_info = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .flags = use_protected_memory ? VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR : 0, + .surface = surface, + .minImageCount = min_image_count, + .imageFormat = surface_format.format, + .imageColorSpace = surface_format.colorSpace, + .imageExtent = {image_size.width(), image_size.height()}, + .imageArrayLayers = 1, + .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, + .preTransform = pre_transform, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = VK_PRESENT_MODE_FIFO_KHR, + .clipped = VK_TRUE, + .oldSwapchain = VK_NULL_HANDLE, + }; + if (old_swap_chain) { + base::AutoLock auto_lock(old_swap_chain->lock_); + old_swap_chain->WaitUntilPostSubBufferAsyncFinished(); + swap_chain_create_info.oldSwapchain = old_swap_chain->swap_chain_; + // Reuse |post_sub_buffer_task_runner_| from the |old_swap_chain|. + post_sub_buffer_task_runner_ = old_swap_chain->post_sub_buffer_task_runner_; + } VkSwapchainKHR new_swap_chain = VK_NULL_HANDLE; result = vkCreateSwapchainKHR(device, &swap_chain_create_info, nullptr, @@ -204,10 +192,18 @@ bool VulkanSwapChain::InitializeSwapChain( size_ = gfx::Size(swap_chain_create_info.imageExtent.width, swap_chain_create_info.imageExtent.height); + if (!post_sub_buffer_task_runner_) { + post_sub_buffer_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner( + {base::TaskPriority::USER_BLOCKING, + base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()}); + } + return true; } void VulkanSwapChain::DestroySwapChain() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (swap_chain_ == VK_NULL_HANDLE) return; vkDestroySwapchainKHR(device_queue_->GetVulkanDevice(), swap_chain_, @@ -217,6 +213,8 @@ void VulkanSwapChain::DestroySwapChain() { bool VulkanSwapChain::InitializeSwapImages( const VkSurfaceFormatKHR& surface_format) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + VkDevice device = device_queue_->GetVulkanDevice(); VkResult result = VK_SUCCESS; @@ -250,6 +248,8 @@ bool VulkanSwapChain::InitializeSwapImages( } void VulkanSwapChain::DestroySwapImages() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (end_write_semaphore_) vkDestroySemaphore(device_queue_->GetVulkanDevice(), end_write_semaphore_, nullptr /* pAllocator */); @@ -281,30 +281,38 @@ bool VulkanSwapChain::BeginWriteCurrentImage(VkImage* image, uint32_t* image_index, VkImageLayout* image_layout, VkSemaphore* semaphore) { + base::AutoLock auto_lock(lock_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(image); DCHECK(image_index); DCHECK(image_layout); DCHECK(semaphore); DCHECK(!is_writing_); - VkSemaphore vk_semaphore = VK_NULL_HANDLE; + if (state_ != VK_SUCCESS) + return false; + + if (!acquired_image_) + return false; + + auto& current_image_data = images_[*acquired_image_]; - if (!acquired_image_) { + VkSemaphore vk_semaphore = VK_NULL_HANDLE; + if (current_image_data.present_end_semaphore != VK_NULL_HANDLE) { DCHECK(end_write_semaphore_ == VK_NULL_HANDLE); - if (!AcquireNextImage()) - return false; - DCHECK(acquired_image_); - std::swap(vk_semaphore, images_[*acquired_image_].present_end_semaphore); + vk_semaphore = current_image_data.present_end_semaphore; + current_image_data.present_end_semaphore = VK_NULL_HANDLE; } else { - // In this case, PresentBuffer() is not called after + DCHECK(end_write_semaphore_ != VK_NULL_HANDLE); + // In this case, PostSubBuffer() is not called after // {Begin,End}WriteCurrentImage pairs, |end_write_semaphore_| should be // waited on before writing the image again. - std::swap(vk_semaphore, end_write_semaphore_); + vk_semaphore = end_write_semaphore_; + end_write_semaphore_ = VK_NULL_HANDLE; } - auto& current_image_data = images_[*acquired_image_]; *image = current_image_data.image; - *image_index = acquired_image_.value(); + *image_index = *acquired_image_; *image_layout = current_image_data.layout; *semaphore = vk_semaphore; is_writing_ = true; @@ -314,6 +322,8 @@ bool VulkanSwapChain::BeginWriteCurrentImage(VkImage* image, void VulkanSwapChain::EndWriteCurrentImage(VkImageLayout image_layout, VkSemaphore semaphore) { + base::AutoLock auto_lock(lock_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(is_writing_); DCHECK(acquired_image_); DCHECK(end_write_semaphore_ == VK_NULL_HANDLE); @@ -324,29 +334,107 @@ void VulkanSwapChain::EndWriteCurrentImage(VkImageLayout image_layout, is_writing_ = false; } -bool VulkanSwapChain::AcquireNextImage() { - DCHECK(!acquired_image_); +bool VulkanSwapChain::PresentBuffer(const gfx::Rect& rect) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK_EQ(state_, VK_SUCCESS); + DCHECK(acquired_image_); + DCHECK(end_write_semaphore_ != VK_NULL_HANDLE); + + VkResult result = VK_SUCCESS; VkDevice device = device_queue_->GetVulkanDevice(); - // The Vulkan spec doesn't require vkAcquireNextImageKHR() returns images in - // the present order for a vulkan swap chain. However for the best - // performance, the driver should return images in order. To avoid buggy - // drivers, we will call vkAcquireNextImageKHR() continually until the - // expected image is returned. - do { - bool all_images_are_tracked = in_present_images_.size() == images_.size(); - if (all_images_are_tracked) { - // Only check the expected_next_image, when all images are tracked. - uint32_t expected_next_image = in_present_images_.front(); - // If the expected next image has been acquired, use it and return true. - if (images_[expected_next_image].is_acquired) { - in_present_images_.pop_front(); - acquired_image_.emplace(expected_next_image); - break; - } + VkQueue queue = device_queue_->GetVulkanQueue(); + auto* fence_helper = device_queue_->GetFenceHelper(); + + auto& current_image_data = images_[*acquired_image_]; + if (current_image_data.layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) { + { + current_image_data.command_buffer->Clear(); + ScopedSingleUseCommandBufferRecorder recorder( + *current_image_data.command_buffer); + current_image_data.command_buffer->TransitionImageLayout( + current_image_data.image, current_image_data.layout, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } + current_image_data.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; VkSemaphore vk_semaphore = CreateSemaphore(device); - DCHECK(vk_semaphore != VK_NULL_HANDLE); + // Submit our command_buffer for the current buffer. It sets the image + // layout for presenting. + if (!current_image_data.command_buffer->Submit(1, &end_write_semaphore_, 1, + &vk_semaphore)) { + vkDestroySemaphore(device, vk_semaphore, nullptr /* pAllocator */); + return false; + } + current_image_data.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + fence_helper->EnqueueSemaphoreCleanupForSubmittedWork(end_write_semaphore_); + end_write_semaphore_ = vk_semaphore; + } + + VkPresentInfoKHR present_info = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR}; + present_info.waitSemaphoreCount = 1; + present_info.pWaitSemaphores = &end_write_semaphore_; + present_info.swapchainCount = 1; + present_info.pSwapchains = &swap_chain_; + present_info.pImageIndices = &acquired_image_.value(); + + VkRectLayerKHR rect_layer; + VkPresentRegionKHR present_region; + VkPresentRegionsKHR present_regions = {VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR}; + if (is_incremental_present_supported_) { + rect_layer.offset = {rect.x(), rect.y()}; + rect_layer.extent = {rect.width(), rect.height()}; + rect_layer.layer = 0; + + present_region.rectangleCount = 1; + present_region.pRectangles = &rect_layer; + + present_regions.swapchainCount = 1; + present_regions.pRegions = &present_region; + + present_info.pNext = &present_regions; + } + + result = vkQueuePresentKHR(queue, &present_info); + if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { + LOG(DFATAL) << "vkQueuePresentKHR() failed: " << result; + state_ = result; + return false; + } + + LOG_IF(ERROR, result == VK_SUBOPTIMAL_KHR) << "Swapchian is suboptimal."; + + if (current_image_data.present_begin_semaphore != VK_NULL_HANDLE) { + // |present_begin_semaphore| for the previous present for this image can be + // safely destroyed after semaphore got from vkAcquireNextImageHKR() is + // passed. That acquired semaphore should be already waited on for a + // submitted GPU work. So we can safely enqueue the + // |present_begin_semaphore| for cleanup here (the enqueued semaphore will + // be destroyed when all submitted GPU work is finished). + fence_helper->EnqueueSemaphoreCleanupForSubmittedWork( + current_image_data.present_begin_semaphore); + } + // We are not sure when the semaphore is not used by present engine, so don't + // destroy the semaphore until the image is returned from present engine. + current_image_data.present_begin_semaphore = end_write_semaphore_; + end_write_semaphore_ = VK_NULL_HANDLE; + + acquired_image_.reset(); + + return true; +} + +bool VulkanSwapChain::AcquireNextImage() { + DCHECK_EQ(state_, VK_SUCCESS); + DCHECK(!acquired_image_); + + // VulkanDeviceQueue is not threadsafe for now, but |device_queue_| will not + // be released, and device_queue_->device will never be changed after + // initialization, so it is safe for now. + // TODO(penghuang): make VulkanDeviceQueue threadsafe. + VkDevice device = device_queue_->GetVulkanDevice(); + + VkSemaphore vk_semaphore = CreateSemaphore(device); + DCHECK(vk_semaphore != VK_NULL_HANDLE); #if defined(USE_X11) // The xserver should still composite windows with a 1Hz fake vblank when @@ -361,44 +449,46 @@ bool VulkanSwapChain::AcquireNextImage() { #else constexpr uint64_t kTimeout = UINT64_MAX; #endif - // Acquire the next image. - uint32_t next_image; - auto result = - vkAcquireNextImageKHR(device, swap_chain_, kTimeout, vk_semaphore, - VK_NULL_HANDLE, &next_image); - if (result == VK_TIMEOUT) { - LOG(ERROR) << "vkAcquireNextImageKHR() hangs."; - vkDestroySemaphore(device, vk_semaphore, nullptr /* pAllocator */); - state_ = VK_ERROR_SURFACE_LOST_KHR; - return false; - } - if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { - LOG(DFATAL) << "vkAcquireNextImageKHR() failed: " << result; - vkDestroySemaphore(device, vk_semaphore, nullptr /* pAllocator */); - state_ = result; - return false; - } + // Acquire the next image. + uint32_t next_image; + auto result = ({ + base::ScopedBlockingCall scoped_blocking_call( + FROM_HERE, base::BlockingType::WILL_BLOCK); + vkAcquireNextImageKHR(device, swap_chain_, kTimeout, vk_semaphore, + VK_NULL_HANDLE, &next_image); + }); + + if (result == VK_TIMEOUT) { + LOG(ERROR) << "vkAcquireNextImageKHR() hangs."; + vkDestroySemaphore(device, vk_semaphore, nullptr /* pAllocator */); + state_ = VK_ERROR_SURFACE_LOST_KHR; + return false; + } - DCHECK(!images_[next_image].is_acquired); - DCHECK(images_[next_image].present_end_semaphore == VK_NULL_HANDLE); - images_[next_image].is_acquired = true; - images_[next_image].present_end_semaphore = vk_semaphore; - - auto it = std::find(in_present_images_.begin(), in_present_images_.end(), - next_image); - if (it == in_present_images_.end()) { - DCHECK(!all_images_are_tracked); - // Got an image which is not in the present queue due to the new created - // swap chain. In this case, just use this image. - acquired_image_.emplace(next_image); - break; - } - LOG_IF(ERROR, it != in_present_images_.begin()) - << "vkAcquireNextImageKHR() returned an unexpected image."; - } while (true); + if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { + LOG(DFATAL) << "vkAcquireNextImageKHR() failed: " << result; + vkDestroySemaphore(device, vk_semaphore, nullptr /* pAllocator */); + state_ = result; + return false; + } + + DCHECK(images_[next_image].present_end_semaphore == VK_NULL_HANDLE); + images_[next_image].present_end_semaphore = vk_semaphore; + acquired_image_.emplace(next_image); return true; } +void VulkanSwapChain::WaitUntilPostSubBufferAsyncFinished() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + while (has_pending_post_sub_buffer_) { + base::ScopedBlockingCall scoped_blocking_call( + FROM_HERE, base::BlockingType::WILL_BLOCK); + condition_variable_.Wait(); + } + DCHECK(acquired_image_ || state_ != VK_SUCCESS); +} + VulkanSwapChain::ScopedWrite::ScopedWrite(VulkanSwapChain* swap_chain) : swap_chain_(swap_chain) { success_ = swap_chain_->BeginWriteCurrentImage( |