• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef VK_TEST_UTILS_H
2 #define VK_TEST_UTILS_H
3 
4 #include "aemu/base/files/PathUtils.h"
5 #include "vulkan/VulkanDispatch.h"
6 #include "vulkan/vk_util.h"
7 
8 namespace gfxstream {
9 namespace vk {
10 
libDir()11 inline std::string libDir() {
12     using android::base::pj;
13     return
14         pj({android::base::getProgramDirectory(),
15 #ifdef _WIN32
16            // Windows uses mock Vulkan ICD.
17            "testlib64"
18 #else
19            "lib64", "vulkan"
20 #endif
21         });
22 }
23 
testIcdFilename()24 inline std::string testIcdFilename() {
25     using android::base::pj;
26     return pj(libDir(),
27 #ifdef _WIN32
28         // Windows uses mock Vulkan ICD.
29         "VkICD_mock_icd.json"
30 #else
31         "vk_swiftshader_icd.json"
32 #endif
33     );
34 }
35 
36 struct RenderResourceVkBase
37     : public vk_util::MultiCrtp<RenderResourceVkBase,                         //
38                                 vk_util::FindMemoryType,                      //
39                                 vk_util::RecordImageLayoutTransformCommands,  //
40                                 vk_util::RunSingleTimeCommand> {
41     const VulkanDispatch& m_vk;
42     VkDevice m_vkDevice;
43     VkPhysicalDevice m_vkPhysicalDevice;
44     VkQueue m_vkQueue;
45     uint32_t m_width;
46     uint32_t m_height;
47 
48     VkImageCreateInfo m_vkImageCreateInfo;
49     VkImage m_vkImage;
50     VkDeviceMemory m_imageVkDeviceMemory;
51     VkImageView m_vkImageView;
52 
53     VkBuffer m_vkBuffer;
54     VkDeviceMemory m_bufferVkDeviceMemory;
55     uint32_t *m_memory;
56 
57     VkCommandPool m_vkCommandPool;
58     VkCommandBuffer m_readCommandBuffer;
59     VkCommandBuffer m_writeCommandBuffer;
60 
RenderResourceVkBaseRenderResourceVkBase61     explicit RenderResourceVkBase(const VulkanDispatch& vk)
62         : m_vk(vk),
63           m_vkImageCreateInfo({}),
64           m_vkImage(VK_NULL_HANDLE),
65           m_imageVkDeviceMemory(VK_NULL_HANDLE),
66           m_vkImageView(VK_NULL_HANDLE),
67           m_vkBuffer(VK_NULL_HANDLE),
68           m_bufferVkDeviceMemory(VK_NULL_HANDLE),
69           m_memory(nullptr),
70           m_readCommandBuffer(VK_NULL_HANDLE),
71           m_writeCommandBuffer(VK_NULL_HANDLE) {}
72 };
73 
74 template <VkImageLayout imageLayout, VkImageUsageFlags imageUsage>
75 struct RenderResourceVk : public RenderResourceVkBase {
76    public:
77     static constexpr VkFormat k_vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
78     static constexpr uint32_t k_bpp = 4;
79     static constexpr VkImageLayout k_vkImageLayout = imageLayout;
80 
createRenderResourceVk81     static std::unique_ptr<const RenderResourceVk<imageLayout, imageUsage>> create(
82         const VulkanDispatch& vk, VkDevice device, VkPhysicalDevice physicalDevice, VkQueue queue,
83         VkCommandPool commandPool, uint32_t width, uint32_t height) {
84         std::unique_ptr<RenderResourceVk<imageLayout, imageUsage>> res(
85             new RenderResourceVk<imageLayout, imageUsage>(vk));
86         res->m_vkDevice = device;
87         res->m_vkPhysicalDevice = physicalDevice;
88         res->m_vkQueue = queue;
89         res->m_width = width;
90         res->m_height = height;
91         res->m_vkCommandPool = commandPool;
92         if (!res->setUpImage()) {
93             return nullptr;
94         }
95         if (!res->setUpBuffer()) {
96             return nullptr;
97         }
98         if (!res->setUpCommandBuffer()) {
99             return nullptr;
100         }
101 
102         return res;
103     }
104 
numOfPixelsRenderResourceVk105     uint32_t numOfPixels() const { return m_width * m_height; }
106 
writeRenderResourceVk107     bool write(const std::vector<uint32_t> &pixels) const {
108         if (pixels.size() != numOfPixels()) {
109             return false;
110         }
111         std::copy(pixels.begin(), pixels.end(), m_memory);
112         return submitCommandBufferAndWait(m_writeCommandBuffer);
113     }
114 
readRenderResourceVk115     std::optional<std::vector<uint32_t>> read() const {
116         std::vector<uint32_t> res(numOfPixels());
117         if (!submitCommandBufferAndWait(m_readCommandBuffer)) {
118             return std::nullopt;
119         }
120         std::copy(m_memory, m_memory + numOfPixels(), res.begin());
121         return res;
122     }
123 
~RenderResourceVkRenderResourceVk124     ~RenderResourceVk() {
125         std::vector<VkCommandBuffer> toFree;
126         if (m_writeCommandBuffer != VK_NULL_HANDLE) {
127             toFree.push_back(m_writeCommandBuffer);
128         }
129         if (m_readCommandBuffer != VK_NULL_HANDLE) {
130             toFree.push_back(m_readCommandBuffer);
131         }
132         if (!toFree.empty()) {
133             m_vk.vkFreeCommandBuffers(m_vkDevice, m_vkCommandPool,
134                                       static_cast<uint32_t>(toFree.size()),
135                                       toFree.data());
136         }
137         if (m_memory) {
138             m_vk.vkUnmapMemory(m_vkDevice, m_bufferVkDeviceMemory);
139         }
140         m_vk.vkFreeMemory(m_vkDevice, m_bufferVkDeviceMemory, nullptr);
141         m_vk.vkDestroyBuffer(m_vkDevice, m_vkBuffer, nullptr);
142         m_vk.vkDestroyImageView(m_vkDevice, m_vkImageView, nullptr);
143         m_vk.vkFreeMemory(m_vkDevice, m_imageVkDeviceMemory, nullptr);
144         m_vk.vkDestroyImage(m_vkDevice, m_vkImage, nullptr);
145     }
146 
147    private:
RenderResourceVkRenderResourceVk148     RenderResourceVk(const VulkanDispatch& vk) : RenderResourceVkBase(vk) {}
149 
setUpImageRenderResourceVk150     bool setUpImage() {
151         VkImageCreateInfo imageCi{
152             .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
153             .imageType = VK_IMAGE_TYPE_2D,
154             .format = k_vkFormat,
155             .extent = {.width = m_width, .height = m_height, .depth = 1},
156             .mipLevels = 1,
157             .arrayLayers = 1,
158             .samples = VK_SAMPLE_COUNT_1_BIT,
159             .tiling = VK_IMAGE_TILING_OPTIMAL,
160             .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT |
161                      VK_IMAGE_USAGE_TRANSFER_SRC_BIT | imageUsage,
162             .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
163             .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED};
164         if (m_vk.vkCreateImage(m_vkDevice, &imageCi, nullptr, &m_vkImage) !=
165             VK_SUCCESS) {
166             m_vkImage = VK_NULL_HANDLE;
167             return false;
168         }
169         m_vkImageCreateInfo = vk_make_orphan_copy(imageCi);
170 
171         VkMemoryRequirements memRequirements;
172         m_vk.vkGetImageMemoryRequirements(m_vkDevice, m_vkImage,
173                                           &memRequirements);
174         auto maybeMemoryTypeIndex =
175             findMemoryType(memRequirements.memoryTypeBits,
176                            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
177         if (!maybeMemoryTypeIndex.has_value()) {
178             return false;
179         }
180         VkMemoryAllocateInfo allocInfo = {
181             .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
182             .allocationSize = memRequirements.size,
183             .memoryTypeIndex = maybeMemoryTypeIndex.value()};
184         if (m_vk.vkAllocateMemory(m_vkDevice, &allocInfo, nullptr,
185                                   &m_imageVkDeviceMemory) != VK_SUCCESS) {
186             m_imageVkDeviceMemory = VK_NULL_HANDLE;
187             return false;
188         }
189         if (m_vk.vkBindImageMemory(m_vkDevice, m_vkImage, m_imageVkDeviceMemory,
190                                    0) != VK_SUCCESS) {
191             return false;
192         }
193 
194         runSingleTimeCommands(m_vkQueue, nullptr, [this](const auto &cmdBuff) {
195             recordImageLayoutTransformCommands(
196                 cmdBuff, m_vkImage, VK_IMAGE_LAYOUT_UNDEFINED, k_vkImageLayout);
197         });
198 
199         VkImageViewCreateInfo imageViewCi = {
200             .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
201             .image = m_vkImage,
202             .viewType = VK_IMAGE_VIEW_TYPE_2D,
203             .format = k_vkFormat,
204             .components = {.r = VK_COMPONENT_SWIZZLE_IDENTITY,
205                            .g = VK_COMPONENT_SWIZZLE_IDENTITY,
206                            .b = VK_COMPONENT_SWIZZLE_IDENTITY,
207                            .a = VK_COMPONENT_SWIZZLE_IDENTITY},
208             .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
209                                  .baseMipLevel = 0,
210                                  .levelCount = 1,
211                                  .baseArrayLayer = 0,
212                                  .layerCount = 1}};
213         if (m_vk.vkCreateImageView(m_vkDevice, &imageViewCi, nullptr,
214                                    &m_vkImageView) != VK_SUCCESS) {
215             return false;
216         }
217         return true;
218     }
219 
submitCommandBufferAndWaitRenderResourceVk220     bool submitCommandBufferAndWait(VkCommandBuffer cmdBuff) const {
221         VkSubmitInfo submitInfo = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
222                                    .commandBufferCount = 1,
223                                    .pCommandBuffers = &cmdBuff};
224         if (m_vk.vkQueueSubmit(m_vkQueue, 1, &submitInfo, VK_NULL_HANDLE) !=
225             VK_SUCCESS) {
226             return false;
227         }
228         if (m_vk.vkQueueWaitIdle(m_vkQueue) != VK_SUCCESS) {
229             return false;
230         }
231         return true;
232     }
233 
setUpBufferRenderResourceVk234     bool setUpBuffer() {
235         VkBufferCreateInfo bufferCi = {
236             .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
237             .size = m_width * m_height * k_bpp,
238             .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
239                      VK_BUFFER_USAGE_TRANSFER_DST_BIT,
240             .sharingMode = VK_SHARING_MODE_EXCLUSIVE};
241 
242         if (m_vk.vkCreateBuffer(m_vkDevice, &bufferCi, nullptr, &m_vkBuffer) !=
243             VK_SUCCESS) {
244             m_vkBuffer = VK_NULL_HANDLE;
245             return false;
246         }
247 
248         VkMemoryRequirements memRequirements;
249         m_vk.vkGetBufferMemoryRequirements(m_vkDevice, m_vkBuffer,
250                                            &memRequirements);
251         auto maybeMemoryTypeIndex =
252             findMemoryType(memRequirements.memoryTypeBits,
253                            VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
254                                VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
255         if (!maybeMemoryTypeIndex.has_value()) {
256             return false;
257         }
258         VkMemoryAllocateInfo allocInfo = {
259             .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
260             .allocationSize = memRequirements.size,
261             .memoryTypeIndex = maybeMemoryTypeIndex.value()};
262         if (m_vk.vkAllocateMemory(m_vkDevice, &allocInfo, nullptr,
263                                   &m_bufferVkDeviceMemory) != VK_SUCCESS) {
264             m_bufferVkDeviceMemory = VK_NULL_HANDLE;
265             return false;
266         }
267         if (m_vk.vkBindBufferMemory(m_vkDevice, m_vkBuffer,
268                                     m_bufferVkDeviceMemory, 0) != VK_SUCCESS) {
269             return false;
270         }
271         if (m_vk.vkMapMemory(
272                 m_vkDevice, m_bufferVkDeviceMemory, 0, bufferCi.size, 0,
273                 reinterpret_cast<void **>(&m_memory)) != VK_SUCCESS) {
274             m_memory = nullptr;
275             return false;
276         }
277         return true;
278     }
279 
setUpCommandBufferRenderResourceVk280     bool setUpCommandBuffer() {
281         std::array<VkCommandBuffer, 2> cmdBuffs;
282         VkCommandBufferAllocateInfo cmdBuffAllocInfo = {
283             .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
284             .commandPool = m_vkCommandPool,
285             .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
286             .commandBufferCount = static_cast<uint32_t>(cmdBuffs.size())};
287         if (m_vk.vkAllocateCommandBuffers(m_vkDevice, &cmdBuffAllocInfo,
288                                           cmdBuffs.data()) != VK_SUCCESS) {
289             return false;
290         }
291         m_readCommandBuffer = cmdBuffs[0];
292         m_writeCommandBuffer = cmdBuffs[1];
293 
294         VkCommandBufferBeginInfo beginInfo = {
295             .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
296         if (m_vk.vkBeginCommandBuffer(m_readCommandBuffer, &beginInfo) !=
297             VK_SUCCESS) {
298             return false;
299         }
300         recordImageLayoutTransformCommands(
301             m_readCommandBuffer, m_vkImage, k_vkImageLayout,
302             VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
303         VkBufferImageCopy region = {
304             .bufferOffset = 0,
305             .bufferRowLength = 0,
306             .bufferImageHeight = 0,
307             .imageSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
308                                  .mipLevel = 0,
309                                  .baseArrayLayer = 0,
310                                  .layerCount = 1},
311             .imageOffset = {0, 0, 0},
312             .imageExtent = {m_width, m_height, 1}};
313         m_vk.vkCmdCopyImageToBuffer(m_readCommandBuffer, m_vkImage,
314                                     VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
315                                     m_vkBuffer, 1, &region);
316         recordImageLayoutTransformCommands(m_readCommandBuffer, m_vkImage,
317                                            VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
318                                            k_vkImageLayout);
319         if (m_vk.vkEndCommandBuffer(m_readCommandBuffer) != VK_SUCCESS) {
320             return false;
321         }
322 
323         if (m_vk.vkBeginCommandBuffer(m_writeCommandBuffer, &beginInfo) !=
324             VK_SUCCESS) {
325             return false;
326         }
327         recordImageLayoutTransformCommands(
328             m_writeCommandBuffer, m_vkImage, k_vkImageLayout,
329             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
330         m_vk.vkCmdCopyBufferToImage(m_writeCommandBuffer, m_vkBuffer, m_vkImage,
331                                     VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
332                                     &region);
333         recordImageLayoutTransformCommands(m_writeCommandBuffer, m_vkImage,
334                                            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
335                                            k_vkImageLayout);
336         if (m_vk.vkEndCommandBuffer(m_writeCommandBuffer) != VK_SUCCESS) {
337             return false;
338         }
339         return true;
340     }
341 };
342 
343 using RenderTextureVk =
344     RenderResourceVk<VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT>;
345 
346 }  // namespace vk
347 }  // namespace gfxstream
348 
349 #endif