[Impeller] use 3 fences to synchronize AHB swapchains (like we do for KHR). (#161767)

Testing on a newer Adreno, I can still see rendering artifacts. This
change matches the syncrhonization to what we do for KHR, and on the
Adreno I see no more rendering artifacts.
This commit is contained in:
Jonah Williams 2025-01-16 18:48:18 -08:00 committed by GitHub
parent 095f46c4a7
commit 32ef7f8e2e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 222 additions and 173 deletions

View File

@ -42719,8 +42719,8 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swap
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_texture_pool_vk.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_texture_pool_vk.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/external_fence_vk.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/external_fence_vk.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/external_semaphore_vk.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/external_semaphore_vk.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc + ../../../flutter/LICENSE
@ -45665,8 +45665,8 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapch
FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h
FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_texture_pool_vk.cc
FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_texture_pool_vk.h
FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/external_fence_vk.cc
FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/external_fence_vk.h
FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/external_semaphore_vk.cc
FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/ahb/external_semaphore_vk.h
FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.cc
FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_image_vk.h
FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain/khr/khr_swapchain_impl_vk.cc

View File

@ -141,8 +141,8 @@ impeller_component("vulkan") {
"swapchain/ahb/ahb_swapchain_vk.h",
"swapchain/ahb/ahb_texture_pool_vk.cc",
"swapchain/ahb/ahb_texture_pool_vk.h",
"swapchain/ahb/external_fence_vk.cc",
"swapchain/ahb/external_fence_vk.h",
"swapchain/ahb/external_semaphore_vk.cc",
"swapchain/ahb/external_semaphore_vk.h",
]
}

View File

@ -4,24 +4,16 @@
#include "impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_impl_vk.h"
#include "flutter/fml/trace_event.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/backend/vulkan/command_buffer_vk.h"
#include "impeller/renderer/backend/vulkan/swapchain/ahb/ahb_formats.h"
#include "impeller/renderer/backend/vulkan/swapchain/ahb/external_semaphore_vk.h"
#include "impeller/renderer/backend/vulkan/swapchain/surface_vk.h"
#include "impeller/toolkit/android/surface_transaction.h"
#include "impeller/toolkit/android/surface_transaction_stats.h"
namespace impeller {
//------------------------------------------------------------------------------
/// The maximum number of presents pending in the compositor after which the
/// acquire calls will block. This value is 2 images given to the system
/// compositor and one for the raster thread, Because the semaphore is acquired
/// when the CPU begins working on the texture
///
static constexpr const size_t kMaxPendingPresents = 3u;
static TextureDescriptor ToSwapchainTextureDescriptor(
const android::HardwareBufferDescriptor& ahb_desc) {
TextureDescriptor desc;
@ -36,6 +28,41 @@ static TextureDescriptor ToSwapchainTextureDescriptor(
return desc;
}
AHBFrameSynchronizerVK::AHBFrameSynchronizerVK(const vk::Device& device) {
auto acquire_res = device.createFenceUnique(
vk::FenceCreateInfo{vk::FenceCreateFlagBits::eSignaled});
if (acquire_res.result != vk::Result::eSuccess) {
VALIDATION_LOG << "Could not create synchronizer.";
return;
}
acquire = std::move(acquire_res.value);
is_valid = true;
}
AHBFrameSynchronizerVK::~AHBFrameSynchronizerVK() = default;
bool AHBFrameSynchronizerVK::IsValid() const {
return is_valid;
}
bool AHBFrameSynchronizerVK::WaitForFence(const vk::Device& device) {
if (auto result = device.waitForFences(
*acquire, // fence
true, // wait all
std::numeric_limits<uint64_t>::max() // timeout (ns)
);
result != vk::Result::eSuccess) {
VALIDATION_LOG << "Fence wait failed: " << vk::to_string(result);
return false;
}
if (auto result = device.resetFences(*acquire);
result != vk::Result::eSuccess) {
VALIDATION_LOG << "Could not reset fence: " << vk::to_string(result);
return false;
}
return true;
}
std::shared_ptr<AHBSwapchainImplVK> AHBSwapchainImplVK::Create(
const std::weak_ptr<Context>& context,
std::weak_ptr<android::SurfaceControl> surface_control,
@ -54,8 +81,7 @@ AHBSwapchainImplVK::AHBSwapchainImplVK(
const ISize& size,
bool enable_msaa,
size_t swapchain_image_count)
: surface_control_(std::move(surface_control)),
pending_presents_(std::make_shared<fml::Semaphore>(kMaxPendingPresents)) {
: surface_control_(std::move(surface_control)) {
desc_ = android::HardwareBufferDescriptor::MakeForSwapchainImage(size);
pool_ =
std::make_shared<AHBTexturePoolVK>(context, desc_, swapchain_image_count);
@ -65,6 +91,15 @@ AHBSwapchainImplVK::AHBSwapchainImplVK(
transients_ = std::make_shared<SwapchainTransientsVK>(
context, ToSwapchainTextureDescriptor(desc_), enable_msaa);
for (auto i = 0u; i < kMaxPendingPresents; i++) {
auto sync = std::make_unique<AHBFrameSynchronizerVK>(
ContextVK::Cast(*context.lock()).GetDeviceHolder()->GetDevice());
if (!sync->IsValid()) {
return;
}
frame_data_.push_back(std::move(sync));
}
auto control = surface_control_.lock();
is_valid_ = control && control->IsValid();
}
@ -85,17 +120,17 @@ const android::HardwareBufferDescriptor& AHBSwapchainImplVK::GetDescriptor()
}
std::unique_ptr<Surface> AHBSwapchainImplVK::AcquireNextDrawable() {
{
TRACE_EVENT0("impeller", "CompositorPendingWait");
if (!pending_presents_->Wait()) {
return nullptr;
}
auto context = transients_->GetContext().lock();
if (!context) {
return nullptr;
}
frame_index_ = (frame_index_ + 1) % kMaxPendingPresents;
AutoSemaSignaler auto_sema_signaler =
std::make_shared<fml::ScopedCleanupClosure>(
[sema = pending_presents_]() { sema->Signal(); });
if (!frame_data_[frame_index_]->WaitForFence(
ContextVK::Cast(*context).GetDevice())) {
return nullptr;
}
if (!is_valid_) {
return nullptr;
@ -110,14 +145,12 @@ std::unique_ptr<Surface> AHBSwapchainImplVK::AcquireNextDrawable() {
// Import the render ready semaphore that will block onscreen rendering until
// it is ready.
if (!SubmitWaitForRenderReady(pool_entry.render_ready_fence,
pool_entry.texture)) {
if (!ImportRenderReady(pool_entry.render_ready_fence, pool_entry.texture)) {
VALIDATION_LOG << "Could wait on render ready fence.";
return nullptr;
}
#if IMPELLER_DEBUG
auto context = transients_->GetContext().lock();
if (context) {
ContextVK::Cast(*context).GetGPUTracer()->MarkFrameStart();
}
@ -125,14 +158,13 @@ std::unique_ptr<Surface> AHBSwapchainImplVK::AcquireNextDrawable() {
auto surface = SurfaceVK::WrapSwapchainImage(
transients_, pool_entry.texture,
[signaler = auto_sema_signaler, weak = weak_from_this(),
texture = pool_entry.texture]() {
[weak = weak_from_this(), texture = pool_entry.texture]() {
auto thiz = weak.lock();
if (!thiz) {
VALIDATION_LOG << "Swapchain died before image could be presented.";
return false;
}
return thiz->Present(signaler, texture);
return thiz->Present(texture);
});
if (!surface) {
@ -143,7 +175,6 @@ std::unique_ptr<Surface> AHBSwapchainImplVK::AcquireNextDrawable() {
}
bool AHBSwapchainImplVK::Present(
const AutoSemaSignaler& signaler,
const std::shared_ptr<AHBTextureSourceVK>& texture) {
auto control = surface_control_.lock();
if (!control || !control->IsValid()) {
@ -163,9 +194,9 @@ bool AHBSwapchainImplVK::Present(
return false;
}
auto fence = SubmitSignalForPresentReady(texture);
auto present_ready = SubmitSignalForPresentReady(texture);
if (!fence) {
if (!present_ready) {
VALIDATION_LOG << "Could not submit completion signal.";
return false;
}
@ -173,67 +204,70 @@ bool AHBSwapchainImplVK::Present(
android::SurfaceTransaction transaction;
if (!transaction.SetContents(control.get(), //
texture->GetBackingStore(), //
fence->CreateFD() //
present_ready->CreateFD() //
)) {
VALIDATION_LOG << "Could not set swapchain image contents on the surface "
"control.";
return false;
}
return transaction.Apply([signaler, texture, weak = weak_from_this()](
ASurfaceTransactionStats* stats) {
auto thiz = weak.lock();
if (!thiz) {
return;
}
thiz->OnTextureUpdatedOnSurfaceControl(signaler, texture, stats);
});
return transaction.Apply(
[texture, weak = weak_from_this()](ASurfaceTransactionStats* stats) {
auto thiz = weak.lock();
if (!thiz) {
return;
}
thiz->OnTextureUpdatedOnSurfaceControl(texture, stats);
});
}
void AHBSwapchainImplVK::AddFinalCommandBuffer(
std::shared_ptr<CommandBuffer> cmd_buffer) {
frame_data_[frame_index_].command_buffer = std::move(cmd_buffer);
frame_data_[frame_index_]->final_cmd_buffer = std::move(cmd_buffer);
}
std::shared_ptr<ExternalFenceVK>
std::shared_ptr<ExternalSemaphoreVK>
AHBSwapchainImplVK::SubmitSignalForPresentReady(
const std::shared_ptr<AHBTextureSourceVK>& texture) const {
auto context = transients_->GetContext().lock();
if (!context) {
return nullptr;
}
auto fence = std::make_shared<ExternalFenceVK>(context);
if (!fence || !fence->IsValid()) {
auto present_ready = std::make_shared<ExternalSemaphoreVK>(context);
if (!present_ready || !present_ready->IsValid()) {
return nullptr;
}
auto command_buffer = frame_data_[frame_index_].command_buffer;
auto& sync = frame_data_[frame_index_];
auto command_buffer = sync->final_cmd_buffer;
if (!command_buffer) {
return nullptr;
}
CommandBufferVK& command_buffer_vk = CommandBufferVK::Cast(*command_buffer);
const auto command_encoder_vk = command_buffer_vk.GetCommandBuffer();
command_buffer_vk.Track(fence->GetSharedHandle());
if (!command_buffer_vk.EndCommandBuffer()) {
return nullptr;
}
sync->present_ready = present_ready;
vk::SubmitInfo submit_info;
vk::PipelineStageFlags wait_stage =
vk::PipelineStageFlagBits::eColorAttachmentOutput;
if (frame_data_[frame_index_].semaphore) {
submit_info.setPWaitSemaphores(&frame_data_[frame_index_].semaphore.get());
if (sync->render_ready) {
submit_info.setPWaitSemaphores(&sync->render_ready.get());
submit_info.setWaitSemaphoreCount(1);
submit_info.setWaitDstStageMask(wait_stage);
}
submit_info.setCommandBuffers(command_encoder_vk);
submit_info.setPSignalSemaphores(&sync->present_ready->GetHandle());
submit_info.setSignalSemaphoreCount(1);
auto result = ContextVK::Cast(*context).GetGraphicsQueue()->Submit(
submit_info, fence->GetHandle());
submit_info, *sync->acquire);
if (result != vk::Result::eSuccess) {
return nullptr;
}
return fence;
return present_ready;
}
vk::UniqueSemaphore AHBSwapchainImplVK::CreateRenderReadySemaphore(
@ -251,7 +285,6 @@ vk::UniqueSemaphore AHBSwapchainImplVK::CreateRenderReadySemaphore(
const auto& device = context_vk.GetDevice();
auto signal_wait = device.createSemaphoreUnique({});
if (signal_wait.result != vk::Result::eSuccess) {
return {};
}
@ -282,33 +315,32 @@ vk::UniqueSemaphore AHBSwapchainImplVK::CreateRenderReadySemaphore(
return std::move(signal_wait.value);
}
bool AHBSwapchainImplVK::SubmitWaitForRenderReady(
bool AHBSwapchainImplVK::ImportRenderReady(
const std::shared_ptr<fml::UniqueFD>& render_ready_fence,
const std::shared_ptr<AHBTextureSourceVK>& texture) {
// If there is no render ready fence, we are already ready to render into
// the texture. There is nothing more to do.
if (!render_ready_fence || !render_ready_fence->is_valid()) {
frame_data_[frame_index_].semaphore = {};
return true;
}
auto context = transients_->GetContext().lock();
if (!context) {
return false;
}
// If there is no render ready fence, we are already ready to render into
// the texture. There is nothing more to do.
if (!render_ready_fence || !render_ready_fence->is_valid()) {
frame_data_[frame_index_]->render_ready = {};
return true;
}
auto semaphore = CreateRenderReadySemaphore(render_ready_fence);
if (!semaphore) {
return false;
}
// This semaphore will be later used to block the onscreen render pass
// from starting until the system is done reading the onscreen.
frame_data_[frame_index_].semaphore = std::move(semaphore);
frame_data_[frame_index_]->render_ready = std::move(semaphore);
return true;
}
void AHBSwapchainImplVK::OnTextureUpdatedOnSurfaceControl(
const AutoSemaSignaler& signaler,
std::shared_ptr<AHBTextureSourceVK> texture,
ASurfaceTransactionStats* stats) {
auto control = surface_control_.lock();

View File

@ -8,11 +8,10 @@
#include <memory>
#include "flutter/fml/closure.h"
#include "flutter/fml/synchronization/semaphore.h"
#include "impeller/base/thread.h"
#include "impeller/renderer/backend/vulkan/android/ahb_texture_source_vk.h"
#include "impeller/renderer/backend/vulkan/swapchain/ahb/ahb_texture_pool_vk.h"
#include "impeller/renderer/backend/vulkan/swapchain/ahb/external_fence_vk.h"
#include "impeller/renderer/backend/vulkan/swapchain/ahb/external_semaphore_vk.h"
#include "impeller/renderer/backend/vulkan/swapchain/swapchain_transients_vk.h"
#include "impeller/renderer/surface.h"
#include "impeller/toolkit/android/hardware_buffer.h"
@ -21,6 +20,24 @@
namespace impeller {
static constexpr const size_t kMaxPendingPresents = 2u;
struct AHBFrameSynchronizerVK {
vk::UniqueFence acquire;
vk::UniqueSemaphore render_ready = {};
std::shared_ptr<ExternalSemaphoreVK> present_ready;
std::shared_ptr<CommandBuffer> final_cmd_buffer;
bool is_valid = false;
explicit AHBFrameSynchronizerVK(const vk::Device& device);
~AHBFrameSynchronizerVK();
bool IsValid() const;
bool WaitForFence(const vk::Device& device);
};
//------------------------------------------------------------------------------
/// @brief The implementation of a swapchain at a specific size. Resizes to
/// the surface will cause the instance of the swapchain impl at
@ -99,19 +116,14 @@ class AHBSwapchainImplVK final
android::HardwareBufferDescriptor desc_;
std::shared_ptr<AHBTexturePoolVK> pool_;
std::shared_ptr<SwapchainTransientsVK> transients_;
// In C++20, this mutex can be replaced by the shared pointer specialization
// of std::atomic.
Mutex currently_displayed_texture_mutex_;
std::shared_ptr<AHBTextureSourceVK> currently_displayed_texture_
IPLR_GUARDED_BY(currently_displayed_texture_mutex_);
std::shared_ptr<fml::Semaphore> pending_presents_;
struct FrameData {
std::shared_ptr<CommandBuffer> command_buffer;
vk::UniqueSemaphore semaphore;
};
std::array<FrameData, 3> frame_data_;
std::vector<std::unique_ptr<AHBFrameSynchronizerVK>> frame_data_;
size_t frame_index_ = 0;
bool is_valid_ = false;
@ -122,21 +134,19 @@ class AHBSwapchainImplVK final
bool enable_msaa,
size_t swapchain_image_count);
bool Present(const AutoSemaSignaler& signaler,
const std::shared_ptr<AHBTextureSourceVK>& texture);
bool Present(const std::shared_ptr<AHBTextureSourceVK>& texture);
vk::UniqueSemaphore CreateRenderReadySemaphore(
const std::shared_ptr<fml::UniqueFD>& fd) const;
bool SubmitWaitForRenderReady(
bool ImportRenderReady(
const std::shared_ptr<fml::UniqueFD>& render_ready_fence,
const std::shared_ptr<AHBTextureSourceVK>& texture);
std::shared_ptr<ExternalFenceVK> SubmitSignalForPresentReady(
std::shared_ptr<ExternalSemaphoreVK> SubmitSignalForPresentReady(
const std::shared_ptr<AHBTextureSourceVK>& texture) const;
void OnTextureUpdatedOnSurfaceControl(
const AutoSemaSignaler& signaler,
std::shared_ptr<AHBTextureSourceVK> texture,
ASurfaceTransactionStats* stats);
};

View File

@ -1,64 +0,0 @@
// 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 "impeller/renderer/backend/vulkan/swapchain/ahb/external_fence_vk.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/backend/vulkan/context_vk.h"
namespace impeller {
ExternalFenceVK::ExternalFenceVK(const std::shared_ptr<Context>& context) {
if (!context) {
return;
}
vk::StructureChain<vk::FenceCreateInfo, vk::ExportFenceCreateInfoKHR> info;
info.get<vk::ExportFenceCreateInfoKHR>().handleTypes =
vk::ExternalFenceHandleTypeFlagBits::eSyncFd;
const auto& context_vk = ContextVK::Cast(*context);
auto [result, fence] = context_vk.GetDevice().createFenceUnique(info.get());
if (result != vk::Result::eSuccess) {
VALIDATION_LOG << "Could not create external fence: "
<< vk::to_string(result);
return;
}
context_vk.SetDebugName(fence.get(), "ExternalFenceSyncFD");
fence_ = MakeSharedVK(std::move(fence));
}
ExternalFenceVK::~ExternalFenceVK() = default;
bool ExternalFenceVK::IsValid() const {
return !!fence_;
}
fml::UniqueFD ExternalFenceVK::CreateFD() const {
if (!IsValid()) {
return {};
}
vk::FenceGetFdInfoKHR info;
info.fence = fence_->Get();
info.handleType = vk::ExternalFenceHandleTypeFlagBits::eSyncFd;
auto [result, fd] = fence_->GetUniqueWrapper().getOwner().getFenceFdKHR(info);
if (result != vk::Result::eSuccess) {
VALIDATION_LOG << "Could not export external fence FD: "
<< vk::to_string(result);
return {};
}
return fml::UniqueFD{fd};
}
const vk::Fence& ExternalFenceVK::GetHandle() const {
return fence_->Get();
}
const SharedHandleVK<vk::Fence>& ExternalFenceVK::GetSharedHandle() const {
return fence_;
}
} // namespace impeller

View File

@ -0,0 +1,70 @@
// 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 "impeller/renderer/backend/vulkan/swapchain/ahb/external_semaphore_vk.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/backend/vulkan/context_vk.h"
#include "vulkan/vulkan_handles.hpp"
namespace impeller {
ExternalSemaphoreVK::ExternalSemaphoreVK(
const std::shared_ptr<Context>& context) {
if (!context) {
return;
}
vk::StructureChain<vk::SemaphoreCreateInfo, vk::ExportSemaphoreCreateInfoKHR>
info;
info.get<vk::ExportSemaphoreCreateInfoKHR>().handleTypes =
vk::ExternalSemaphoreHandleTypeFlagBits::eSyncFd;
const auto& context_vk = ContextVK::Cast(*context);
auto [result, semaphore] =
context_vk.GetDevice().createSemaphoreUnique(info.get());
if (result != vk::Result::eSuccess) {
VALIDATION_LOG << "Could not create external fence: "
<< vk::to_string(result);
return;
}
context_vk.SetDebugName(semaphore.get(), "ExternalSemaphoreSyncFD");
semaphore_ = MakeSharedVK(std::move(semaphore));
}
ExternalSemaphoreVK::~ExternalSemaphoreVK() = default;
bool ExternalSemaphoreVK::IsValid() const {
return !!semaphore_;
}
fml::UniqueFD ExternalSemaphoreVK::CreateFD() const {
if (!IsValid()) {
return {};
}
vk::SemaphoreGetFdInfoKHR info;
info.semaphore = semaphore_->Get();
info.handleType = vk::ExternalSemaphoreHandleTypeFlagBits::eSyncFd;
auto [result, fd] =
semaphore_->GetUniqueWrapper().getOwner().getSemaphoreFdKHR(info);
if (result != vk::Result::eSuccess) {
VALIDATION_LOG << "Could not export external fence FD: "
<< vk::to_string(result);
return {};
}
return fml::UniqueFD{fd};
}
const vk::Semaphore& ExternalSemaphoreVK::GetHandle() const {
return semaphore_->Get();
}
const SharedHandleVK<vk::Semaphore>& ExternalSemaphoreVK::GetSharedHandle()
const {
return semaphore_;
}
} // namespace impeller

View File

@ -2,44 +2,43 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_AHB_EXTERNAL_FENCE_VK_H_
#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_AHB_EXTERNAL_FENCE_VK_H_
#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_AHB_EXTERNAL_SEMAPHORE_VK_H_
#define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_AHB_EXTERNAL_SEMAPHORE_VK_H_
#include "flutter/fml/unique_fd.h"
#include "impeller/renderer/backend/vulkan/shared_object_vk.h"
#include "impeller/renderer/backend/vulkan/vk.h"
#include "impeller/renderer/context.h"
#include "vulkan/vulkan_handles.hpp"
namespace impeller {
//------------------------------------------------------------------------------
/// @brief A Vulkan fence that can be exported as a platform specific file
/// descriptor.
/// @brief A Vulkan semaphore that can be exported as a platform specific
/// file descriptor.
///
/// The fences are exported as sync file descriptors.
/// The semaphore are exported as sync file descriptors.
///
/// @warning Only fences that have been signaled or have a single operation
/// pending can be exported. Make sure to submit a fence signalling
/// operation to a queue before attempted to obtain a file
/// descriptor for the fence. See
/// VUID-VkFenceGetFdInfoKHR-handleType-01454 for additional details
/// on the implementation.
/// @warning Only semaphore that have been signaled or have a single
/// operation pending can be exported. Make sure to submit a fence
/// signalling operation to a queue before attempted to obtain a
/// file descriptor for the fence.
///
class ExternalFenceVK {
class ExternalSemaphoreVK {
public:
//----------------------------------------------------------------------------
/// @brief Create a new un-signaled fence that can be exported as a sync
/// file descriptor.
/// @brief Create a new un-signaled semaphore that can be exported as a
/// sync file descriptor.
///
/// @param[in] context The device context.
///
explicit ExternalFenceVK(const std::shared_ptr<Context>& context);
explicit ExternalSemaphoreVK(const std::shared_ptr<Context>& context);
~ExternalFenceVK();
~ExternalSemaphoreVK();
ExternalFenceVK(const ExternalFenceVK&) = delete;
ExternalSemaphoreVK(const ExternalSemaphoreVK&) = delete;
ExternalFenceVK& operator=(const ExternalFenceVK&) = delete;
ExternalSemaphoreVK& operator=(const ExternalSemaphoreVK&) = delete;
//----------------------------------------------------------------------------
/// @brief If a valid fence could be created.
@ -49,16 +48,18 @@ class ExternalFenceVK {
bool IsValid() const;
//----------------------------------------------------------------------------
/// @brief Create a new sync file descriptor for the underlying fence.
/// The fence must already be signaled or have a signal operation
/// pending in a queue. There are no checks for this in the
/// implementation and only Vulkan validation will catch such a
/// misuse and undefined behavior.
/// @brief Create a new sync file descriptor for the underlying
/// semaphore.
///
/// The semaphore must already be signaled or have a signal
/// operation pending in a queue. There are no checks for this in
/// the implementation and only Vulkan validation will catch such
/// a misuse and undefined behavior.
///
/// @warning Implementations are also allowed to return invalid file
/// descriptors in case a fence has already been signaled. So it
/// is not necessary an error to obtain an invalid descriptor from
/// this call. For APIs that are meant to consume such
/// descriptors in case a semaphore has already been signaled. So
/// it is not necessary an error to obtain an invalid descriptor
/// from this call. For APIs that are meant to consume such
/// descriptors, pass -1 as the file handle.
///
/// Since this call can return an invalid FD even in case of
@ -70,14 +71,14 @@ class ExternalFenceVK {
///
fml::UniqueFD CreateFD() const;
const vk::Fence& GetHandle() const;
const vk::Semaphore& GetHandle() const;
const SharedHandleVK<vk::Fence>& GetSharedHandle() const;
const SharedHandleVK<vk::Semaphore>& GetSharedHandle() const;
private:
SharedHandleVK<vk::Fence> fence_;
SharedHandleVK<vk::Semaphore> semaphore_;
};
} // namespace impeller
#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_AHB_EXTERNAL_FENCE_VK_H_
#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_SWAPCHAIN_AHB_EXTERNAL_SEMAPHORE_VK_H_