blob: f1795d79303b8ecdd3a4ba7bac8239f76c429576 [file] [log] [blame]
// Copyright 2017 The Fuchsia 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 SRC_LIB_VULKAN_SWAPCHAIN_IMAGE_PIPE_SURFACE_ASYNC_H_
#define SRC_LIB_VULKAN_SWAPCHAIN_IMAGE_PIPE_SURFACE_ASYNC_H_
#include <fuchsia/sysmem/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <mutex>
#include <thread>
#include <unordered_map>
#include "image_pipe_surface.h"
namespace image_pipe_swapchain {
// An implementation of ImagePipeSurface based on an async fidl ImagePipe.
class ImagePipeSurfaceAsync : public ImagePipeSurface {
public:
explicit ImagePipeSurfaceAsync(zx_handle_t image_pipe_handle)
: loop_(&kAsyncLoopConfigNoAttachToCurrentThread) {
image_pipe_.Bind(zx::channel(image_pipe_handle), loop_.dispatcher());
image_pipe_.set_error_handler([this](zx_status_t status) {
std::lock_guard<std::mutex> lock(mutex_);
channel_closed_ = true;
queue_.clear();
});
loop_.StartThread();
std::vector<VkSurfaceFormatKHR> formats(
{{VK_FORMAT_B8G8R8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_B8G8R8A8_SRGB, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_R8G8B8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_R8G8B8A8_SRGB, VK_COLORSPACE_SRGB_NONLINEAR_KHR}});
supported_image_properties_ = {formats};
}
~ImagePipeSurfaceAsync() override { loop_.Shutdown(); }
bool Init() override;
bool IsLost() override;
bool CreateImage(VkDevice device, VkLayerDispatchTable* pDisp, VkFormat format,
VkImageUsageFlags usage, VkSwapchainCreateFlagsKHR swapchain_flags,
fuchsia::images::ImageInfo image_info, uint32_t image_count,
const VkAllocationCallbacks* pAllocator,
std::vector<ImageInfo>* image_info_out) override;
void RemoveImage(uint32_t image_id) override;
void PresentImage(uint32_t image_id, std::vector<zx::event> acquire_fences,
std::vector<zx::event> release_fences) override;
SupportedImageProperties& GetSupportedImageProperties() override;
private:
class FenceSignaler {
public:
explicit FenceSignaler(zx::event event) : event_(std::move(event)) {}
~FenceSignaler() {
if (event_)
event_.signal(0, ZX_EVENT_SIGNALED);
}
const zx::event& event() { return event_; }
void reset() { event_.reset(); }
private:
zx::event event_;
};
// Called on the async loop.
void PresentNextImageLocked() __attribute__((requires_capability(mutex_)));
async::Loop loop_;
std::mutex mutex_;
// Can only be accessed from the async loop's thread.
fuchsia::images::ImagePipe2Ptr image_pipe_;
uint32_t current_buffer_id_ = 0;
std::unordered_map</*image_id=*/uint32_t, /*buffer_id=*/uint32_t> image_id_to_buffer_id_;
std::unordered_map</*buffer_id=*/uint32_t, /*image count=*/uint32_t> buffer_counts_;
struct PendingPresent {
uint32_t image_id;
std::vector<zx::event> acquire_fences;
// These fences will automatically be signaled when they go out of scope, which could happen if
// the ImagePipe channel is closed. As these events are passed to the application as acquire
// semaphores, this prevents semaphore waits on them from hanging until the GPU driver decides
// to time them out.
// The only case where we don't automatically signal them is if the PresentImage callback is
// run, in which case scenic is responsible for signaling them.
std::vector<std::unique_ptr<FenceSignaler>> release_fences;
};
std::vector<PendingPresent> queue_ __attribute__((guarded_by(mutex_)));
bool present_pending_ __attribute__((guarded_by(mutex_))) = false;
fuchsia::sysmem::AllocatorSyncPtr sysmem_allocator_;
SupportedImageProperties supported_image_properties_;
bool channel_closed_ __attribute__((guarded_by(mutex_))) = false;
};
} // namespace image_pipe_swapchain
#endif // SRC_LIB_VULKAN_SWAPCHAIN_IMAGE_PIPE_SURFACE_ASYNC_H_