32 auto acquire_res =
device.createFenceUnique({});
33 if (acquire_res.result != vk::Result::eSuccess) {
37 acquire = std::move(acquire_res.value);
51 if (
auto result =
device.waitForFences(
54 std::numeric_limits<uint64_t>::max()
56 result != vk::Result::eSuccess) {
62 result != vk::Result::eSuccess) {
63 VALIDATION_LOG <<
"Could not reset fence: " << vk::to_string(result);
70 const std::weak_ptr<Context>&
context,
71 std::weak_ptr<android::SurfaceControl> surface_control,
76 context, std::move(surface_control), cb, size, enable_msaa));
77 return impl->IsValid() ? impl :
nullptr;
81 const std::weak_ptr<Context>&
context,
82 std::weak_ptr<android::SurfaceControl> surface_control,
86 : surface_control_(
std::move(surface_control)), cb_(cb) {
88 pool_ = std::make_shared<AHBTexturePoolVK>(
context, desc_);
89 if (!pool_->IsValid()) {
92 transients_ = std::make_shared<SwapchainTransientsVK>(
96 auto sync = std::make_unique<AHBFrameSynchronizerVK>(
98 if (!sync->IsValid()) {
101 frame_data_.push_back(std::move(sync));
104 auto control = surface_control_.lock();
105 is_valid_ = control && control->IsValid();
127void AHBSwapchainImplVK::WaitIdle()
const {
129 if (
auto context = transients_->GetContext().lock()) {
131 if (result != vk::Result::eSuccess) {
132 FML_LOG(INFO) <<
"Device waitIdle failed: " << vk::to_string(result);
139 auto context = transients_->GetContext().lock();
146 if (!frame_data_[frame_index_]->WaitForFence(
155 auto pool_entry = pool_->Pop();
157 if (!pool_entry.IsValid()) {
164 if (!ImportRenderReady(pool_entry.render_ready_fence, pool_entry.texture)) {
176 transients_, pool_entry.texture,
177 [weak = weak_from_this(),
texture = pool_entry.texture]() {
178 auto thiz = weak.lock();
180 VALIDATION_LOG <<
"Swapchain died before image could be presented.";
193bool AHBSwapchainImplVK::Present(
194 const std::shared_ptr<AHBTextureSourceVK>&
texture) {
195 auto control = surface_control_.lock();
196 if (!control || !control->IsValid()) {
197 VALIDATION_LOG <<
"Surface control died before swapchain image could be "
203 auto context = transients_->GetContext().lock();
205 ContextVK::Cast(*context).GetGPUTracer()->MarkFrameEnd();
213 auto present_ready = SubmitSignalForPresentReady(
texture);
215 if (!present_ready) {
220 android::SurfaceTransaction transaction =
222 if (!transaction.SetContents(control.get(),
224 present_ready->CreateFD()
226 VALIDATION_LOG <<
"Could not set swapchain image contents on the surface "
230 return transaction.Apply(
231 [
texture, weak = weak_from_this()](ASurfaceTransactionStats* stats) {
232 auto thiz = weak.lock();
236 thiz->OnTextureUpdatedOnSurfaceControl(
texture, stats);
240void AHBSwapchainImplVK::AddFinalCommandBuffer(
241 std::shared_ptr<CommandBuffer> cmd_buffer) {
242 frame_data_[frame_index_]->final_cmd_buffer = std::move(cmd_buffer);
245std::shared_ptr<ExternalSemaphoreVK>
246AHBSwapchainImplVK::SubmitSignalForPresentReady(
247 const std::shared_ptr<AHBTextureSourceVK>&
texture)
const {
248 auto context = transients_->GetContext().lock();
253 auto present_ready = std::make_shared<ExternalSemaphoreVK>(
context);
254 if (!present_ready || !present_ready->IsValid()) {
258 auto& sync = frame_data_[frame_index_];
263 CommandBufferVK& command_buffer_vk = CommandBufferVK::Cast(*
command_buffer);
264 const auto command_encoder_vk = command_buffer_vk.GetCommandBuffer();
265 if (!command_buffer_vk.EndCommandBuffer()) {
268 sync->present_ready = present_ready;
270 vk::SubmitInfo submit_info;
271 vk::PipelineStageFlags wait_stage =
272 vk::PipelineStageFlagBits::eColorAttachmentOutput;
273 if (sync->render_ready) {
274 submit_info.setPWaitSemaphores(&sync->render_ready.get());
275 submit_info.setWaitSemaphoreCount(1);
276 submit_info.setWaitDstStageMask(wait_stage);
278 submit_info.setCommandBuffers(command_encoder_vk);
279 submit_info.setPSignalSemaphores(&sync->present_ready->GetHandle());
280 submit_info.setSignalSemaphoreCount(1);
282 auto result = ContextVK::Cast(*context).GetGraphicsQueue()->Submit(
283 submit_info, *sync->acquire);
284 if (result != vk::Result::eSuccess) {
287 sync->acquire_fence_pending =
true;
288 return present_ready;
291vk::UniqueSemaphore AHBSwapchainImplVK::CreateRenderReadySemaphore(
292 const std::shared_ptr<fml::UniqueFD>& fd)
const {
293 if (!fd->is_valid()) {
297 auto context = transients_->GetContext().lock();
302 const auto& context_vk = ContextVK::Cast(*
context);
303 const auto&
device = context_vk.GetDevice();
305 auto signal_wait =
device.createSemaphoreUnique({});
306 if (signal_wait.result != vk::Result::eSuccess) {
310 context_vk.SetDebugName(*signal_wait.value,
"AHBRenderReadySemaphore");
312 vk::ImportSemaphoreFdInfoKHR import_info;
313 import_info.semaphore = *signal_wait.value;
314 import_info.fd = fd->get();
315 import_info.handleType = vk::ExternalSemaphoreHandleTypeFlagBits::eSyncFd;
317 import_info.flags = vk::SemaphoreImportFlagBitsKHR::eTemporary;
319 const auto import_result =
device.importSemaphoreFdKHR(import_info);
321 if (import_result != vk::Result::eSuccess) {
323 << vk::to_string(import_result);
331 [[maybe_unused]]
auto released = fd->release();
333 return std::move(signal_wait.value);
336bool AHBSwapchainImplVK::ImportRenderReady(
337 const std::shared_ptr<fml::UniqueFD>& render_ready_fence,
338 const std::shared_ptr<AHBTextureSourceVK>&
texture) {
339 auto context = transients_->GetContext().lock();
346 if (!render_ready_fence || !render_ready_fence->is_valid()) {
347 frame_data_[frame_index_]->render_ready = {};
351 auto semaphore = CreateRenderReadySemaphore(render_ready_fence);
357 frame_data_[frame_index_]->render_ready = std::move(semaphore);
361void AHBSwapchainImplVK::OnTextureUpdatedOnSurfaceControl(
362 std::shared_ptr<AHBTextureSourceVK>
texture,
363 ASurfaceTransactionStats* stats) {
364 auto control = surface_control_.lock();
371 auto render_ready_fence =
372 android::CreatePreviousReleaseFence(*control, stats);
377 Lock lock(currently_displayed_texture_mutex_);
378 auto old_texture = currently_displayed_texture_;
379 currently_displayed_texture_ = std::move(
texture);
380 pool_->Push(std::move(old_texture), std::move(render_ready_fence));
The implementation of a swapchain at a specific size. Resizes to the surface will cause the instance ...
static std::shared_ptr< AHBSwapchainImplVK > Create(const std::weak_ptr< Context > &context, std::weak_ptr< android::SurfaceControl > surface_control, const CreateTransactionCB &cb, const ISize &size, bool enable_msaa)
Create a swapchain of a specific size whose images will be presented to the provided surface control.
AHBSwapchainImplVK(const AHBSwapchainImplVK &)=delete
std::unique_ptr< Surface > AcquireNextDrawable()
Acquire the next surface that can be used to present to the swapchain.
const android::HardwareBufferDescriptor & GetDescriptor() const
Get the descriptor used to create the hardware buffers that will be displayed on the surface control.
const ISize & GetSize() const
static ContextVK & Cast(Context &base)
std::shared_ptr< DeviceHolderVK > GetDeviceHolder() const
const vk::Device & GetDevice() const
std::shared_ptr< GPUTracerVK > GetGPUTracer() const
static std::unique_ptr< SurfaceVK > WrapSwapchainImage(const std::shared_ptr< SwapchainTransientsVK > &transients, const std::shared_ptr< TextureSourceVK > &swapchain_image, SwapCallback swap_callback)
Wrap the swapchain image in a Surface, which provides the additional configuration required for usage...
A wrapper for ASurfaceTransaction. https://developer.android.com/ndk/reference/group/native-activity#...
#define FML_LOG(severity)
std::function< android::SurfaceTransaction()> CreateTransactionCB
constexpr PixelFormat ToPixelFormat(vk::Format format)
static constexpr const size_t kMaxPendingPresents
static TextureDescriptor ToSwapchainTextureDescriptor(const android::HardwareBufferDescriptor &ahb_desc)
std::shared_ptr< ContextGLES > context
std::shared_ptr< CommandBuffer > command_buffer
~AHBFrameSynchronizerVK()
AHBFrameSynchronizerVK(const vk::Device &device)
bool WaitForFence(const vk::Device &device)
bool acquire_fence_pending
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
CompressionType compression_type
A descriptor use to specify hardware buffer allocations.
static HardwareBufferDescriptor MakeForSwapchainImage(const ISize &size)
Create a descriptor of the given size that is suitable for use as a swapchain image.
HardwareBufferFormat format