blob: 81814679ef67ea8bc732f7d012dda0cc7b893d2d [file] [log] [blame]
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GPU_VULKAN_VULKAN_SWAP_CHAIN_H_
#define GPU_VULKAN_VULKAN_SWAP_CHAIN_H_
#include <vulkan/vulkan.h>
#include <memory>
#include <vector>
#include "base/callback.h"
#include "base/component_export.h"
#include "base/containers/circular_deque.h"
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/swap_result.h"
namespace base {
class SingleThreadTaskRunner;
}
namespace gpu {
class VulkanCommandBuffer;
class VulkanCommandPool;
class VulkanDeviceQueue;
class COMPONENT_EXPORT(VULKAN) VulkanSwapChain {
public:
class COMPONENT_EXPORT(VULKAN) ScopedWrite {
public:
explicit ScopedWrite(VulkanSwapChain* swap_chain);
~ScopedWrite();
bool success() const { return success_; }
VkImage image() const { return image_; }
uint32_t image_index() const { return image_index_; }
VkImageLayout image_layout() const { return image_layout_; }
void set_image_layout(VkImageLayout layout) { image_layout_ = layout; }
// Take the begin write semaphore. The ownership of the semaphore will be
// transferred to the caller.
VkSemaphore TakeBeginSemaphore();
// Get the end write semaphore.
VkSemaphore GetEndSemaphore();
private:
VulkanSwapChain* const swap_chain_;
bool success_ = false;
VkImage image_ = VK_NULL_HANDLE;
uint32_t image_index_ = 0;
VkImageLayout image_layout_ = VK_IMAGE_LAYOUT_UNDEFINED;
VkSemaphore begin_semaphore_ = VK_NULL_HANDLE;
VkSemaphore end_semaphore_ = VK_NULL_HANDLE;
DISALLOW_COPY_AND_ASSIGN(ScopedWrite);
};
VulkanSwapChain();
~VulkanSwapChain();
// min_image_count is the minimum number of presentable images.
bool Initialize(VulkanDeviceQueue* device_queue,
VkSurfaceKHR surface,
const VkSurfaceFormatKHR& surface_format,
const gfx::Size& image_size,
uint32_t min_image_count,
VkSurfaceTransformFlagBitsKHR pre_transform,
bool use_protected_memory,
std::unique_ptr<VulkanSwapChain> old_swap_chain);
// Destroy() should be called when all related GPU tasks have been finished.
void Destroy();
// Present the current buffer.
gfx::SwapResult PostSubBuffer(const gfx::Rect& rect);
using PostSubBufferCompletionCallback =
base::OnceCallback<void(gfx::SwapResult)>;
void PostSubBufferAsync(const gfx::Rect& rect,
PostSubBufferCompletionCallback callback);
uint32_t num_images() const {
// size of |images_| will not be changed after initializing, so it is safe
// to read it here.
return static_cast<uint32_t>(TS_UNCHECKED_READ(images_).size());
}
const gfx::Size& size() const {
// |size_| is never changed after initialization.
return size_;
}
bool use_protected_memory() const {
// |use_protected_memory_| is never changed after initialization.
return use_protected_memory_;
}
VkResult state() const {
base::AutoLock auto_lock(lock_);
return state_;
}
private:
bool InitializeSwapChain(VkSurfaceKHR surface,
const VkSurfaceFormatKHR& surface_format,
const gfx::Size& image_size,
uint32_t min_image_count,
VkSurfaceTransformFlagBitsKHR pre_transform,
bool use_protected_memory,
std::unique_ptr<VulkanSwapChain> old_swap_chain)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void DestroySwapChain() EXCLUSIVE_LOCKS_REQUIRED(lock_);
bool InitializeSwapImages(const VkSurfaceFormatKHR& surface_format)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void DestroySwapImages() EXCLUSIVE_LOCKS_REQUIRED(lock_);
bool BeginWriteCurrentImage(VkImage* image,
uint32_t* image_index,
VkImageLayout* layout,
VkSemaphore* semaphore);
void EndWriteCurrentImage(VkImageLayout layout, VkSemaphore semaphore);
bool PresentBuffer(const gfx::Rect& rect) EXCLUSIVE_LOCKS_REQUIRED(lock_);
bool AcquireNextImage() EXCLUSIVE_LOCKS_REQUIRED(lock_);
// Wait until PostSubBufferAsync() is finished on ThreadPool.
void WaitUntilPostSubBufferAsyncFinished() EXCLUSIVE_LOCKS_REQUIRED(lock_);
mutable base::Lock lock_;
bool use_protected_memory_ = false;
VulkanDeviceQueue* device_queue_ = nullptr;
bool is_incremental_present_supported_ = false;
VkSwapchainKHR swap_chain_ GUARDED_BY(lock_) = VK_NULL_HANDLE;
std::unique_ptr<VulkanCommandPool> command_pool_;
gfx::Size size_;
struct ImageData {
ImageData();
ImageData(ImageData&& other);
~ImageData();
ImageData& operator=(ImageData&& other);
VkImage image = VK_NULL_HANDLE;
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
std::unique_ptr<VulkanCommandBuffer> command_buffer;
// Semaphore passed to vkQueuePresentKHR to wait on.
VkSemaphore present_begin_semaphore = VK_NULL_HANDLE;
// Semaphore signaled when present engine is done with the image.
VkSemaphore present_end_semaphore = VK_NULL_HANDLE;
// True indicates the image is acquired from swapchain and haven't sent back
// to swapchain for presenting.
bool is_acquired = false;
};
// Images in the swap chain.
std::vector<ImageData> images_ GUARDED_BY(lock_);
base::circular_deque<uint32_t> in_present_images_ GUARDED_BY(lock_);
bool is_writing_ GUARDED_BY(lock_) = false;
VkSemaphore end_write_semaphore_ GUARDED_BY(lock_) = VK_NULL_HANDLE;
// Condition variable is signalled when a PostSubBufferAsync() is finished.
base::ConditionVariable condition_variable_{&lock_};
// Count of pending unfinished PostSubBufferAsync() calls.
uint32_t pending_post_sub_buffer_ GUARDED_BY(lock_) = 0;
// The current swapchain state_.
VkResult state_ GUARDED_BY(lock_) = VK_SUCCESS;
// Acquired images queue.
base::circular_deque<uint32_t> acquired_images_ GUARDED_BY(lock_);
// For executing task on GPU main thread.
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
// For executing PosSubBufferAsync tasks off the GPU main thread.
scoped_refptr<base::SequencedTaskRunner> post_sub_buffer_task_runner_;
THREAD_CHECKER(thread_checker_);
DISALLOW_COPY_AND_ASSIGN(VulkanSwapChain);
};
} // namespace gpu
#endif // GPU_VULKAN_VULKAN_SWAP_CHAIN_H_