summaryrefslogtreecommitdiff
path: root/chromium/gpu/vulkan/vulkan_swap_chain.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/gpu/vulkan/vulkan_swap_chain.cc')
-rw-r--r--chromium/gpu/vulkan/vulkan_swap_chain.cc418
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(