32 auto acquire_res = device.createFenceUnique(
33 vk::FenceCreateInfo{vk::FenceCreateFlagBits::eSignaled});
34 if (acquire_res.result != vk::Result::eSuccess) {
38 acquire = std::move(acquire_res.value);
49 if (
auto result = device.waitForFences(
52 std::numeric_limits<uint64_t>::max()
54 result != vk::Result::eSuccess) {
58 if (
auto result = device.resetFences(*
acquire);
59 result != vk::Result::eSuccess) {
60 VALIDATION_LOG <<
"Could not reset fence: " << vk::to_string(result);
67 const std::weak_ptr<Context>& context,
68 std::weak_ptr<android::SurfaceControl> surface_control,
72 size_t swapchain_image_count) {
73 auto impl = std::shared_ptr<AHBSwapchainImplVK>(
75 enable_msaa, swapchain_image_count));
76 return impl->IsValid() ? impl :
nullptr;
80 const std::weak_ptr<Context>& context,
81 std::weak_ptr<android::SurfaceControl> surface_control,
85 size_t swapchain_image_count)
86 : surface_control_(
std::move(surface_control)), cb_(cb) {
89 std::make_shared<AHBTexturePoolVK>(context, desc_, swapchain_image_count);
90 if (!pool_->IsValid()) {
93 transients_ = std::make_shared<SwapchainTransientsVK>(
97 auto sync = std::make_unique<AHBFrameSynchronizerVK>(
99 if (!sync->IsValid()) {
102 frame_data_.push_back(std::move(sync));
105 auto control = surface_control_.lock();
106 is_valid_ = control && control->IsValid();
125 auto context = transients_->GetContext().lock();
132 if (!frame_data_[frame_index_]->WaitForFence(
141 auto pool_entry = pool_->Pop();
143 if (!pool_entry.IsValid()) {
150 if (!ImportRenderReady(pool_entry.render_ready_fence, pool_entry.texture)) {
162 transients_, pool_entry.texture,
163 [weak = weak_from_this(), texture = pool_entry.texture]() {
164 auto thiz = weak.lock();
166 VALIDATION_LOG <<
"Swapchain died before image could be presented.";
169 return thiz->Present(texture);
179 bool AHBSwapchainImplVK::Present(
180 const std::shared_ptr<AHBTextureSourceVK>& texture) {
181 auto control = surface_control_.lock();
182 if (!control || !control->IsValid()) {
183 VALIDATION_LOG <<
"Surface control died before swapchain image could be "
189 auto context = transients_->GetContext().lock();
191 ContextVK::Cast(*context).GetGPUTracer()->MarkFrameEnd();
199 auto present_ready = SubmitSignalForPresentReady(texture);
201 if (!present_ready) {
206 android::SurfaceTransaction transaction = cb_();
207 if (!transaction.SetContents(control.get(),
208 texture->GetBackingStore(),
209 present_ready->CreateFD()
211 VALIDATION_LOG <<
"Could not set swapchain image contents on the surface "
215 return transaction.Apply(
216 [texture, weak = weak_from_this()](ASurfaceTransactionStats* stats) {
217 auto thiz = weak.lock();
221 thiz->OnTextureUpdatedOnSurfaceControl(texture, stats);
225 void AHBSwapchainImplVK::AddFinalCommandBuffer(
226 std::shared_ptr<CommandBuffer> cmd_buffer) {
227 frame_data_[frame_index_]->final_cmd_buffer = std::move(cmd_buffer);
230 std::shared_ptr<ExternalSemaphoreVK>
231 AHBSwapchainImplVK::SubmitSignalForPresentReady(
232 const std::shared_ptr<AHBTextureSourceVK>& texture)
const {
233 auto context = transients_->GetContext().lock();
238 auto present_ready = std::make_shared<ExternalSemaphoreVK>(context);
239 if (!present_ready || !present_ready->IsValid()) {
243 auto& sync = frame_data_[frame_index_];
244 auto command_buffer = sync->final_cmd_buffer;
245 if (!command_buffer) {
248 CommandBufferVK& command_buffer_vk = CommandBufferVK::Cast(*command_buffer);
249 const auto command_encoder_vk = command_buffer_vk.GetCommandBuffer();
250 if (!command_buffer_vk.EndCommandBuffer()) {
253 sync->present_ready = present_ready;
255 vk::SubmitInfo submit_info;
256 vk::PipelineStageFlags wait_stage =
257 vk::PipelineStageFlagBits::eColorAttachmentOutput;
258 if (sync->render_ready) {
259 submit_info.setPWaitSemaphores(&sync->render_ready.get());
260 submit_info.setWaitSemaphoreCount(1);
261 submit_info.setWaitDstStageMask(wait_stage);
263 submit_info.setCommandBuffers(command_encoder_vk);
264 submit_info.setPSignalSemaphores(&sync->present_ready->GetHandle());
265 submit_info.setSignalSemaphoreCount(1);
267 auto result = ContextVK::Cast(*context).GetGraphicsQueue()->Submit(
268 submit_info, *sync->acquire);
269 if (result != vk::Result::eSuccess) {
272 return present_ready;
275 vk::UniqueSemaphore AHBSwapchainImplVK::CreateRenderReadySemaphore(
276 const std::shared_ptr<fml::UniqueFD>& fd)
const {
277 if (!fd->is_valid()) {
281 auto context = transients_->GetContext().lock();
286 const auto& context_vk = ContextVK::Cast(*context);
287 const auto& device = context_vk.GetDevice();
289 auto signal_wait = device.createSemaphoreUnique({});
290 if (signal_wait.result != vk::Result::eSuccess) {
294 context_vk.SetDebugName(*signal_wait.value,
"AHBRenderReadySemaphore");
296 vk::ImportSemaphoreFdInfoKHR import_info;
297 import_info.semaphore = *signal_wait.value;
298 import_info.fd = fd->get();
299 import_info.handleType = vk::ExternalSemaphoreHandleTypeFlagBits::eSyncFd;
301 import_info.flags = vk::SemaphoreImportFlagBitsKHR::eTemporary;
303 const auto import_result = device.importSemaphoreFdKHR(import_info);
305 if (import_result != vk::Result::eSuccess) {
307 << vk::to_string(import_result);
315 [[maybe_unused]]
auto released = fd->release();
317 return std::move(signal_wait.value);
320 bool AHBSwapchainImplVK::ImportRenderReady(
321 const std::shared_ptr<fml::UniqueFD>& render_ready_fence,
322 const std::shared_ptr<AHBTextureSourceVK>& texture) {
323 auto context = transients_->GetContext().lock();
330 if (!render_ready_fence || !render_ready_fence->is_valid()) {
331 frame_data_[frame_index_]->render_ready = {};
335 auto semaphore = CreateRenderReadySemaphore(render_ready_fence);
341 frame_data_[frame_index_]->render_ready = std::move(semaphore);
345 void AHBSwapchainImplVK::OnTextureUpdatedOnSurfaceControl(
346 std::shared_ptr<AHBTextureSourceVK> texture,
347 ASurfaceTransactionStats* stats) {
348 auto control = surface_control_.lock();
355 auto render_ready_fence =
361 Lock lock(currently_displayed_texture_mutex_);
362 auto old_texture = currently_displayed_texture_;
363 currently_displayed_texture_ = std::move(texture);
364 pool_->Push(std::move(old_texture), std::move(render_ready_fence));
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.
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, size_t swapchain_image_count)
Create a swapchain of a specific size whose images will be presented to the provided surface control.
const ISize & GetSize() const
static ContextVK & Cast(Context &base)
const vk::Device & GetDevice() const
std::shared_ptr< GPUTracerVK > GetGPUTracer() const
std::shared_ptr< DeviceHolderVK > GetDeviceHolder() 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...
fml::UniqueFD CreatePreviousReleaseFence(const SurfaceControl &control, ASurfaceTransactionStats *stats)
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)
~AHBFrameSynchronizerVK()
AHBFrameSynchronizerVK(const vk::Device &device)
bool WaitForFence(const vk::Device &device)
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