blob: 1f51cd61053054eba2b602e1c7addbeb5b7fcd94 [file] [log] [blame]
Jamie Madill9e54b5a2016-05-25 12:57:39 -04001//
2// Copyright 2016 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6// RendererVk.cpp:
7// Implements the class methods for RendererVk.
8//
9
10#include "libANGLE/renderer/vulkan/RendererVk.h"
11
Jamie Madill4d0bf552016-12-28 15:45:24 -050012// Placing this first seems to solve an intellisense bug.
13#include "libANGLE/renderer/vulkan/renderervk_utils.h"
14
Jamie Madille09bd5d2016-11-29 16:20:35 -050015#include <EGL/eglext.h>
16
Jamie Madill9e54b5a2016-05-25 12:57:39 -040017#include "common/debug.h"
Jamie Madilla66779f2017-01-06 10:43:44 -050018#include "common/system_utils.h"
Jamie Madill4d0bf552016-12-28 15:45:24 -050019#include "libANGLE/renderer/driver_utils.h"
Jamie Madille09bd5d2016-11-29 16:20:35 -050020#include "libANGLE/renderer/vulkan/CompilerVk.h"
21#include "libANGLE/renderer/vulkan/FramebufferVk.h"
Jamie Madill8ecf7f92017-01-13 17:29:52 -050022#include "libANGLE/renderer/vulkan/GlslangWrapper.h"
Jamie Madille09bd5d2016-11-29 16:20:35 -050023#include "libANGLE/renderer/vulkan/TextureVk.h"
24#include "libANGLE/renderer/vulkan/VertexArrayVk.h"
Jamie Madill7b57b9d2017-01-13 09:33:38 -050025#include "libANGLE/renderer/vulkan/formatutilsvk.h"
Jamie Madille09bd5d2016-11-29 16:20:35 -050026#include "platform/Platform.h"
Jamie Madill9e54b5a2016-05-25 12:57:39 -040027
28namespace rx
29{
30
Jamie Madille09bd5d2016-11-29 16:20:35 -050031namespace
32{
33
34VkResult VerifyExtensionsPresent(const std::vector<VkExtensionProperties> &extensionProps,
35 const std::vector<const char *> &enabledExtensionNames)
36{
37 // Compile the extensions names into a set.
38 std::set<std::string> extensionNames;
39 for (const auto &extensionProp : extensionProps)
40 {
41 extensionNames.insert(extensionProp.extensionName);
42 }
43
44 for (const auto &extensionName : enabledExtensionNames)
45 {
46 if (extensionNames.count(extensionName) == 0)
47 {
48 return VK_ERROR_EXTENSION_NOT_PRESENT;
49 }
50 }
51
52 return VK_SUCCESS;
53}
54
Jamie Madill0448ec82016-12-23 13:41:47 -050055VkBool32 VKAPI_CALL DebugReportCallback(VkDebugReportFlagsEXT flags,
56 VkDebugReportObjectTypeEXT objectType,
57 uint64_t object,
58 size_t location,
59 int32_t messageCode,
60 const char *layerPrefix,
61 const char *message,
62 void *userData)
63{
64 if ((flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0)
65 {
Yuly Novikovbcb3f9b2017-01-27 22:45:18 -050066 ERR() << message;
Jamie Madill0448ec82016-12-23 13:41:47 -050067#if !defined(NDEBUG)
68 // Abort the call in Debug builds.
69 return VK_TRUE;
70#endif
71 }
72 else if ((flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) != 0)
73 {
Yuly Novikovbcb3f9b2017-01-27 22:45:18 -050074 WARN() << message;
Jamie Madill0448ec82016-12-23 13:41:47 -050075 }
76 else
77 {
Yuly Novikovbcb3f9b2017-01-27 22:45:18 -050078 // Uncomment this if you want Vulkan spam.
79 // WARN() << message;
Jamie Madill0448ec82016-12-23 13:41:47 -050080 }
81
82 return VK_FALSE;
83}
84
Jamie Madille09bd5d2016-11-29 16:20:35 -050085} // anonymous namespace
86
Jamie Madill0448ec82016-12-23 13:41:47 -050087RendererVk::RendererVk()
88 : mCapsInitialized(false),
89 mInstance(VK_NULL_HANDLE),
90 mEnableValidationLayers(false),
Jamie Madill4d0bf552016-12-28 15:45:24 -050091 mDebugReportCallback(VK_NULL_HANDLE),
92 mPhysicalDevice(VK_NULL_HANDLE),
93 mQueue(VK_NULL_HANDLE),
94 mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
95 mDevice(VK_NULL_HANDLE),
Jamie Madill8ecf7f92017-01-13 17:29:52 -050096 mHostVisibleMemoryIndex(std::numeric_limits<uint32_t>::max()),
Jamie Madill4c26fc22017-02-24 11:04:10 -050097 mGlslangWrapper(nullptr),
98 mCurrentQueueSerial(),
99 mLastCompletedQueueSerial(),
100 mInFlightCommands()
Jamie Madill9e54b5a2016-05-25 12:57:39 -0400101{
Jamie Madill4c26fc22017-02-24 11:04:10 -0500102 ++mCurrentQueueSerial;
Jamie Madill9e54b5a2016-05-25 12:57:39 -0400103}
104
105RendererVk::~RendererVk()
106{
Jamie Madill0c0dc342017-03-24 14:18:51 -0400107 if (!mInFlightCommands.empty() || !mInFlightFences.empty() || !mGarbage.empty())
Jamie Madill4c26fc22017-02-24 11:04:10 -0500108 {
109 vk::Error error = finish();
110 if (error.isError())
111 {
112 ERR() << "Error during VK shutdown: " << error;
113 }
114 }
115
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500116 if (mGlslangWrapper)
117 {
118 GlslangWrapper::ReleaseReference();
119 mGlslangWrapper = nullptr;
120 }
121
Jamie Madill5deea722017-02-16 10:44:46 -0500122 if (mCommandBuffer.valid())
123 {
124 mCommandBuffer.destroy(mDevice);
125 }
126
127 if (mCommandPool.valid())
128 {
129 mCommandPool.destroy(mDevice);
130 }
Jamie Madill4d0bf552016-12-28 15:45:24 -0500131
132 if (mDevice)
133 {
134 vkDestroyDevice(mDevice, nullptr);
135 mDevice = VK_NULL_HANDLE;
136 }
137
Jamie Madill0448ec82016-12-23 13:41:47 -0500138 if (mDebugReportCallback)
139 {
140 ASSERT(mInstance);
141 auto destroyDebugReportCallback = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
142 vkGetInstanceProcAddr(mInstance, "vkDestroyDebugReportCallbackEXT"));
143 ASSERT(destroyDebugReportCallback);
144 destroyDebugReportCallback(mInstance, mDebugReportCallback, nullptr);
145 }
146
Jamie Madill4d0bf552016-12-28 15:45:24 -0500147 if (mInstance)
148 {
149 vkDestroyInstance(mInstance, nullptr);
150 mInstance = VK_NULL_HANDLE;
151 }
152
153 mPhysicalDevice = VK_NULL_HANDLE;
Jamie Madill327ba852016-11-30 12:38:28 -0500154}
155
Frank Henigman29f148b2016-11-23 21:05:36 -0500156vk::Error RendererVk::initialize(const egl::AttributeMap &attribs, const char *wsiName)
Jamie Madill327ba852016-11-30 12:38:28 -0500157{
Jamie Madilla66779f2017-01-06 10:43:44 -0500158#if !defined(NDEBUG)
159 // Validation layers enabled by default in Debug.
160 mEnableValidationLayers = true;
161#endif
162
163 // If specified in the attributes, override the default.
164 if (attribs.contains(EGL_PLATFORM_ANGLE_ENABLE_VALIDATION_LAYER_ANGLE))
165 {
166 mEnableValidationLayers =
167 (attribs.get(EGL_PLATFORM_ANGLE_ENABLE_VALIDATION_LAYER_ANGLE, EGL_FALSE) == EGL_TRUE);
168 }
169
170 // If we're loading the validation layers, we could be running from any random directory.
171 // Change to the executable directory so we can find the layers, then change back to the
172 // previous directory to be safe we don't disrupt the application.
173 std::string previousCWD;
174
175 if (mEnableValidationLayers)
176 {
177 const auto &cwd = angle::GetCWD();
178 if (!cwd.valid())
179 {
Yuly Novikovbcb3f9b2017-01-27 22:45:18 -0500180 ERR() << "Error getting CWD for Vulkan layers init.";
Jamie Madilla66779f2017-01-06 10:43:44 -0500181 mEnableValidationLayers = false;
182 }
183 else
184 {
185 previousCWD = cwd.value();
186 }
187 const char *exeDir = angle::GetExecutableDirectory();
188 angle::SetCWD(exeDir);
189 }
190
Jamie Madill0448ec82016-12-23 13:41:47 -0500191 // Gather global layer properties.
192 uint32_t instanceLayerCount = 0;
193 ANGLE_VK_TRY(vkEnumerateInstanceLayerProperties(&instanceLayerCount, nullptr));
194
195 std::vector<VkLayerProperties> instanceLayerProps(instanceLayerCount);
196 if (instanceLayerCount > 0)
197 {
198 ANGLE_VK_TRY(
199 vkEnumerateInstanceLayerProperties(&instanceLayerCount, instanceLayerProps.data()));
200 }
201
Jamie Madille09bd5d2016-11-29 16:20:35 -0500202 uint32_t instanceExtensionCount = 0;
203 ANGLE_VK_TRY(vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtensionCount, nullptr));
204
205 std::vector<VkExtensionProperties> instanceExtensionProps(instanceExtensionCount);
206 if (instanceExtensionCount > 0)
207 {
208 ANGLE_VK_TRY(vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtensionCount,
209 instanceExtensionProps.data()));
210 }
211
Jamie Madill0448ec82016-12-23 13:41:47 -0500212 if (mEnableValidationLayers)
213 {
214 // Verify the standard validation layers are available.
215 if (!HasStandardValidationLayer(instanceLayerProps))
216 {
217 // Generate an error if the attribute was requested, warning otherwise.
218 if (attribs.contains(EGL_PLATFORM_ANGLE_ENABLE_VALIDATION_LAYER_ANGLE))
219 {
Yuly Novikovbcb3f9b2017-01-27 22:45:18 -0500220 ERR() << "Vulkan standard validation layers are missing.";
Jamie Madill0448ec82016-12-23 13:41:47 -0500221 }
222 else
223 {
Yuly Novikovbcb3f9b2017-01-27 22:45:18 -0500224 WARN() << "Vulkan standard validation layers are missing.";
Jamie Madill0448ec82016-12-23 13:41:47 -0500225 }
226 mEnableValidationLayers = false;
227 }
228 }
229
Jamie Madille09bd5d2016-11-29 16:20:35 -0500230 std::vector<const char *> enabledInstanceExtensions;
231 enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
Frank Henigman29f148b2016-11-23 21:05:36 -0500232 enabledInstanceExtensions.push_back(wsiName);
Jamie Madille09bd5d2016-11-29 16:20:35 -0500233
Jamie Madill0448ec82016-12-23 13:41:47 -0500234 // TODO(jmadill): Should be able to continue initialization if debug report ext missing.
235 if (mEnableValidationLayers)
236 {
237 enabledInstanceExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
238 }
239
Jamie Madille09bd5d2016-11-29 16:20:35 -0500240 // Verify the required extensions are in the extension names set. Fail if not.
241 ANGLE_VK_TRY(VerifyExtensionsPresent(instanceExtensionProps, enabledInstanceExtensions));
242
Jamie Madill327ba852016-11-30 12:38:28 -0500243 VkApplicationInfo applicationInfo;
244 applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
245 applicationInfo.pNext = nullptr;
246 applicationInfo.pApplicationName = "ANGLE";
247 applicationInfo.applicationVersion = 1;
248 applicationInfo.pEngineName = "ANGLE";
249 applicationInfo.engineVersion = 1;
250 applicationInfo.apiVersion = VK_API_VERSION_1_0;
251
252 VkInstanceCreateInfo instanceInfo;
253 instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
254 instanceInfo.pNext = nullptr;
255 instanceInfo.flags = 0;
256 instanceInfo.pApplicationInfo = &applicationInfo;
257
Jamie Madille09bd5d2016-11-29 16:20:35 -0500258 // Enable requested layers and extensions.
259 instanceInfo.enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size());
260 instanceInfo.ppEnabledExtensionNames =
261 enabledInstanceExtensions.empty() ? nullptr : enabledInstanceExtensions.data();
Jamie Madill0448ec82016-12-23 13:41:47 -0500262 instanceInfo.enabledLayerCount = mEnableValidationLayers ? 1u : 0u;
263 instanceInfo.ppEnabledLayerNames =
264 mEnableValidationLayers ? &g_VkStdValidationLayerName : nullptr;
Jamie Madill327ba852016-11-30 12:38:28 -0500265
266 ANGLE_VK_TRY(vkCreateInstance(&instanceInfo, nullptr, &mInstance));
267
Jamie Madill0448ec82016-12-23 13:41:47 -0500268 if (mEnableValidationLayers)
269 {
Jamie Madilla66779f2017-01-06 10:43:44 -0500270 // Change back to the previous working directory now that we've loaded the instance -
271 // the validation layers should be loaded at this point.
272 angle::SetCWD(previousCWD.c_str());
273
Jamie Madill0448ec82016-12-23 13:41:47 -0500274 VkDebugReportCallbackCreateInfoEXT debugReportInfo;
275
276 debugReportInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
277 debugReportInfo.pNext = nullptr;
278 debugReportInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT |
279 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
280 VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT;
281 debugReportInfo.pfnCallback = &DebugReportCallback;
282 debugReportInfo.pUserData = this;
283
284 auto createDebugReportCallback = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
285 vkGetInstanceProcAddr(mInstance, "vkCreateDebugReportCallbackEXT"));
286 ASSERT(createDebugReportCallback);
287 ANGLE_VK_TRY(
288 createDebugReportCallback(mInstance, &debugReportInfo, nullptr, &mDebugReportCallback));
289 }
290
Jamie Madill4d0bf552016-12-28 15:45:24 -0500291 uint32_t physicalDeviceCount = 0;
292 ANGLE_VK_TRY(vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, nullptr));
293 ANGLE_VK_CHECK(physicalDeviceCount > 0, VK_ERROR_INITIALIZATION_FAILED);
294
295 // TODO(jmadill): Handle multiple physical devices. For now, use the first device.
296 physicalDeviceCount = 1;
297 ANGLE_VK_TRY(vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, &mPhysicalDevice));
298
299 vkGetPhysicalDeviceProperties(mPhysicalDevice, &mPhysicalDeviceProperties);
300
301 // Ensure we can find a graphics queue family.
302 uint32_t queueCount = 0;
303 vkGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount, nullptr);
304
305 ANGLE_VK_CHECK(queueCount > 0, VK_ERROR_INITIALIZATION_FAILED);
306
307 mQueueFamilyProperties.resize(queueCount);
308 vkGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount,
309 mQueueFamilyProperties.data());
310
311 size_t graphicsQueueFamilyCount = false;
312 uint32_t firstGraphicsQueueFamily = 0;
313 for (uint32_t familyIndex = 0; familyIndex < queueCount; ++familyIndex)
314 {
315 const auto &queueInfo = mQueueFamilyProperties[familyIndex];
316 if ((queueInfo.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
317 {
318 ASSERT(queueInfo.queueCount > 0);
319 graphicsQueueFamilyCount++;
320 if (firstGraphicsQueueFamily == 0)
321 {
322 firstGraphicsQueueFamily = familyIndex;
323 }
324 break;
325 }
326 }
327
328 ANGLE_VK_CHECK(graphicsQueueFamilyCount > 0, VK_ERROR_INITIALIZATION_FAILED);
329
330 // If only one queue family, go ahead and initialize the device. If there is more than one
331 // queue, we'll have to wait until we see a WindowSurface to know which supports present.
332 if (graphicsQueueFamilyCount == 1)
333 {
334 ANGLE_TRY(initializeDevice(firstGraphicsQueueFamily));
335 }
336
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500337 VkPhysicalDeviceMemoryProperties memoryProperties;
338 vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &memoryProperties);
339
340 for (uint32_t memoryIndex = 0; memoryIndex < memoryProperties.memoryTypeCount; ++memoryIndex)
341 {
342 if ((memoryProperties.memoryTypes[memoryIndex].propertyFlags &
343 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
344 {
345 mHostVisibleMemoryIndex = memoryIndex;
346 break;
347 }
348 }
349
350 ANGLE_VK_CHECK(mHostVisibleMemoryIndex < std::numeric_limits<uint32_t>::max(),
351 VK_ERROR_INITIALIZATION_FAILED);
352
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500353 mGlslangWrapper = GlslangWrapper::GetReference();
354
Jamie Madill327ba852016-11-30 12:38:28 -0500355 return vk::NoError();
Jamie Madill9e54b5a2016-05-25 12:57:39 -0400356}
357
Jamie Madill4d0bf552016-12-28 15:45:24 -0500358vk::Error RendererVk::initializeDevice(uint32_t queueFamilyIndex)
359{
360 uint32_t deviceLayerCount = 0;
361 ANGLE_VK_TRY(vkEnumerateDeviceLayerProperties(mPhysicalDevice, &deviceLayerCount, nullptr));
362
363 std::vector<VkLayerProperties> deviceLayerProps(deviceLayerCount);
364 if (deviceLayerCount > 0)
365 {
366 ANGLE_VK_TRY(vkEnumerateDeviceLayerProperties(mPhysicalDevice, &deviceLayerCount,
367 deviceLayerProps.data()));
368 }
369
370 uint32_t deviceExtensionCount = 0;
371 ANGLE_VK_TRY(vkEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr,
372 &deviceExtensionCount, nullptr));
373
374 std::vector<VkExtensionProperties> deviceExtensionProps(deviceExtensionCount);
375 if (deviceExtensionCount > 0)
376 {
377 ANGLE_VK_TRY(vkEnumerateDeviceExtensionProperties(
378 mPhysicalDevice, nullptr, &deviceExtensionCount, deviceExtensionProps.data()));
379 }
380
381 if (mEnableValidationLayers)
382 {
383 if (!HasStandardValidationLayer(deviceLayerProps))
384 {
Yuly Novikovbcb3f9b2017-01-27 22:45:18 -0500385 WARN() << "Vulkan standard validation layer is missing.";
Jamie Madill4d0bf552016-12-28 15:45:24 -0500386 mEnableValidationLayers = false;
387 }
388 }
389
390 std::vector<const char *> enabledDeviceExtensions;
391 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
392
393 ANGLE_VK_TRY(VerifyExtensionsPresent(deviceExtensionProps, enabledDeviceExtensions));
394
395 VkDeviceQueueCreateInfo queueCreateInfo;
396
397 float zeroPriority = 0.0f;
398
399 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
400 queueCreateInfo.pNext = nullptr;
401 queueCreateInfo.flags = 0;
402 queueCreateInfo.queueFamilyIndex = queueFamilyIndex;
403 queueCreateInfo.queueCount = 1;
404 queueCreateInfo.pQueuePriorities = &zeroPriority;
405
406 // Initialize the device
407 VkDeviceCreateInfo createInfo;
408
409 createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
410 createInfo.pNext = nullptr;
411 createInfo.flags = 0;
412 createInfo.queueCreateInfoCount = 1;
413 createInfo.pQueueCreateInfos = &queueCreateInfo;
414 createInfo.enabledLayerCount = mEnableValidationLayers ? 1u : 0u;
415 createInfo.ppEnabledLayerNames =
416 mEnableValidationLayers ? &g_VkStdValidationLayerName : nullptr;
417 createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size());
418 createInfo.ppEnabledExtensionNames =
419 enabledDeviceExtensions.empty() ? nullptr : enabledDeviceExtensions.data();
420 createInfo.pEnabledFeatures = nullptr; // TODO(jmadill): features
421
422 ANGLE_VK_TRY(vkCreateDevice(mPhysicalDevice, &createInfo, nullptr, &mDevice));
423
424 mCurrentQueueFamilyIndex = queueFamilyIndex;
425
426 vkGetDeviceQueue(mDevice, mCurrentQueueFamilyIndex, 0, &mQueue);
427
428 // Initialize the command pool now that we know the queue family index.
429 VkCommandPoolCreateInfo commandPoolInfo;
430 commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
431 commandPoolInfo.pNext = nullptr;
432 // TODO(jmadill): Investigate transient command buffers.
433 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
434 commandPoolInfo.queueFamilyIndex = mCurrentQueueFamilyIndex;
435
Jamie Madill5deea722017-02-16 10:44:46 -0500436 ANGLE_TRY(mCommandPool.init(mDevice, commandPoolInfo));
Jamie Madill4d0bf552016-12-28 15:45:24 -0500437
Jamie Madill5deea722017-02-16 10:44:46 -0500438 mCommandBuffer.setCommandPool(&mCommandPool);
Jamie Madill4d0bf552016-12-28 15:45:24 -0500439
440 return vk::NoError();
441}
442
443vk::ErrorOrResult<uint32_t> RendererVk::selectPresentQueueForSurface(VkSurfaceKHR surface)
444{
445 // We've already initialized a device, and can't re-create it unless it's never been used.
446 // TODO(jmadill): Handle the re-creation case if necessary.
447 if (mDevice != VK_NULL_HANDLE)
448 {
449 ASSERT(mCurrentQueueFamilyIndex != std::numeric_limits<uint32_t>::max());
450
451 // Check if the current device supports present on this surface.
452 VkBool32 supportsPresent = VK_FALSE;
453 ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceSupportKHR(mPhysicalDevice, mCurrentQueueFamilyIndex,
454 surface, &supportsPresent));
455
456 return (supportsPresent == VK_TRUE);
457 }
458
459 // Find a graphics and present queue.
460 Optional<uint32_t> newPresentQueue;
461 uint32_t queueCount = static_cast<uint32_t>(mQueueFamilyProperties.size());
462 for (uint32_t queueIndex = 0; queueIndex < queueCount; ++queueIndex)
463 {
464 const auto &queueInfo = mQueueFamilyProperties[queueIndex];
465 if ((queueInfo.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
466 {
467 VkBool32 supportsPresent = VK_FALSE;
468 ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceSupportKHR(mPhysicalDevice, queueIndex, surface,
469 &supportsPresent));
470
471 if (supportsPresent == VK_TRUE)
472 {
473 newPresentQueue = queueIndex;
474 break;
475 }
476 }
477 }
478
479 ANGLE_VK_CHECK(newPresentQueue.valid(), VK_ERROR_INITIALIZATION_FAILED);
480 ANGLE_TRY(initializeDevice(newPresentQueue.value()));
481
482 return newPresentQueue.value();
483}
484
485std::string RendererVk::getVendorString() const
486{
487 switch (mPhysicalDeviceProperties.vendorID)
488 {
489 case VENDOR_ID_AMD:
490 return "Advanced Micro Devices";
491 case VENDOR_ID_NVIDIA:
492 return "NVIDIA";
493 case VENDOR_ID_INTEL:
494 return "Intel";
495 default:
496 {
497 // TODO(jmadill): More vendor IDs.
498 std::stringstream strstr;
499 strstr << "Vendor ID: " << mPhysicalDeviceProperties.vendorID;
500 return strstr.str();
501 }
502 }
503}
504
Jamie Madille09bd5d2016-11-29 16:20:35 -0500505std::string RendererVk::getRendererDescription() const
506{
Jamie Madill4d0bf552016-12-28 15:45:24 -0500507 std::stringstream strstr;
508
509 uint32_t apiVersion = mPhysicalDeviceProperties.apiVersion;
510
511 strstr << "Vulkan ";
512 strstr << VK_VERSION_MAJOR(apiVersion) << ".";
513 strstr << VK_VERSION_MINOR(apiVersion) << ".";
514 strstr << VK_VERSION_PATCH(apiVersion);
515
516 strstr << "(" << mPhysicalDeviceProperties.deviceName << ")";
517
518 return strstr.str();
Jamie Madille09bd5d2016-11-29 16:20:35 -0500519}
520
Jamie Madillacccc6c2016-05-03 17:22:10 -0400521void RendererVk::ensureCapsInitialized() const
522{
523 if (!mCapsInitialized)
524 {
525 generateCaps(&mNativeCaps, &mNativeTextureCaps, &mNativeExtensions, &mNativeLimitations);
526 mCapsInitialized = true;
527 }
528}
529
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500530void RendererVk::generateCaps(gl::Caps *outCaps,
Jamie Madillacccc6c2016-05-03 17:22:10 -0400531 gl::TextureCapsMap * /*outTextureCaps*/,
Jamie Madillb8353b02017-01-25 12:57:21 -0800532 gl::Extensions *outExtensions,
Jamie Madillacccc6c2016-05-03 17:22:10 -0400533 gl::Limitations * /* outLimitations */) const
534{
Jamie Madill327ba852016-11-30 12:38:28 -0500535 // TODO(jmadill): Caps.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500536 outCaps->maxDrawBuffers = 1;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800537 outCaps->maxVertexAttributes = gl::MAX_VERTEX_ATTRIBS;
538 outCaps->maxVertexAttribBindings = gl::MAX_VERTEX_ATTRIB_BINDINGS;
Jamie Madillb8353b02017-01-25 12:57:21 -0800539
540 // Enable this for simple buffer readback testing, but some functionality is missing.
541 // TODO(jmadill): Support full mapBufferRange extension.
542 outExtensions->mapBuffer = true;
543 outExtensions->mapBufferRange = true;
Jamie Madillacccc6c2016-05-03 17:22:10 -0400544}
545
546const gl::Caps &RendererVk::getNativeCaps() const
547{
548 ensureCapsInitialized();
549 return mNativeCaps;
550}
551
552const gl::TextureCapsMap &RendererVk::getNativeTextureCaps() const
553{
554 ensureCapsInitialized();
555 return mNativeTextureCaps;
556}
557
558const gl::Extensions &RendererVk::getNativeExtensions() const
559{
560 ensureCapsInitialized();
561 return mNativeExtensions;
562}
563
564const gl::Limitations &RendererVk::getNativeLimitations() const
565{
566 ensureCapsInitialized();
567 return mNativeLimitations;
568}
569
Jamie Madill0c0dc342017-03-24 14:18:51 -0400570vk::Error RendererVk::getStartedCommandBuffer(vk::CommandBuffer **commandBufferOut)
Jamie Madill4d0bf552016-12-28 15:45:24 -0500571{
Jamie Madill0c0dc342017-03-24 14:18:51 -0400572 ANGLE_TRY(mCommandBuffer.begin(mDevice));
573 *commandBufferOut = &mCommandBuffer;
574 return vk::NoError();
Jamie Madill4d0bf552016-12-28 15:45:24 -0500575}
576
Jamie Madill0c0dc342017-03-24 14:18:51 -0400577vk::Error RendererVk::submitCommandBuffer(vk::CommandBuffer *commandBuffer)
Jamie Madill4d0bf552016-12-28 15:45:24 -0500578{
Jamie Madill0c0dc342017-03-24 14:18:51 -0400579 ANGLE_TRY(commandBuffer->end());
580
Jamie Madill4d0bf552016-12-28 15:45:24 -0500581 VkFenceCreateInfo fenceInfo;
582 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
583 fenceInfo.pNext = nullptr;
584 fenceInfo.flags = 0;
585
Jamie Madill4d0bf552016-12-28 15:45:24 -0500586 VkSubmitInfo submitInfo;
587 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
588 submitInfo.pNext = nullptr;
589 submitInfo.waitSemaphoreCount = 0;
590 submitInfo.pWaitSemaphores = nullptr;
591 submitInfo.pWaitDstStageMask = nullptr;
592 submitInfo.commandBufferCount = 1;
Jamie Madill0c0dc342017-03-24 14:18:51 -0400593 submitInfo.pCommandBuffers = commandBuffer->ptr();
Jamie Madill4d0bf552016-12-28 15:45:24 -0500594 submitInfo.signalSemaphoreCount = 0;
595 submitInfo.pSignalSemaphores = nullptr;
596
597 // TODO(jmadill): Investigate how to properly submit command buffers.
Jamie Madill4c26fc22017-02-24 11:04:10 -0500598 ANGLE_TRY(submit(submitInfo));
Jamie Madill4d0bf552016-12-28 15:45:24 -0500599
Jamie Madillf651c772017-02-21 15:03:51 -0500600 return vk::NoError();
601}
602
Jamie Madill0c0dc342017-03-24 14:18:51 -0400603vk::Error RendererVk::submitAndFinishCommandBuffer(vk::CommandBuffer *commandBuffer)
Jamie Madillf651c772017-02-21 15:03:51 -0500604{
605 ANGLE_TRY(submitCommandBuffer(commandBuffer));
Jamie Madill4c26fc22017-02-24 11:04:10 -0500606 ANGLE_TRY(finish());
Jamie Madill4d0bf552016-12-28 15:45:24 -0500607
608 return vk::NoError();
609}
610
Jamie Madill0c0dc342017-03-24 14:18:51 -0400611vk::Error RendererVk::submitCommandsWithSync(vk::CommandBuffer *commandBuffer,
Jamie Madille918de22017-04-12 10:21:11 -0400612 const vk::Semaphore &waitSemaphore,
613 const vk::Semaphore &signalSemaphore)
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500614{
Jamie Madill0c0dc342017-03-24 14:18:51 -0400615 ANGLE_TRY(commandBuffer->end());
616
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500617 VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
618
619 VkSubmitInfo submitInfo;
620 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
621 submitInfo.pNext = nullptr;
622 submitInfo.waitSemaphoreCount = 1;
Jamie Madille918de22017-04-12 10:21:11 -0400623 submitInfo.pWaitSemaphores = waitSemaphore.ptr();
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500624 submitInfo.pWaitDstStageMask = &waitStageMask;
625 submitInfo.commandBufferCount = 1;
Jamie Madill0c0dc342017-03-24 14:18:51 -0400626 submitInfo.pCommandBuffers = commandBuffer->ptr();
Jamie Madille918de22017-04-12 10:21:11 -0400627 submitInfo.signalSemaphoreCount = 1;
628 submitInfo.pSignalSemaphores = signalSemaphore.ptr();
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500629
630 // TODO(jmadill): Investigate how to properly queue command buffer work.
Jamie Madill0c0dc342017-03-24 14:18:51 -0400631 ANGLE_TRY(submitFrame(submitInfo));
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500632
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500633 return vk::NoError();
634}
635
Jamie Madill4c26fc22017-02-24 11:04:10 -0500636vk::Error RendererVk::finish()
637{
638 ASSERT(mQueue != VK_NULL_HANDLE);
Jamie Madill4c26fc22017-02-24 11:04:10 -0500639 ANGLE_VK_TRY(vkQueueWaitIdle(mQueue));
Jamie Madill0c0dc342017-03-24 14:18:51 -0400640 freeAllInFlightResources();
Jamie Madill4c26fc22017-02-24 11:04:10 -0500641 return vk::NoError();
642}
643
Jamie Madill0c0dc342017-03-24 14:18:51 -0400644void RendererVk::freeAllInFlightResources()
645{
646 for (auto &fence : mInFlightFences)
647 {
648 fence.destroy(mDevice);
649 }
650 mInFlightFences.clear();
651
652 for (auto &command : mInFlightCommands)
653 {
654 command.destroy(mDevice);
655 }
656 mInFlightCommands.clear();
657
658 for (auto &garbage : mGarbage)
659 {
660 garbage->destroy(mDevice);
661 }
662 mGarbage.clear();
663}
664
Jamie Madill4c26fc22017-02-24 11:04:10 -0500665vk::Error RendererVk::checkInFlightCommands()
666{
Jamie Madill0c0dc342017-03-24 14:18:51 -0400667 size_t finishedIndex = 0;
Jamie Madillf651c772017-02-21 15:03:51 -0500668
Jamie Madill4c26fc22017-02-24 11:04:10 -0500669 // Check if any in-flight command buffers are finished.
Jamie Madill0c0dc342017-03-24 14:18:51 -0400670 for (size_t index = 0; index < mInFlightFences.size(); index++)
Jamie Madill4c26fc22017-02-24 11:04:10 -0500671 {
Jamie Madill0c0dc342017-03-24 14:18:51 -0400672 auto *inFlightFence = &mInFlightFences[index];
Jamie Madill4c26fc22017-02-24 11:04:10 -0500673
Jamie Madill0c0dc342017-03-24 14:18:51 -0400674 VkResult result = inFlightFence->get().getStatus(mDevice);
675 if (result == VK_NOT_READY)
676 break;
677 ANGLE_VK_TRY(result);
678 finishedIndex = index + 1;
679
680 // Release the fence handle.
681 // TODO(jmadill): Re-use fences.
682 inFlightFence->destroy(mDevice);
Jamie Madill4c26fc22017-02-24 11:04:10 -0500683 }
684
Jamie Madill0c0dc342017-03-24 14:18:51 -0400685 if (finishedIndex == 0)
686 return vk::NoError();
Jamie Madillf651c772017-02-21 15:03:51 -0500687
Jamie Madill0c0dc342017-03-24 14:18:51 -0400688 Serial finishedSerial = mInFlightFences[finishedIndex - 1].queueSerial();
689 mInFlightFences.erase(mInFlightFences.begin(), mInFlightFences.begin() + finishedIndex);
690
691 size_t completedCBIndex = 0;
692 for (size_t cbIndex = 0; cbIndex < mInFlightCommands.size(); ++cbIndex)
693 {
694 auto *inFlightCB = &mInFlightCommands[cbIndex];
695 if (inFlightCB->queueSerial() > finishedSerial)
696 break;
697
698 completedCBIndex = cbIndex + 1;
699 inFlightCB->destroy(mDevice);
700 }
701
702 if (completedCBIndex == 0)
703 return vk::NoError();
704
705 mInFlightCommands.erase(mInFlightCommands.begin(),
706 mInFlightCommands.begin() + completedCBIndex);
707
708 size_t freeIndex = 0;
709 for (; freeIndex < mGarbage.size(); ++freeIndex)
710 {
711 if (!mGarbage[freeIndex]->destroyIfComplete(mDevice, finishedSerial))
712 break;
713 }
714
715 // Remove the entries from the garbage list - they should be ready to go.
716 if (freeIndex > 0)
717 {
718 mGarbage.erase(mGarbage.begin(), mGarbage.begin() + freeIndex);
Jamie Madillf651c772017-02-21 15:03:51 -0500719 }
720
Jamie Madill4c26fc22017-02-24 11:04:10 -0500721 return vk::NoError();
722}
723
724vk::Error RendererVk::submit(const VkSubmitInfo &submitInfo)
725{
Jamie Madill0c0dc342017-03-24 14:18:51 -0400726 ANGLE_VK_TRY(vkQueueSubmit(mQueue, 1, &submitInfo, VK_NULL_HANDLE));
Jamie Madill4c26fc22017-02-24 11:04:10 -0500727
728 // Store this command buffer in the in-flight list.
Jamie Madill0c0dc342017-03-24 14:18:51 -0400729 mInFlightCommands.emplace_back(std::move(mCommandBuffer), mCurrentQueueSerial);
Jamie Madill4c26fc22017-02-24 11:04:10 -0500730
731 // Sanity check.
732 ASSERT(mInFlightCommands.size() < 1000u);
733
Jamie Madill0c0dc342017-03-24 14:18:51 -0400734 // Increment the queue serial. If this fails, we should restart ANGLE.
Jamie Madill4c26fc22017-02-24 11:04:10 -0500735 ANGLE_VK_CHECK(++mCurrentQueueSerial, VK_ERROR_OUT_OF_HOST_MEMORY);
Jamie Madill0c0dc342017-03-24 14:18:51 -0400736
737 return vk::NoError();
738}
739
740vk::Error RendererVk::submitFrame(const VkSubmitInfo &submitInfo)
741{
742 VkFenceCreateInfo createInfo;
743 createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
744 createInfo.pNext = nullptr;
745 createInfo.flags = 0;
746
747 vk::Fence fence;
748 ANGLE_TRY(fence.init(mDevice, createInfo));
749
750 ANGLE_VK_TRY(vkQueueSubmit(mQueue, 1, &submitInfo, fence.getHandle()));
751
752 // Store this command buffer in the in-flight list.
753 mInFlightFences.emplace_back(std::move(fence), mCurrentQueueSerial);
754 mInFlightCommands.emplace_back(std::move(mCommandBuffer), mCurrentQueueSerial);
755
756 // Sanity check.
757 ASSERT(mInFlightCommands.size() < 1000u);
758
759 // Increment the queue serial. If this fails, we should restart ANGLE.
760 ANGLE_VK_CHECK(++mCurrentQueueSerial, VK_ERROR_OUT_OF_HOST_MEMORY);
761
762 ANGLE_TRY(checkInFlightCommands());
763
Jamie Madill4c26fc22017-02-24 11:04:10 -0500764 return vk::NoError();
765}
766
Jamie Madill5deea722017-02-16 10:44:46 -0500767vk::Error RendererVk::createStagingImage(TextureDimension dimension,
768 const vk::Format &format,
769 const gl::Extents &extent,
770 vk::StagingImage *imageOut)
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500771{
772 ASSERT(mHostVisibleMemoryIndex != std::numeric_limits<uint32_t>::max());
773
Jamie Madill5deea722017-02-16 10:44:46 -0500774 ANGLE_TRY(imageOut->init(mDevice, mCurrentQueueFamilyIndex, mHostVisibleMemoryIndex, dimension,
775 format.native, extent));
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500776
Jamie Madill5deea722017-02-16 10:44:46 -0500777 return vk::NoError();
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500778}
779
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500780GlslangWrapper *RendererVk::getGlslangWrapper()
781{
782 return mGlslangWrapper;
783}
784
Jamie Madill4c26fc22017-02-24 11:04:10 -0500785Serial RendererVk::getCurrentQueueSerial() const
786{
787 return mCurrentQueueSerial;
788}
789
Jamie Madill9e54b5a2016-05-25 12:57:39 -0400790} // namespace rx