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