// Copyright (C) 2024 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include #include #include #include #include #include #define VULKAN_HPP_NAMESPACE vkhpp #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 #define VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL 1 #define VULKAN_HPP_NO_CONSTRUCTORS #define VULKAN_HPP_NO_EXCEPTIONS #define VULKAN_HPP_ASSERT_ON_RESULT #include #include #include "common.h" namespace cuttlefish { template using Result = android::base::expected; // Empty object for `Result` that allows using the below macros. struct Ok {}; inline android::base::unexpected Err(const std::string& msg) { return android::base::unexpected(msg); } #define VK_ASSERT(x) \ ({ \ auto result = (x); \ if (!result.ok()) { \ ALOGE("Failed to " #x ": %s.", result.error().c_str()); \ std::abort(); \ }; \ std::move(result.value()); \ }) #define VK_EXPECT(x) \ ({ \ auto expected = (x); \ if (!expected.ok()) { \ return Err(expected.error()); \ }; \ std::move(expected.value()); \ }) #define VK_EXPECT_RESULT(x) \ do { \ vkhpp::Result result = (x); \ if (result != vkhpp::Result::eSuccess) { \ return Err(std::string("Failed to " #x ": ") + \ vkhpp::to_string(result)); \ } \ } while (0); #define VK_EXPECT_RV(x) \ ({ \ auto vkhpp_rv = (x); \ if (vkhpp_rv.result != vkhpp::Result::eSuccess) { \ return Err(std::string("Failed to " #x ": ") + \ vkhpp::to_string(vkhpp_rv.result)); \ }; \ std::move(vkhpp_rv.value); \ }) #define VK_TRY(x) \ do { \ vkhpp::Result result = (x); \ if (result != vkhpp::Result::eSuccess) { \ return Err(std::string("Failed to " #x ": ") + \ vkhpp::to_string(result)); \ } \ } while (0); #define VK_TRY_RV(x) \ ({ \ auto vkhpp_rv = (x); \ if (vkhpp_rv.result != vkhpp::Result::eSuccess) { \ return Err(std::string("Failed to " #x ": ") + \ vkhpp::to_string(vkhpp_rv.result)); \ }; \ std::move(vkhpp_rv.value); \ }) class SampleBase { public: virtual ~SampleBase() {} SampleBase(const SampleBase&) = delete; SampleBase& operator=(const SampleBase&) = delete; SampleBase(SampleBase&&) = default; SampleBase& operator=(SampleBase&&) = default; virtual Result StartUp() = 0; virtual Result CleanUp() = 0; struct SwapchainInfo { vkhpp::Format swapchainFormat; vkhpp::Extent2D swapchainExtent; std::vector swapchainImageViews; }; virtual Result CreateSwapchainDependents(const SwapchainInfo& /*info*/) { return Ok{}; } virtual Result DestroySwapchainDependents() { return Ok{}; } struct FrameInfo { uint32_t swapchainImageIndex = -1; vkhpp::CommandBuffer commandBuffer; }; virtual Result RecordFrame(const FrameInfo& /*frame*/) { return Ok{}; } Result Render(); Result SetWindow(ANativeWindow* window = nullptr); protected: SampleBase() = default; Result StartUpBase(const std::vector& instance_extensions = { VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_EXTENSION_NAME, }, const std::vector& instance_layers = {}, const std::vector& device_extensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, }); Result CleanUpBase(); Result CreateSurface(); Result DestroySurface(); Result CreateSwapchain(); Result DestroySwapchain(); Result RecreateSwapchain(); struct BufferWithMemory { vkhpp::UniqueBuffer buffer; vkhpp::UniqueDeviceMemory bufferMemory; }; Result CreateBuffer( vkhpp::DeviceSize buffer_size, vkhpp::BufferUsageFlags buffer_usages, vkhpp::MemoryPropertyFlags buffer_memory_properties); Result CreateBufferWithData( vkhpp::DeviceSize buffer_size, vkhpp::BufferUsageFlags buffer_usages, vkhpp::MemoryPropertyFlags buffer_memory_properties, const uint8_t* buffer_data); Result DoCommandsImmediate( const std::function(vkhpp::UniqueCommandBuffer&)>& func, const std::vector& semaphores_wait = {}, const std::vector& semaphores_signal = {}); struct ImageWithMemory { vkhpp::UniqueImage image; vkhpp::UniqueDeviceMemory imageMemory; vkhpp::UniqueImageView imageView; }; Result CreateImage( uint32_t width, uint32_t height, vkhpp::Format format, vkhpp::ImageUsageFlags usages, vkhpp::MemoryPropertyFlags memory_properties, vkhpp::ImageLayout returned_layout); Result LoadImage(const vkhpp::UniqueImage& image, uint32_t width, uint32_t height, const std::vector& imageData, vkhpp::ImageLayout currentLayout, vkhpp::ImageLayout returnedLayout); Result> DownloadImage( uint32_t width, uint32_t height, const vkhpp::UniqueImage& image, vkhpp::ImageLayout current_layout, vkhpp::ImageLayout returned_layout); struct YuvImageWithMemory { vkhpp::UniqueSamplerYcbcrConversion imageSamplerConversion; vkhpp::UniqueSampler imageSampler; vkhpp::UniqueDeviceMemory imageMemory; vkhpp::UniqueImage image; vkhpp::UniqueImageView imageView; }; Result CreateYuvImage( uint32_t width, uint32_t height, vkhpp::ImageUsageFlags usages, vkhpp::MemoryPropertyFlags memory_properties, vkhpp::ImageLayout returned_layout); Result LoadYuvImage(const vkhpp::UniqueImage& image, uint32_t width, uint32_t height, const std::vector& image_data_y, const std::vector& image_data_u, const std::vector& image_data_v, vkhpp::ImageLayout current_layout, vkhpp::ImageLayout returned_layout); struct FramebufferWithAttachments { std::optional colorAttachment; std::optional depthAttachment; vkhpp::UniqueRenderPass renderpass; vkhpp::UniqueFramebuffer framebuffer; }; Result CreateFramebuffer( uint32_t width, uint32_t height, vkhpp::Format colorAttachmentFormat = vkhpp::Format::eUndefined, vkhpp::Format depthAttachmentFormat = vkhpp::Format::eUndefined); private: vkhpp::DynamicLoader mLoader; vkhpp::UniqueInstance mInstance; std::optional mDebugMessenger; protected: vkhpp::PhysicalDevice mPhysicalDevice; vkhpp::UniqueDevice mDevice; vkhpp::Queue mQueue; uint32_t mQueueFamilyIndex = 0; private: static constexpr const VkDeviceSize kStagingBufferSize = 32 * 1024 * 1024; BufferWithMemory mStagingBuffer; struct PerFrameObjects { vkhpp::UniqueFence readyFence; vkhpp::UniqueSemaphore readyForRender; vkhpp::UniqueSemaphore readyForPresent; vkhpp::UniqueCommandPool commandPool; vkhpp::UniqueCommandBuffer commandBuffer; }; static constexpr const uint32_t kMaxFramesInFlight = 3; uint32_t mCurrentFrame = 0; std::vector mFrameObjects; ANativeWindow* mWindow = nullptr; std::optional mSurface; struct SwapchainObjects { vkhpp::SurfaceFormatKHR swapchainFormat; vkhpp::Extent2D swapchainExtent; vkhpp::UniqueSwapchainKHR swapchain; std::vector swapchainImages; std::vector swapchainImageViews; }; std::optional mSwapchainObjects; }; Result> BuildVulkanSampleApp(); } // namespace cuttlefish