blob: 20d8afa8677199ad3f238d6c919b49467f017b76 [file] [log] [blame]
Po-Hsien Wang42e116c2020-06-09 16:10:27 -07001// Copyright 2020 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <unistd.h>
Po-Hsien Wangaafe13e2020-09-24 14:29:58 +08006#include <algorithm>
Po-Hsien Wang42e116c2020-06-09 16:10:27 -07007#include <limits>
8#include <vulkan/vulkan.hpp>
9
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070010#include "utils.h"
11#include "vkBase.h"
12
13extern int g_vlayer;
14
15namespace vkbench {
Po-Hsien Wangaafe13e2020-09-24 14:29:58 +080016bool IsLayerSupported(const char* layer) {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070017 std::vector<vk::LayerProperties> availLayers =
18 vk::enumerateInstanceLayerProperties();
Po-Hsien Wangaafe13e2020-09-24 14:29:58 +080019 for (const auto& availLayer : availLayers) {
20 if (!strcmp(layer, availLayer.layerName)) {
21 return true;
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070022 }
23 }
Po-Hsien Wangaafe13e2020-09-24 14:29:58 +080024 LOG("Layer %s is not support.", layer);
25 return false;
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070026}
27
Po-Hsien Wangaafe13e2020-09-24 14:29:58 +080028bool IsExtensionSupported(const char* ext) {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070029 std::vector<vk::ExtensionProperties> availExtensions =
30 vk::enumerateInstanceExtensionProperties();
Po-Hsien Wangaafe13e2020-09-24 14:29:58 +080031 for (const auto& availExtension : availExtensions) {
32 if (!strcmp(ext, availExtension.extensionName)) {
33 return true;
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070034 }
35 }
Po-Hsien Wangaafe13e2020-09-24 14:29:58 +080036 DEBUG("Extension %s is not supported.", ext);
37 return false;
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070038}
39
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +080040vkImage::vkImage(vkBase* vkbase,
41 vk::Extent2D img_size,
42 vk::Format img_format,
43 vk::ImageUsageFlags usage,
44 vk::MemoryPropertyFlags memory_properties,
45 vk::ImageTiling tiling) {
46 vkbase_ = vkbase;
47
48 vk::ImageCreateInfo img_create_info;
49 img_create_info.setFormat(img_format)
50 .setImageType(vk::ImageType::e2D)
51 .setSamples(vk::SampleCountFlagBits::e1)
52 .setUsage(usage)
53 .setMipLevels(1)
54 .setArrayLayers(1)
55 .setExtent(vk::Extent3D(img_size, 1))
56 .setQueueFamilyIndexCount(1)
57 .setPQueueFamilyIndices(&vkbase_->GetGFXQueueFamilyIndex())
58 .setInitialLayout(vk::ImageLayout::eUndefined)
59 .setTiling(tiling);
60 img_ = vkbase_->GetDevice().createImage(img_create_info);
61 vk::MemoryRequirements mem_req =
62 vkbase_->GetDevice().getImageMemoryRequirements(img_);
63 memory_ = vkbase_->GetDevice().allocateMemory(
64 {mem_req.size,
65 vkbase_->GetMemoryType(mem_req.memoryTypeBits, memory_properties)});
66 vkbase_->GetDevice().bindImageMemory(img_, memory_, 0);
67}
68
69vkImage::~vkImage() {
70 vkbase_->GetDevice().freeMemory(memory_);
71 vkbase_->GetDevice().destroyImage(img_);
72}
73
74void CreateDebugUtilsMessengerEXT(
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070075 vk::Instance instance,
76 const vk::DebugUtilsMessengerCreateInfoEXT* kPcreateInfo,
77 const vk::AllocationCallbacks* kPallocator,
78 vk::DebugUtilsMessengerEXT* pdebug_messengeer) {
79 auto func = (PFN_vkCreateDebugUtilsMessengerEXT)instance.getProcAddr(
80 "vkCreateDebugUtilsMessengerEXT");
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +080081 if (func == nullptr)
Po-Hsien Wang53230a22020-11-12 18:03:18 -080082 RUNTIME_ERROR("can't locate vkCreateDebugUtilsMessengerEXT");
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +080083 VkCheck(static_cast<vk::Result>(func(
84 (VkInstance)instance,
85 reinterpret_cast<const VkDebugUtilsMessengerCreateInfoEXT*>(
86 kPcreateInfo),
87 reinterpret_cast<const VkAllocationCallbacks*>(kPallocator),
88 reinterpret_cast<VkDebugUtilsMessengerEXT*>(pdebug_messengeer))),
89 "vkCreateDebugUtilsMessengerEXT");
Po-Hsien Wang42e116c2020-06-09 16:10:27 -070090}
91
92void DestroyDebugUtilsMessengerEXT(vk::Instance instance,
93 vk::DebugUtilsMessengerEXT debug_messengeer,
94 const vk::AllocationCallbacks* kPAllocator) {
95 auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)instance.getProcAddr(
96 "vkDestroyDebugUtilsMessengerEXT");
97 if (func != nullptr) {
98 func((VkInstance)instance,
99 static_cast<VkDebugUtilsMessengerEXT>(debug_messengeer),
100 reinterpret_cast<const VkAllocationCallbacks*>(
101 static_cast<const vk::AllocationCallbacks*>(kPAllocator)));
102 }
103}
104
Po-Hsien Wangc2ba7f52020-11-19 19:41:40 -0800105vkBase* vkBase::singleton_ = nullptr;
106vkBase* vkBase::GetInstance() {
107 if (singleton_ == nullptr)
108 singleton_ = new vkBase();
109 return singleton_;
110}
111
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800112uint32_t ChooseGFXQueueFamilies(const vk::PhysicalDevice& physical_device) {
113 uint32_t gfx_queue_idx = UINT32_MAX;
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700114 std::vector<vk::QueueFamilyProperties> props =
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800115 physical_device.getQueueFamilyProperties();
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700116 for (uint32_t i = 0; i < props.size(); i++) {
117 if (props[i].queueCount <= 0)
118 continue;
119 if (props[i].queueFlags & vk::QueueFlagBits::eGraphics) {
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800120 gfx_queue_idx = i;
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700121 break;
122 }
123 }
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800124 return gfx_queue_idx;
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700125}
126
127VKAPI_ATTR VkBool32 VKAPI_CALL
128ValidationCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
129 VkDebugUtilsMessageTypeFlagsEXT messageType,
130 const VkDebugUtilsMessengerCallbackDataEXT* kPcallbackData,
131 void* pUserData) {
132 UNUSED(messageType);
133 UNUSED(pUserData);
Po-Hsien Wangaafe13e2020-09-24 14:29:58 +0800134 switch (messageSeverity) {
135 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
136 DEBUG("%s", kPcallbackData->pMessage);
137 break;
138 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
139 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
140 LOG("%s", kPcallbackData->pMessage);
141 break;
142 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
143 ERROR("%s", kPcallbackData->pMessage);
144 break;
145 default:
Po-Hsien Wang53230a22020-11-12 18:03:18 -0800146 RUNTIME_ERROR("%s", kPcallbackData->pMessage);
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700147 }
148 return VK_FALSE;
149}
150
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800151void vkBase::Initialize() {
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800152 CreateInstance();
153 ChoosePhysicalDevice();
154 CreateLogicalDevice();
155 CreateCommandPool();
156 initialized_ = true;
157}
158
Po-Hsien Wang513fe192020-10-02 11:40:07 +0800159bool vkBase::IsInitialized() const {
160 return initialized_;
161}
162
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700163void vkBase::CreateInstance() {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700164 vk::ApplicationInfo appInfo("vkbench", 1, "Vulkan.hpp", 1,
165 VK_API_VERSION_1_1);
166 vk::InstanceCreateInfo createInfo({}, &appInfo);
167
168 if (g_vlayer) {
Po-Hsien Wangaafe13e2020-09-24 14:29:58 +0800169 validation_layers_.erase(
170 std::remove_if(
171 validation_layers_.begin(), validation_layers_.end(),
172 [](const char* layer) { return !IsLayerSupported(layer); }),
173 validation_layers_.end());
174 debug_extension_.erase(
175 std::remove_if(
176 debug_extension_.begin(), debug_extension_.end(),
177 [](const char* ext) { return !IsExtensionSupported(ext); }),
178 debug_extension_.end());
179 if (validation_layers_.size() == 0 || debug_extension_.size() == 0) {
180 LOG("Validation layer is not supported. Less log will be printed.")
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700181 enable_validation_layer_ = false;
182 } else {
Po-Hsien Wangaafe13e2020-09-24 14:29:58 +0800183 createInfo.setEnabledExtensionCount(debug_extension_.size())
184 .setPpEnabledExtensionNames(debug_extension_.data())
185 .setEnabledLayerCount(validation_layers_.size())
186 .setPpEnabledLayerNames(validation_layers_.data());
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700187 enable_validation_layer_ = true;
188 }
189 }
190 instance_ = vk::createInstance(createInfo);
191 if (enable_validation_layer_) {
192 vk::DebugUtilsMessengerCreateInfoEXT debugCreateInfo;
193 debugCreateInfo
194 .setMessageSeverity(vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
195 vk::DebugUtilsMessageSeverityFlagBitsEXT::eError)
196 .setMessageType(vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
197 vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation)
198 .setPfnUserCallback(ValidationCallback);
199 CreateDebugUtilsMessengerEXT(instance_, &debugCreateInfo, nullptr,
200 &debug_messenger_);
201 }
202}
203
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800204void vkBase::ChoosePhysicalDevice() {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700205 std::vector<vk::PhysicalDevice> physical_devices =
206 instance_.enumeratePhysicalDevices();
207 if (physical_devices.size() == 0) {
Po-Hsien Wang53230a22020-11-12 18:03:18 -0800208 RUNTIME_ERROR("enumeratePhysicalDevices returns 0 devices.");
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700209 }
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800210
211 auto isSuitable = [&physical_devices](vk::MemoryPropertyFlags flags) -> int {
212 int target = -1;
213 for (auto index = 0; index < physical_devices.size(); index++) {
214 vk::PhysicalDeviceMemoryProperties mem_properties =
215 physical_devices[index].getMemoryProperties();
216
217 for (uint32_t i = 0; i < mem_properties.memoryTypeCount; i++) {
218 if ((mem_properties.memoryTypes[i].propertyFlags & flags) == flags) {
219 target = index;
220 }
221 }
222 }
223 return target;
224 };
225 int index = isSuitable(vk::MemoryPropertyFlagBits::eDeviceLocal |
226 vk::MemoryPropertyFlagBits::eHostVisible |
227 vk::MemoryPropertyFlagBits::eHostCoherent);
228 if (index == -1) {
229 index = isSuitable(vk::MemoryPropertyFlagBits::eDeviceLocal);
230 }
231 physical_device_ = physical_devices[index];
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700232 gfx_queue_idx_ = ChooseGFXQueueFamilies(physical_device_);
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800233 mem_properties_ = physical_device_.getMemoryProperties();
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700234}
235
236void vkBase::CreateLogicalDevice() {
237 float tmp = 1.0f;
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800238 vk::DeviceQueueCreateInfo queue_create_info;
239 queue_create_info.setQueueCount(1)
240 .setQueueFamilyIndex(gfx_queue_idx_)
241 .setPQueuePriorities(&tmp);
242 vk::DeviceCreateInfo device_create_info;
243 device_create_info.setQueueCreateInfoCount(1).setPQueueCreateInfos(
244 &queue_create_info);
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700245 if (enable_validation_layer_) {
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800246 device_create_info.setEnabledLayerCount(validation_layers_.size())
247 .setPpEnabledLayerNames(validation_layers_.data());
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700248 }
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800249 device_ = physical_device_.createDevice(device_create_info);
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700250 gfx_queue_ = device_.getQueue(gfx_queue_idx_, /* Queue Index */ 0);
251}
252
253void vkBase::CreateCommandPool() {
254 cmd_pool_ =
255 device_.createCommandPool({vk::CommandPoolCreateFlags(), gfx_queue_idx_});
256}
257
258void vkBase::Destroy() {
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700259 if (cmd_pool_)
260 device_.destroy(cmd_pool_, nullptr);
261 device_.destroy();
262 if (enable_validation_layer_) {
263 DestroyDebugUtilsMessengerEXT(instance_, debug_messenger_, nullptr);
264 }
265 instance_.destroy();
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800266 initialized_ = false;
267}
268
269// AllocateImage allocates an VkImage and returns its handle.
270vkImage* vkBase::AllocateImage(
271 vk::Extent2D img_size,
272 vk::Format img_format,
273 vk::ImageUsageFlags usage = vk::ImageUsageFlagBits::eColorAttachment,
274 vk::MemoryPropertyFlags memory_properties,
275 vk::ImageTiling tiling) {
276 return new vkImage(this, img_size, img_format, usage, memory_properties,
277 tiling);
278}
279
280// GetReadableImage copys a image created with eTransferSrc to a readable
281// vkImage and returns it.
282vkImage* vkBase::GetReadableImage(vkImage* src,
283 vk::Extent2D size,
284 vk::Format format) {
285 std::vector<vk::CommandBuffer> cmds = device_.allocateCommandBuffers(
286 {cmd_pool_, vk::CommandBufferLevel::ePrimary, 1});
287 DEFER(device_.freeCommandBuffers(cmd_pool_, cmds));
288
289 vk::CommandBuffer command = cmds[0];
290
291 vkImage* dest =
292 AllocateImage(size, format, vk::ImageUsageFlagBits::eTransferDst,
293 vk::MemoryPropertyFlagBits::eHostCoherent |
294 vk::MemoryPropertyFlagBits::eHostVisible,
295 vk::ImageTiling::eLinear);
Po-Hsien Wang41024f42020-10-28 17:52:56 -0700296 command.begin(vk::CommandBufferBeginInfo());
Po-Hsien Wanga0e1c312020-09-24 22:06:52 +0800297 vk::ImageMemoryBarrier img_memory_barrier[4];
298 // Transition dest image to transfer destination layout.
299 img_memory_barrier[0]
300 .setDstAccessMask(vk::AccessFlagBits::eTransferWrite)
301 .setOldLayout(vk::ImageLayout::eUndefined)
302 .setNewLayout(vk::ImageLayout::eTransferDstOptimal)
303 .setImage(dest->GetImage())
304 .setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
305 // Transition src image to transfer source layout.
306 img_memory_barrier[1]
307 .setSrcAccessMask(vk::AccessFlagBits::eMemoryRead)
308 .setDstAccessMask(vk::AccessFlagBits::eTransferRead)
309 .setOldLayout(vk::ImageLayout::eGeneral)
310 .setNewLayout(vk::ImageLayout::eTransferSrcOptimal)
311 .setImage(src->GetImage())
312 .setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
313 // Transition dst image to general layout.
314 img_memory_barrier[2]
315 .setSrcAccessMask(vk::AccessFlagBits::eTransferWrite)
316 .setDstAccessMask(vk::AccessFlagBits::eMemoryRead)
317 .setOldLayout(vk::ImageLayout::eTransferDstOptimal)
318 .setNewLayout(vk::ImageLayout::eGeneral)
319 .setImage(dest->GetImage())
320 .setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
321 // Transition src image to transfer source layout.
322 img_memory_barrier[3]
323 .setSrcAccessMask(vk::AccessFlagBits::eTransferRead)
324 .setDstAccessMask(vk::AccessFlagBits::eMemoryRead)
325 .setOldLayout(vk::ImageLayout::eTransferSrcOptimal)
326 .setNewLayout(vk::ImageLayout::eGeneral)
327 .setImage(src->GetImage())
328 .setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
329
330 command.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
331 vk::PipelineStageFlagBits::eTransfer, {}, 0, nullptr,
332 0, nullptr, 1, &img_memory_barrier[0]);
333 command.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
334 vk::PipelineStageFlagBits::eTransfer, {}, 0, nullptr,
335 0, nullptr, 1, &img_memory_barrier[1]);
336 // Copy the image
337 vk::ImageCopy img_copy_region;
338 img_copy_region.srcSubresource.setAspectMask(vk::ImageAspectFlagBits::eColor)
339 .setLayerCount(1);
340 img_copy_region.dstSubresource.setAspectMask(vk::ImageAspectFlagBits::eColor)
341 .setLayerCount(1);
342 img_copy_region.extent.setWidth(size.width)
343 .setHeight(size.height)
344 .setDepth(1);
345 command.copyImage(src->GetImage(), vk::ImageLayout::eTransferSrcOptimal,
346 dest->GetImage(), vk::ImageLayout::eTransferDstOptimal, 1,
347 &img_copy_region);
348 command.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
349 vk::PipelineStageFlagBits::eTransfer, {}, 0, nullptr,
350 0, nullptr, 1, &img_memory_barrier[2]);
351 command.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
352 vk::PipelineStageFlagBits::eTransfer, {}, 0, nullptr,
353 0, nullptr, 1, &img_memory_barrier[3]);
354
355 // Finish command buffer recording and submit.
356 command.end();
357
358 std::vector<vk::SubmitInfo> submit_infos(1);
359 submit_infos[0].setCommandBufferCount(1).setPCommandBuffers(cmds.data());
360 gfx_queue_.submit(submit_infos, {});
361 gfx_queue_.waitIdle();
362 return dest;
363}
364
365// Get the index of a memory type that has all the requested property bits set
366uint32_t vkBase::GetMemoryType(uint32_t bits,
367 vk::MemoryPropertyFlags properties) {
368 for (uint32_t i = 0; i < mem_properties_.memoryTypeCount; i++) {
369 if ((bits & 1) == 1) {
370 if (!properties)
371 return i;
372 if ((mem_properties_.memoryTypes[i].propertyFlags & properties) ==
373 properties) {
374 return i;
375 }
376 }
377 bits >>= 1;
378 }
Po-Hsien Wang53230a22020-11-12 18:03:18 -0800379 RUNTIME_ERROR("could not find a matching memory type");
380 return 0;
Po-Hsien Wang42e116c2020-06-09 16:10:27 -0700381}
382
383} // namespace vkbench