blob: 0a0f3b85b16769d108bf32f8af372c4cdf3e98ce [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),
Jamie Madillfb05bcb2017-06-07 15:43:18 -040098 mLastCompletedQueueSerial(mQueueSerialFactory.generate()),
99 mCurrentQueueSerial(mQueueSerialFactory.generate()),
Jamie Madill4c26fc22017-02-24 11:04:10 -0500100 mInFlightCommands()
Jamie Madill9e54b5a2016-05-25 12:57:39 -0400101{
102}
103
104RendererVk::~RendererVk()
105{
Jamie Madill0c0dc342017-03-24 14:18:51 -0400106 if (!mInFlightCommands.empty() || !mInFlightFences.empty() || !mGarbage.empty())
Jamie Madill4c26fc22017-02-24 11:04:10 -0500107 {
108 vk::Error error = finish();
109 if (error.isError())
110 {
111 ERR() << "Error during VK shutdown: " << error;
112 }
113 }
114
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500115 if (mGlslangWrapper)
116 {
117 GlslangWrapper::ReleaseReference();
118 mGlslangWrapper = nullptr;
119 }
120
Jamie Madill5deea722017-02-16 10:44:46 -0500121 if (mCommandBuffer.valid())
122 {
123 mCommandBuffer.destroy(mDevice);
124 }
125
126 if (mCommandPool.valid())
127 {
128 mCommandPool.destroy(mDevice);
129 }
Jamie Madill4d0bf552016-12-28 15:45:24 -0500130
131 if (mDevice)
132 {
133 vkDestroyDevice(mDevice, nullptr);
134 mDevice = VK_NULL_HANDLE;
135 }
136
Jamie Madill0448ec82016-12-23 13:41:47 -0500137 if (mDebugReportCallback)
138 {
139 ASSERT(mInstance);
140 auto destroyDebugReportCallback = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
141 vkGetInstanceProcAddr(mInstance, "vkDestroyDebugReportCallbackEXT"));
142 ASSERT(destroyDebugReportCallback);
143 destroyDebugReportCallback(mInstance, mDebugReportCallback, nullptr);
144 }
145
Jamie Madill4d0bf552016-12-28 15:45:24 -0500146 if (mInstance)
147 {
148 vkDestroyInstance(mInstance, nullptr);
149 mInstance = VK_NULL_HANDLE;
150 }
151
152 mPhysicalDevice = VK_NULL_HANDLE;
Jamie Madill327ba852016-11-30 12:38:28 -0500153}
154
Frank Henigman29f148b2016-11-23 21:05:36 -0500155vk::Error RendererVk::initialize(const egl::AttributeMap &attribs, const char *wsiName)
Jamie Madill327ba852016-11-30 12:38:28 -0500156{
Jamie Madilla66779f2017-01-06 10:43:44 -0500157#if !defined(NDEBUG)
158 // Validation layers enabled by default in Debug.
159 mEnableValidationLayers = true;
160#endif
161
162 // If specified in the attributes, override the default.
163 if (attribs.contains(EGL_PLATFORM_ANGLE_ENABLE_VALIDATION_LAYER_ANGLE))
164 {
165 mEnableValidationLayers =
166 (attribs.get(EGL_PLATFORM_ANGLE_ENABLE_VALIDATION_LAYER_ANGLE, EGL_FALSE) == EGL_TRUE);
167 }
168
169 // If we're loading the validation layers, we could be running from any random directory.
170 // Change to the executable directory so we can find the layers, then change back to the
171 // previous directory to be safe we don't disrupt the application.
172 std::string previousCWD;
173
174 if (mEnableValidationLayers)
175 {
176 const auto &cwd = angle::GetCWD();
177 if (!cwd.valid())
178 {
Yuly Novikovbcb3f9b2017-01-27 22:45:18 -0500179 ERR() << "Error getting CWD for Vulkan layers init.";
Jamie Madilla66779f2017-01-06 10:43:44 -0500180 mEnableValidationLayers = false;
181 }
182 else
183 {
184 previousCWD = cwd.value();
185 }
186 const char *exeDir = angle::GetExecutableDirectory();
187 angle::SetCWD(exeDir);
188 }
189
Jamie Madill0448ec82016-12-23 13:41:47 -0500190 // Gather global layer properties.
191 uint32_t instanceLayerCount = 0;
192 ANGLE_VK_TRY(vkEnumerateInstanceLayerProperties(&instanceLayerCount, nullptr));
193
194 std::vector<VkLayerProperties> instanceLayerProps(instanceLayerCount);
195 if (instanceLayerCount > 0)
196 {
197 ANGLE_VK_TRY(
198 vkEnumerateInstanceLayerProperties(&instanceLayerCount, instanceLayerProps.data()));
199 }
200
Jamie Madille09bd5d2016-11-29 16:20:35 -0500201 uint32_t instanceExtensionCount = 0;
202 ANGLE_VK_TRY(vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtensionCount, nullptr));
203
204 std::vector<VkExtensionProperties> instanceExtensionProps(instanceExtensionCount);
205 if (instanceExtensionCount > 0)
206 {
207 ANGLE_VK_TRY(vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtensionCount,
208 instanceExtensionProps.data()));
209 }
210
Jamie Madill0448ec82016-12-23 13:41:47 -0500211 if (mEnableValidationLayers)
212 {
213 // Verify the standard validation layers are available.
214 if (!HasStandardValidationLayer(instanceLayerProps))
215 {
216 // Generate an error if the attribute was requested, warning otherwise.
217 if (attribs.contains(EGL_PLATFORM_ANGLE_ENABLE_VALIDATION_LAYER_ANGLE))
218 {
Yuly Novikovbcb3f9b2017-01-27 22:45:18 -0500219 ERR() << "Vulkan standard validation layers are missing.";
Jamie Madill0448ec82016-12-23 13:41:47 -0500220 }
221 else
222 {
Yuly Novikovbcb3f9b2017-01-27 22:45:18 -0500223 WARN() << "Vulkan standard validation layers are missing.";
Jamie Madill0448ec82016-12-23 13:41:47 -0500224 }
225 mEnableValidationLayers = false;
226 }
227 }
228
Jamie Madille09bd5d2016-11-29 16:20:35 -0500229 std::vector<const char *> enabledInstanceExtensions;
230 enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
Frank Henigman29f148b2016-11-23 21:05:36 -0500231 enabledInstanceExtensions.push_back(wsiName);
Jamie Madille09bd5d2016-11-29 16:20:35 -0500232
Jamie Madill0448ec82016-12-23 13:41:47 -0500233 // TODO(jmadill): Should be able to continue initialization if debug report ext missing.
234 if (mEnableValidationLayers)
235 {
236 enabledInstanceExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
237 }
238
Jamie Madille09bd5d2016-11-29 16:20:35 -0500239 // Verify the required extensions are in the extension names set. Fail if not.
240 ANGLE_VK_TRY(VerifyExtensionsPresent(instanceExtensionProps, enabledInstanceExtensions));
241
Jamie Madill327ba852016-11-30 12:38:28 -0500242 VkApplicationInfo applicationInfo;
243 applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
244 applicationInfo.pNext = nullptr;
245 applicationInfo.pApplicationName = "ANGLE";
246 applicationInfo.applicationVersion = 1;
247 applicationInfo.pEngineName = "ANGLE";
248 applicationInfo.engineVersion = 1;
249 applicationInfo.apiVersion = VK_API_VERSION_1_0;
250
251 VkInstanceCreateInfo instanceInfo;
252 instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
253 instanceInfo.pNext = nullptr;
254 instanceInfo.flags = 0;
255 instanceInfo.pApplicationInfo = &applicationInfo;
256
Jamie Madille09bd5d2016-11-29 16:20:35 -0500257 // Enable requested layers and extensions.
258 instanceInfo.enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size());
259 instanceInfo.ppEnabledExtensionNames =
260 enabledInstanceExtensions.empty() ? nullptr : enabledInstanceExtensions.data();
Jamie Madill0448ec82016-12-23 13:41:47 -0500261 instanceInfo.enabledLayerCount = mEnableValidationLayers ? 1u : 0u;
262 instanceInfo.ppEnabledLayerNames =
263 mEnableValidationLayers ? &g_VkStdValidationLayerName : nullptr;
Jamie Madill327ba852016-11-30 12:38:28 -0500264
265 ANGLE_VK_TRY(vkCreateInstance(&instanceInfo, nullptr, &mInstance));
266
Jamie Madill0448ec82016-12-23 13:41:47 -0500267 if (mEnableValidationLayers)
268 {
Jamie Madilla66779f2017-01-06 10:43:44 -0500269 // Change back to the previous working directory now that we've loaded the instance -
270 // the validation layers should be loaded at this point.
271 angle::SetCWD(previousCWD.c_str());
272
Jamie Madill0448ec82016-12-23 13:41:47 -0500273 VkDebugReportCallbackCreateInfoEXT debugReportInfo;
274
275 debugReportInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
276 debugReportInfo.pNext = nullptr;
277 debugReportInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT |
278 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
279 VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT;
280 debugReportInfo.pfnCallback = &DebugReportCallback;
281 debugReportInfo.pUserData = this;
282
283 auto createDebugReportCallback = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
284 vkGetInstanceProcAddr(mInstance, "vkCreateDebugReportCallbackEXT"));
285 ASSERT(createDebugReportCallback);
286 ANGLE_VK_TRY(
287 createDebugReportCallback(mInstance, &debugReportInfo, nullptr, &mDebugReportCallback));
288 }
289
Jamie Madill4d0bf552016-12-28 15:45:24 -0500290 uint32_t physicalDeviceCount = 0;
291 ANGLE_VK_TRY(vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, nullptr));
292 ANGLE_VK_CHECK(physicalDeviceCount > 0, VK_ERROR_INITIALIZATION_FAILED);
293
294 // TODO(jmadill): Handle multiple physical devices. For now, use the first device.
295 physicalDeviceCount = 1;
296 ANGLE_VK_TRY(vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, &mPhysicalDevice));
297
298 vkGetPhysicalDeviceProperties(mPhysicalDevice, &mPhysicalDeviceProperties);
299
300 // Ensure we can find a graphics queue family.
301 uint32_t queueCount = 0;
302 vkGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount, nullptr);
303
304 ANGLE_VK_CHECK(queueCount > 0, VK_ERROR_INITIALIZATION_FAILED);
305
306 mQueueFamilyProperties.resize(queueCount);
307 vkGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount,
308 mQueueFamilyProperties.data());
309
310 size_t graphicsQueueFamilyCount = false;
311 uint32_t firstGraphicsQueueFamily = 0;
312 for (uint32_t familyIndex = 0; familyIndex < queueCount; ++familyIndex)
313 {
314 const auto &queueInfo = mQueueFamilyProperties[familyIndex];
315 if ((queueInfo.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
316 {
317 ASSERT(queueInfo.queueCount > 0);
318 graphicsQueueFamilyCount++;
319 if (firstGraphicsQueueFamily == 0)
320 {
321 firstGraphicsQueueFamily = familyIndex;
322 }
323 break;
324 }
325 }
326
327 ANGLE_VK_CHECK(graphicsQueueFamilyCount > 0, VK_ERROR_INITIALIZATION_FAILED);
328
329 // If only one queue family, go ahead and initialize the device. If there is more than one
330 // queue, we'll have to wait until we see a WindowSurface to know which supports present.
331 if (graphicsQueueFamilyCount == 1)
332 {
333 ANGLE_TRY(initializeDevice(firstGraphicsQueueFamily));
334 }
335
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500336 VkPhysicalDeviceMemoryProperties memoryProperties;
337 vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &memoryProperties);
338
339 for (uint32_t memoryIndex = 0; memoryIndex < memoryProperties.memoryTypeCount; ++memoryIndex)
340 {
341 if ((memoryProperties.memoryTypes[memoryIndex].propertyFlags &
342 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
343 {
344 mHostVisibleMemoryIndex = memoryIndex;
345 break;
346 }
347 }
348
349 ANGLE_VK_CHECK(mHostVisibleMemoryIndex < std::numeric_limits<uint32_t>::max(),
350 VK_ERROR_INITIALIZATION_FAILED);
351
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500352 mGlslangWrapper = GlslangWrapper::GetReference();
353
Jamie Madill327ba852016-11-30 12:38:28 -0500354 return vk::NoError();
Jamie Madill9e54b5a2016-05-25 12:57:39 -0400355}
356
Jamie Madill4d0bf552016-12-28 15:45:24 -0500357vk::Error RendererVk::initializeDevice(uint32_t queueFamilyIndex)
358{
359 uint32_t deviceLayerCount = 0;
360 ANGLE_VK_TRY(vkEnumerateDeviceLayerProperties(mPhysicalDevice, &deviceLayerCount, nullptr));
361
362 std::vector<VkLayerProperties> deviceLayerProps(deviceLayerCount);
363 if (deviceLayerCount > 0)
364 {
365 ANGLE_VK_TRY(vkEnumerateDeviceLayerProperties(mPhysicalDevice, &deviceLayerCount,
366 deviceLayerProps.data()));
367 }
368
369 uint32_t deviceExtensionCount = 0;
370 ANGLE_VK_TRY(vkEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr,
371 &deviceExtensionCount, nullptr));
372
373 std::vector<VkExtensionProperties> deviceExtensionProps(deviceExtensionCount);
374 if (deviceExtensionCount > 0)
375 {
376 ANGLE_VK_TRY(vkEnumerateDeviceExtensionProperties(
377 mPhysicalDevice, nullptr, &deviceExtensionCount, deviceExtensionProps.data()));
378 }
379
380 if (mEnableValidationLayers)
381 {
382 if (!HasStandardValidationLayer(deviceLayerProps))
383 {
Yuly Novikovbcb3f9b2017-01-27 22:45:18 -0500384 WARN() << "Vulkan standard validation layer is missing.";
Jamie Madill4d0bf552016-12-28 15:45:24 -0500385 mEnableValidationLayers = false;
386 }
387 }
388
389 std::vector<const char *> enabledDeviceExtensions;
390 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
391
392 ANGLE_VK_TRY(VerifyExtensionsPresent(deviceExtensionProps, enabledDeviceExtensions));
393
394 VkDeviceQueueCreateInfo queueCreateInfo;
395
396 float zeroPriority = 0.0f;
397
398 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
399 queueCreateInfo.pNext = nullptr;
400 queueCreateInfo.flags = 0;
401 queueCreateInfo.queueFamilyIndex = queueFamilyIndex;
402 queueCreateInfo.queueCount = 1;
403 queueCreateInfo.pQueuePriorities = &zeroPriority;
404
405 // Initialize the device
406 VkDeviceCreateInfo createInfo;
407
408 createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
409 createInfo.pNext = nullptr;
410 createInfo.flags = 0;
411 createInfo.queueCreateInfoCount = 1;
412 createInfo.pQueueCreateInfos = &queueCreateInfo;
413 createInfo.enabledLayerCount = mEnableValidationLayers ? 1u : 0u;
414 createInfo.ppEnabledLayerNames =
415 mEnableValidationLayers ? &g_VkStdValidationLayerName : nullptr;
416 createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size());
417 createInfo.ppEnabledExtensionNames =
418 enabledDeviceExtensions.empty() ? nullptr : enabledDeviceExtensions.data();
419 createInfo.pEnabledFeatures = nullptr; // TODO(jmadill): features
420
421 ANGLE_VK_TRY(vkCreateDevice(mPhysicalDevice, &createInfo, nullptr, &mDevice));
422
423 mCurrentQueueFamilyIndex = queueFamilyIndex;
424
425 vkGetDeviceQueue(mDevice, mCurrentQueueFamilyIndex, 0, &mQueue);
426
427 // Initialize the command pool now that we know the queue family index.
428 VkCommandPoolCreateInfo commandPoolInfo;
429 commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
430 commandPoolInfo.pNext = nullptr;
431 // TODO(jmadill): Investigate transient command buffers.
432 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
433 commandPoolInfo.queueFamilyIndex = mCurrentQueueFamilyIndex;
434
Jamie Madill5deea722017-02-16 10:44:46 -0500435 ANGLE_TRY(mCommandPool.init(mDevice, commandPoolInfo));
Jamie Madill4d0bf552016-12-28 15:45:24 -0500436
Jamie Madill5deea722017-02-16 10:44:46 -0500437 mCommandBuffer.setCommandPool(&mCommandPool);
Jamie Madill4d0bf552016-12-28 15:45:24 -0500438
439 return vk::NoError();
440}
441
442vk::ErrorOrResult<uint32_t> RendererVk::selectPresentQueueForSurface(VkSurfaceKHR surface)
443{
444 // We've already initialized a device, and can't re-create it unless it's never been used.
445 // TODO(jmadill): Handle the re-creation case if necessary.
446 if (mDevice != VK_NULL_HANDLE)
447 {
448 ASSERT(mCurrentQueueFamilyIndex != std::numeric_limits<uint32_t>::max());
449
450 // Check if the current device supports present on this surface.
451 VkBool32 supportsPresent = VK_FALSE;
452 ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceSupportKHR(mPhysicalDevice, mCurrentQueueFamilyIndex,
453 surface, &supportsPresent));
454
455 return (supportsPresent == VK_TRUE);
456 }
457
458 // Find a graphics and present queue.
459 Optional<uint32_t> newPresentQueue;
460 uint32_t queueCount = static_cast<uint32_t>(mQueueFamilyProperties.size());
461 for (uint32_t queueIndex = 0; queueIndex < queueCount; ++queueIndex)
462 {
463 const auto &queueInfo = mQueueFamilyProperties[queueIndex];
464 if ((queueInfo.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
465 {
466 VkBool32 supportsPresent = VK_FALSE;
467 ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceSupportKHR(mPhysicalDevice, queueIndex, surface,
468 &supportsPresent));
469
470 if (supportsPresent == VK_TRUE)
471 {
472 newPresentQueue = queueIndex;
473 break;
474 }
475 }
476 }
477
478 ANGLE_VK_CHECK(newPresentQueue.valid(), VK_ERROR_INITIALIZATION_FAILED);
479 ANGLE_TRY(initializeDevice(newPresentQueue.value()));
480
481 return newPresentQueue.value();
482}
483
484std::string RendererVk::getVendorString() const
485{
486 switch (mPhysicalDeviceProperties.vendorID)
487 {
488 case VENDOR_ID_AMD:
489 return "Advanced Micro Devices";
490 case VENDOR_ID_NVIDIA:
491 return "NVIDIA";
492 case VENDOR_ID_INTEL:
493 return "Intel";
494 default:
495 {
496 // TODO(jmadill): More vendor IDs.
497 std::stringstream strstr;
498 strstr << "Vendor ID: " << mPhysicalDeviceProperties.vendorID;
499 return strstr.str();
500 }
501 }
502}
503
Jamie Madille09bd5d2016-11-29 16:20:35 -0500504std::string RendererVk::getRendererDescription() const
505{
Jamie Madill4d0bf552016-12-28 15:45:24 -0500506 std::stringstream strstr;
507
508 uint32_t apiVersion = mPhysicalDeviceProperties.apiVersion;
509
510 strstr << "Vulkan ";
511 strstr << VK_VERSION_MAJOR(apiVersion) << ".";
512 strstr << VK_VERSION_MINOR(apiVersion) << ".";
513 strstr << VK_VERSION_PATCH(apiVersion);
514
515 strstr << "(" << mPhysicalDeviceProperties.deviceName << ")";
516
517 return strstr.str();
Jamie Madille09bd5d2016-11-29 16:20:35 -0500518}
519
Jamie Madillacccc6c2016-05-03 17:22:10 -0400520void RendererVk::ensureCapsInitialized() const
521{
522 if (!mCapsInitialized)
523 {
524 generateCaps(&mNativeCaps, &mNativeTextureCaps, &mNativeExtensions, &mNativeLimitations);
525 mCapsInitialized = true;
526 }
527}
528
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500529void RendererVk::generateCaps(gl::Caps *outCaps,
Jamie Madillacccc6c2016-05-03 17:22:10 -0400530 gl::TextureCapsMap * /*outTextureCaps*/,
Jamie Madillb8353b02017-01-25 12:57:21 -0800531 gl::Extensions *outExtensions,
Jamie Madillacccc6c2016-05-03 17:22:10 -0400532 gl::Limitations * /* outLimitations */) const
533{
Jamie Madill327ba852016-11-30 12:38:28 -0500534 // TODO(jmadill): Caps.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500535 outCaps->maxDrawBuffers = 1;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800536 outCaps->maxVertexAttributes = gl::MAX_VERTEX_ATTRIBS;
537 outCaps->maxVertexAttribBindings = gl::MAX_VERTEX_ATTRIB_BINDINGS;
Jamie Madillb8353b02017-01-25 12:57:21 -0800538
539 // Enable this for simple buffer readback testing, but some functionality is missing.
540 // TODO(jmadill): Support full mapBufferRange extension.
541 outExtensions->mapBuffer = true;
542 outExtensions->mapBufferRange = true;
Jamie Madillacccc6c2016-05-03 17:22:10 -0400543}
544
545const gl::Caps &RendererVk::getNativeCaps() const
546{
547 ensureCapsInitialized();
548 return mNativeCaps;
549}
550
551const gl::TextureCapsMap &RendererVk::getNativeTextureCaps() const
552{
553 ensureCapsInitialized();
554 return mNativeTextureCaps;
555}
556
557const gl::Extensions &RendererVk::getNativeExtensions() const
558{
559 ensureCapsInitialized();
560 return mNativeExtensions;
561}
562
563const gl::Limitations &RendererVk::getNativeLimitations() const
564{
565 ensureCapsInitialized();
566 return mNativeLimitations;
567}
568
Jamie Madill0c0dc342017-03-24 14:18:51 -0400569vk::Error RendererVk::getStartedCommandBuffer(vk::CommandBuffer **commandBufferOut)
Jamie Madill4d0bf552016-12-28 15:45:24 -0500570{
Jamie Madill0c0dc342017-03-24 14:18:51 -0400571 ANGLE_TRY(mCommandBuffer.begin(mDevice));
572 *commandBufferOut = &mCommandBuffer;
573 return vk::NoError();
Jamie Madill4d0bf552016-12-28 15:45:24 -0500574}
575
Jamie Madill0c0dc342017-03-24 14:18:51 -0400576vk::Error RendererVk::submitCommandBuffer(vk::CommandBuffer *commandBuffer)
Jamie Madill4d0bf552016-12-28 15:45:24 -0500577{
Jamie Madill0c0dc342017-03-24 14:18:51 -0400578 ANGLE_TRY(commandBuffer->end());
579
Jamie Madill4d0bf552016-12-28 15:45:24 -0500580 VkFenceCreateInfo fenceInfo;
581 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
582 fenceInfo.pNext = nullptr;
583 fenceInfo.flags = 0;
584
Jamie Madill4d0bf552016-12-28 15:45:24 -0500585 VkSubmitInfo submitInfo;
586 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
587 submitInfo.pNext = nullptr;
588 submitInfo.waitSemaphoreCount = 0;
589 submitInfo.pWaitSemaphores = nullptr;
590 submitInfo.pWaitDstStageMask = nullptr;
591 submitInfo.commandBufferCount = 1;
Jamie Madill0c0dc342017-03-24 14:18:51 -0400592 submitInfo.pCommandBuffers = commandBuffer->ptr();
Jamie Madill4d0bf552016-12-28 15:45:24 -0500593 submitInfo.signalSemaphoreCount = 0;
594 submitInfo.pSignalSemaphores = nullptr;
595
596 // TODO(jmadill): Investigate how to properly submit command buffers.
Jamie Madill4c26fc22017-02-24 11:04:10 -0500597 ANGLE_TRY(submit(submitInfo));
Jamie Madill4d0bf552016-12-28 15:45:24 -0500598
Jamie Madillf651c772017-02-21 15:03:51 -0500599 return vk::NoError();
600}
601
Jamie Madill0c0dc342017-03-24 14:18:51 -0400602vk::Error RendererVk::submitAndFinishCommandBuffer(vk::CommandBuffer *commandBuffer)
Jamie Madillf651c772017-02-21 15:03:51 -0500603{
604 ANGLE_TRY(submitCommandBuffer(commandBuffer));
Jamie Madill4c26fc22017-02-24 11:04:10 -0500605 ANGLE_TRY(finish());
Jamie Madill4d0bf552016-12-28 15:45:24 -0500606
607 return vk::NoError();
608}
609
Jamie Madill0c0dc342017-03-24 14:18:51 -0400610vk::Error RendererVk::submitCommandsWithSync(vk::CommandBuffer *commandBuffer,
Jamie Madille918de22017-04-12 10:21:11 -0400611 const vk::Semaphore &waitSemaphore,
612 const vk::Semaphore &signalSemaphore)
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500613{
Jamie Madill0c0dc342017-03-24 14:18:51 -0400614 ANGLE_TRY(commandBuffer->end());
615
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500616 VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
617
618 VkSubmitInfo submitInfo;
619 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
620 submitInfo.pNext = nullptr;
621 submitInfo.waitSemaphoreCount = 1;
Jamie Madille918de22017-04-12 10:21:11 -0400622 submitInfo.pWaitSemaphores = waitSemaphore.ptr();
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500623 submitInfo.pWaitDstStageMask = &waitStageMask;
624 submitInfo.commandBufferCount = 1;
Jamie Madill0c0dc342017-03-24 14:18:51 -0400625 submitInfo.pCommandBuffers = commandBuffer->ptr();
Jamie Madille918de22017-04-12 10:21:11 -0400626 submitInfo.signalSemaphoreCount = 1;
627 submitInfo.pSignalSemaphores = signalSemaphore.ptr();
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500628
629 // TODO(jmadill): Investigate how to properly queue command buffer work.
Jamie Madill0c0dc342017-03-24 14:18:51 -0400630 ANGLE_TRY(submitFrame(submitInfo));
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500631
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500632 return vk::NoError();
633}
634
Jamie Madill4c26fc22017-02-24 11:04:10 -0500635vk::Error RendererVk::finish()
636{
637 ASSERT(mQueue != VK_NULL_HANDLE);
Jamie Madill4c26fc22017-02-24 11:04:10 -0500638 ANGLE_VK_TRY(vkQueueWaitIdle(mQueue));
Jamie Madill0c0dc342017-03-24 14:18:51 -0400639 freeAllInFlightResources();
Jamie Madill4c26fc22017-02-24 11:04:10 -0500640 return vk::NoError();
641}
642
Jamie Madill0c0dc342017-03-24 14:18:51 -0400643void RendererVk::freeAllInFlightResources()
644{
645 for (auto &fence : mInFlightFences)
646 {
647 fence.destroy(mDevice);
648 }
649 mInFlightFences.clear();
650
651 for (auto &command : mInFlightCommands)
652 {
653 command.destroy(mDevice);
654 }
655 mInFlightCommands.clear();
656
657 for (auto &garbage : mGarbage)
658 {
659 garbage->destroy(mDevice);
660 }
661 mGarbage.clear();
662}
663
Jamie Madill4c26fc22017-02-24 11:04:10 -0500664vk::Error RendererVk::checkInFlightCommands()
665{
Jamie Madill0c0dc342017-03-24 14:18:51 -0400666 size_t finishedIndex = 0;
Jamie Madillf651c772017-02-21 15:03:51 -0500667
Jamie Madill4c26fc22017-02-24 11:04:10 -0500668 // Check if any in-flight command buffers are finished.
Jamie Madill0c0dc342017-03-24 14:18:51 -0400669 for (size_t index = 0; index < mInFlightFences.size(); index++)
Jamie Madill4c26fc22017-02-24 11:04:10 -0500670 {
Jamie Madill0c0dc342017-03-24 14:18:51 -0400671 auto *inFlightFence = &mInFlightFences[index];
Jamie Madill4c26fc22017-02-24 11:04:10 -0500672
Jamie Madill0c0dc342017-03-24 14:18:51 -0400673 VkResult result = inFlightFence->get().getStatus(mDevice);
674 if (result == VK_NOT_READY)
675 break;
676 ANGLE_VK_TRY(result);
677 finishedIndex = index + 1;
678
679 // Release the fence handle.
680 // TODO(jmadill): Re-use fences.
681 inFlightFence->destroy(mDevice);
Jamie Madill4c26fc22017-02-24 11:04:10 -0500682 }
683
Jamie Madill0c0dc342017-03-24 14:18:51 -0400684 if (finishedIndex == 0)
685 return vk::NoError();
Jamie Madillf651c772017-02-21 15:03:51 -0500686
Jamie Madill0c0dc342017-03-24 14:18:51 -0400687 Serial finishedSerial = mInFlightFences[finishedIndex - 1].queueSerial();
688 mInFlightFences.erase(mInFlightFences.begin(), mInFlightFences.begin() + finishedIndex);
689
690 size_t completedCBIndex = 0;
691 for (size_t cbIndex = 0; cbIndex < mInFlightCommands.size(); ++cbIndex)
692 {
693 auto *inFlightCB = &mInFlightCommands[cbIndex];
694 if (inFlightCB->queueSerial() > finishedSerial)
695 break;
696
697 completedCBIndex = cbIndex + 1;
698 inFlightCB->destroy(mDevice);
699 }
700
701 if (completedCBIndex == 0)
702 return vk::NoError();
703
704 mInFlightCommands.erase(mInFlightCommands.begin(),
705 mInFlightCommands.begin() + completedCBIndex);
706
707 size_t freeIndex = 0;
708 for (; freeIndex < mGarbage.size(); ++freeIndex)
709 {
710 if (!mGarbage[freeIndex]->destroyIfComplete(mDevice, finishedSerial))
711 break;
712 }
713
714 // Remove the entries from the garbage list - they should be ready to go.
715 if (freeIndex > 0)
716 {
717 mGarbage.erase(mGarbage.begin(), mGarbage.begin() + freeIndex);
Jamie Madillf651c772017-02-21 15:03:51 -0500718 }
719
Jamie Madill4c26fc22017-02-24 11:04:10 -0500720 return vk::NoError();
721}
722
723vk::Error RendererVk::submit(const VkSubmitInfo &submitInfo)
724{
Jamie Madill0c0dc342017-03-24 14:18:51 -0400725 ANGLE_VK_TRY(vkQueueSubmit(mQueue, 1, &submitInfo, VK_NULL_HANDLE));
Jamie Madill4c26fc22017-02-24 11:04:10 -0500726
727 // Store this command buffer in the in-flight list.
Jamie Madill0c0dc342017-03-24 14:18:51 -0400728 mInFlightCommands.emplace_back(std::move(mCommandBuffer), mCurrentQueueSerial);
Jamie Madill4c26fc22017-02-24 11:04:10 -0500729
730 // Sanity check.
731 ASSERT(mInFlightCommands.size() < 1000u);
732
Jamie Madill0c0dc342017-03-24 14:18:51 -0400733 // Increment the queue serial. If this fails, we should restart ANGLE.
Jamie Madillfb05bcb2017-06-07 15:43:18 -0400734 // TODO(jmadill): Overflow check.
735 mCurrentQueueSerial = mQueueSerialFactory.generate();
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.
Jamie Madillfb05bcb2017-06-07 15:43:18 -0400760 // TODO(jmadill): Overflow check.
761 mCurrentQueueSerial = mQueueSerialFactory.generate();
Jamie Madill0c0dc342017-03-24 14:18:51 -0400762
763 ANGLE_TRY(checkInFlightCommands());
764
Jamie Madill4c26fc22017-02-24 11:04:10 -0500765 return vk::NoError();
766}
767
Jamie Madill5deea722017-02-16 10:44:46 -0500768vk::Error RendererVk::createStagingImage(TextureDimension dimension,
769 const vk::Format &format,
770 const gl::Extents &extent,
771 vk::StagingImage *imageOut)
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500772{
773 ASSERT(mHostVisibleMemoryIndex != std::numeric_limits<uint32_t>::max());
774
Jamie Madill5deea722017-02-16 10:44:46 -0500775 ANGLE_TRY(imageOut->init(mDevice, mCurrentQueueFamilyIndex, mHostVisibleMemoryIndex, dimension,
776 format.native, extent));
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500777
Jamie Madill5deea722017-02-16 10:44:46 -0500778 return vk::NoError();
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500779}
780
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500781GlslangWrapper *RendererVk::getGlslangWrapper()
782{
783 return mGlslangWrapper;
784}
785
Jamie Madill4c26fc22017-02-24 11:04:10 -0500786Serial RendererVk::getCurrentQueueSerial() const
787{
788 return mCurrentQueueSerial;
789}
790
Jamie Madill9e54b5a2016-05-25 12:57:39 -0400791} // namespace rx