1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <functional>
20 #include <optional>
21 #include <string>
22 #include <vector>
23 
24 #define VULKAN_HPP_NAMESPACE vkhpp
25 #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
26 #define VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL 1
27 #define VULKAN_HPP_NO_CONSTRUCTORS
28 #define VULKAN_HPP_NO_EXCEPTIONS
29 #define VULKAN_HPP_ASSERT_ON_RESULT
30 #include <vulkan/vulkan_raii.hpp>
31 #include <vulkan/vulkan_to_string.hpp>
32 
33 #include "Expected.h"
34 
35 namespace gfxstream {
36 
37 #define VK_EXPECT(x)                                        \
38     ({                                                      \
39         auto expected = (x);                                \
40         if (!expected.ok()) {                               \
41             return gfxstream::unexpected(expected.error()); \
42         };                                                  \
43         std::move(expected.value());                        \
44     })
45 
46 #define VK_EXPECT_RESULT(x)                                 \
47     do {                                                    \
48         vkhpp::Result result = (x);                         \
49         if (result != vkhpp::Result::eSuccess) {            \
50             return gfxstream::unexpected(result);           \
51         }                                                   \
52     } while (0);
53 
54 #define VK_EXPECT_RV(x)                                     \
55     ({                                                      \
56         auto vkhpp_rv = (x);                                \
57         if (vkhpp_rv.result != vkhpp::Result::eSuccess) {   \
58             return gfxstream::unexpected(vkhpp_rv.result);  \
59         };                                                  \
60         std::move(vkhpp_rv.value);                          \
61     })
62 
63 #define VK_EXPECT_RV_OR_STRING(x)                           \
64     ({                                                      \
65         auto vkhpp_rv = (x);                                \
66         if (vkhpp_rv.result != vkhpp::Result::eSuccess) {   \
67             return gfxstream::unexpected(                   \
68                 std::string("Failed to " #x ": ") +         \
69                 vkhpp::to_string(vkhpp_rv.result));         \
70         };                                                  \
71         std::move(vkhpp_rv.value);                          \
72     })
73 
74 #define VK_TRY(x)                                           \
75     do {                                                    \
76         vkhpp::Result result = (x);                         \
77         if (result != vkhpp::Result::eSuccess) {            \
78             return result;                                  \
79         }                                                   \
80     } while (0);
81 
82 #define VK_TRY_RV(x)                                        \
83     ({                                                      \
84         auto vkhpp_rv = (x);                                \
85         if (vkhpp_rv.result != vkhpp::Result::eSuccess) {   \
86             return vkhpp_rv.result;                         \
87         };                                                  \
88         std::move(vkhpp_rv.value);                          \
89     })
90 
91 class Vk {
92   public:
93     static gfxstream::expected<Vk, vkhpp::Result> Load(
94         const std::vector<std::string>& instance_extensions = {},
95         const std::vector<std::string>& instance_layers = {},
96         const std::vector<std::string>& device_extensions = {});
97 
98     Vk(const Vk&) = delete;
99     Vk& operator=(const Vk&) = delete;
100 
101     Vk(Vk&&) = default;
102     Vk& operator=(Vk&&) = default;
103 
104     struct BufferWithMemory {
105         vkhpp::UniqueBuffer buffer;
106         vkhpp::UniqueDeviceMemory bufferMemory;
107     };
108     gfxstream::expected<BufferWithMemory, vkhpp::Result> CreateBuffer(
109         vkhpp::DeviceSize buffer_size,
110         vkhpp::BufferUsageFlags buffer_usages,
111         vkhpp::MemoryPropertyFlags buffer_memory_properties);
112     gfxstream::expected<BufferWithMemory, vkhpp::Result> CreateBufferWithData(
113         vkhpp::DeviceSize buffer_size,
114         vkhpp::BufferUsageFlags buffer_usages,
115         vkhpp::MemoryPropertyFlags buffer_memory_properties,
116         const uint8_t* buffer_data);
117 
118     vkhpp::Result DoCommandsImmediate(
119         const std::function<vkhpp::Result(vkhpp::UniqueCommandBuffer&)>& func,
120         const std::vector<vkhpp::UniqueSemaphore>& semaphores_wait = {},
121         const std::vector<vkhpp::UniqueSemaphore>& semaphores_signal = {});
122 
123     struct ImageWithMemory {
124         vkhpp::UniqueImage image;
125         vkhpp::UniqueDeviceMemory imageMemory;
126         vkhpp::UniqueImageView imageView;
127     };
128     gfxstream::expected<ImageWithMemory, vkhpp::Result> CreateImage(
129         uint32_t width,
130         uint32_t height,
131         vkhpp::Format format,
132         vkhpp::ImageUsageFlags usages,
133         vkhpp::MemoryPropertyFlags memory_properties,
134         vkhpp::ImageLayout returned_layout);
135 
136     gfxstream::expected<std::vector<uint8_t>, vkhpp::Result> DownloadImage(
137         uint32_t width,
138         uint32_t height,
139         const vkhpp::UniqueImage& image,
140         vkhpp::ImageLayout current_layout,
141         vkhpp::ImageLayout returned_layout);
142 
143     struct YuvImageWithMemory {
144         vkhpp::UniqueSamplerYcbcrConversion imageSamplerConversion;
145         vkhpp::UniqueSampler imageSampler;
146         vkhpp::UniqueDeviceMemory imageMemory;
147         vkhpp::UniqueImage image;
148         vkhpp::UniqueImageView imageView;
149     };
150     gfxstream::expected<YuvImageWithMemory, vkhpp::Result> CreateYuvImage(
151         uint32_t width,
152         uint32_t height,
153         vkhpp::ImageUsageFlags usages,
154         vkhpp::MemoryPropertyFlags memory_properties,
155         vkhpp::ImageLayout returned_layout);
156 
157     vkhpp::Result LoadYuvImage(const vkhpp::UniqueImage& image,
158                                uint32_t width,
159                                uint32_t height,
160                                const std::vector<uint8_t>& image_data_y,
161                                const std::vector<uint8_t>& image_data_u,
162                                const std::vector<uint8_t>& image_data_v,
163                                vkhpp::ImageLayout current_layout,
164                                vkhpp::ImageLayout returned_layout);
165 
166     struct FramebufferWithAttachments {
167         std::optional<ImageWithMemory> colorAttachment;
168         std::optional<ImageWithMemory> depthAttachment;
169         vkhpp::UniqueRenderPass renderpass;
170         vkhpp::UniqueFramebuffer framebuffer;
171     };
172     gfxstream::expected<FramebufferWithAttachments, vkhpp::Result> CreateFramebuffer(
173         uint32_t width,
174         uint32_t height,
175         vkhpp::Format colorAttachmentFormat = vkhpp::Format::eUndefined,
176         vkhpp::Format depthAttachmentFormat = vkhpp::Format::eUndefined);
177 
instance()178     vkhpp::Instance& instance() { return *mInstance; }
179 
device()180     vkhpp::Device& device() { return *mDevice; }
181 
182   private:
Vk(vkhpp::DynamicLoader loader,vkhpp::UniqueInstance instance,std::optional<vkhpp::UniqueDebugUtilsMessengerEXT> debug,vkhpp::PhysicalDevice physical_device,vkhpp::UniqueDevice device,vkhpp::Queue queue,uint32_t queue_family_index,vkhpp::UniqueCommandPool command_pool,vkhpp::UniqueBuffer stagingBuffer,vkhpp::UniqueDeviceMemory stagingBufferMemory)183     Vk(vkhpp::DynamicLoader loader,
184        vkhpp::UniqueInstance instance,
185        std::optional<vkhpp::UniqueDebugUtilsMessengerEXT> debug,
186        vkhpp::PhysicalDevice physical_device,
187        vkhpp::UniqueDevice device,
188        vkhpp::Queue queue,
189        uint32_t queue_family_index,
190        vkhpp::UniqueCommandPool command_pool,
191        vkhpp::UniqueBuffer stagingBuffer,
192        vkhpp::UniqueDeviceMemory stagingBufferMemory)
193         : mLoader(std::move(loader)),
194           mInstance(std::move(instance)),
195           mDebugMessenger(std::move(debug)),
196           mPhysicalDevice(std::move(physical_device)),
197           mDevice(std::move(device)),
198           mQueue(std::move(queue)),
199           mQueueFamilyIndex(queue_family_index),
200           mCommandPool(std::move(command_pool)),
201           mStagingBuffer(std::move(stagingBuffer)),
202           mStagingBufferMemory(std::move(stagingBufferMemory)) {}
203 
204     // Note: order is important for destruction.
205     vkhpp::DynamicLoader mLoader;
206     vkhpp::UniqueInstance mInstance;
207     std::optional<vkhpp::UniqueDebugUtilsMessengerEXT> mDebugMessenger;
208     vkhpp::PhysicalDevice mPhysicalDevice;
209     vkhpp::UniqueDevice mDevice;
210     vkhpp::Queue mQueue;
211     uint32_t mQueueFamilyIndex;
212     vkhpp::UniqueCommandPool mCommandPool;
213     static constexpr const VkDeviceSize kStagingBufferSize = 32 * 1024 * 1024;
214     vkhpp::UniqueBuffer mStagingBuffer;
215     vkhpp::UniqueDeviceMemory mStagingBufferMemory;
216 };
217 
218 }  // namespace cuttlefish
219