blob: 1ca624922a31cfb0c24d770b9dd3051e3a690f23 [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 Madill4c26fc22017-02-24 11:04:10 -0500107 if (!mInFlightCommands.empty())
108 {
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
Jamie Madille09bd5d2016-11-29 16:20:35 -0500156vk::Error RendererVk::initialize(const egl::AttributeMap &attribs)
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);
232#if defined(ANGLE_PLATFORM_WINDOWS)
233 enabledInstanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
234#else
235#error Unsupported Vulkan platform.
236#endif // defined(ANGLE_PLATFORM_WINDOWS)
237
Jamie Madill0448ec82016-12-23 13:41:47 -0500238 // TODO(jmadill): Should be able to continue initialization if debug report ext missing.
239 if (mEnableValidationLayers)
240 {
241 enabledInstanceExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
242 }
243
Jamie Madille09bd5d2016-11-29 16:20:35 -0500244 // Verify the required extensions are in the extension names set. Fail if not.
245 ANGLE_VK_TRY(VerifyExtensionsPresent(instanceExtensionProps, enabledInstanceExtensions));
246
Jamie Madill327ba852016-11-30 12:38:28 -0500247 VkApplicationInfo applicationInfo;
248 applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
249 applicationInfo.pNext = nullptr;
250 applicationInfo.pApplicationName = "ANGLE";
251 applicationInfo.applicationVersion = 1;
252 applicationInfo.pEngineName = "ANGLE";
253 applicationInfo.engineVersion = 1;
254 applicationInfo.apiVersion = VK_API_VERSION_1_0;
255
256 VkInstanceCreateInfo instanceInfo;
257 instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
258 instanceInfo.pNext = nullptr;
259 instanceInfo.flags = 0;
260 instanceInfo.pApplicationInfo = &applicationInfo;
261
Jamie Madille09bd5d2016-11-29 16:20:35 -0500262 // Enable requested layers and extensions.
263 instanceInfo.enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size());
264 instanceInfo.ppEnabledExtensionNames =
265 enabledInstanceExtensions.empty() ? nullptr : enabledInstanceExtensions.data();
Jamie Madill0448ec82016-12-23 13:41:47 -0500266 instanceInfo.enabledLayerCount = mEnableValidationLayers ? 1u : 0u;
267 instanceInfo.ppEnabledLayerNames =
268 mEnableValidationLayers ? &g_VkStdValidationLayerName : nullptr;
Jamie Madill327ba852016-11-30 12:38:28 -0500269
270 ANGLE_VK_TRY(vkCreateInstance(&instanceInfo, nullptr, &mInstance));
271
Jamie Madill0448ec82016-12-23 13:41:47 -0500272 if (mEnableValidationLayers)
273 {
Jamie Madilla66779f2017-01-06 10:43:44 -0500274 // Change back to the previous working directory now that we've loaded the instance -
275 // the validation layers should be loaded at this point.
276 angle::SetCWD(previousCWD.c_str());
277
Jamie Madill0448ec82016-12-23 13:41:47 -0500278 VkDebugReportCallbackCreateInfoEXT debugReportInfo;
279
280 debugReportInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
281 debugReportInfo.pNext = nullptr;
282 debugReportInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT |
283 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
284 VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT;
285 debugReportInfo.pfnCallback = &DebugReportCallback;
286 debugReportInfo.pUserData = this;
287
288 auto createDebugReportCallback = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
289 vkGetInstanceProcAddr(mInstance, "vkCreateDebugReportCallbackEXT"));
290 ASSERT(createDebugReportCallback);
291 ANGLE_VK_TRY(
292 createDebugReportCallback(mInstance, &debugReportInfo, nullptr, &mDebugReportCallback));
293 }
294
Jamie Madill4d0bf552016-12-28 15:45:24 -0500295 uint32_t physicalDeviceCount = 0;
296 ANGLE_VK_TRY(vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, nullptr));
297 ANGLE_VK_CHECK(physicalDeviceCount > 0, VK_ERROR_INITIALIZATION_FAILED);
298
299 // TODO(jmadill): Handle multiple physical devices. For now, use the first device.
300 physicalDeviceCount = 1;
301 ANGLE_VK_TRY(vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, &mPhysicalDevice));
302
303 vkGetPhysicalDeviceProperties(mPhysicalDevice, &mPhysicalDeviceProperties);
304
305 // Ensure we can find a graphics queue family.
306 uint32_t queueCount = 0;
307 vkGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount, nullptr);
308
309 ANGLE_VK_CHECK(queueCount > 0, VK_ERROR_INITIALIZATION_FAILED);
310
311 mQueueFamilyProperties.resize(queueCount);
312 vkGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount,
313 mQueueFamilyProperties.data());
314
315 size_t graphicsQueueFamilyCount = false;
316 uint32_t firstGraphicsQueueFamily = 0;
317 for (uint32_t familyIndex = 0; familyIndex < queueCount; ++familyIndex)
318 {
319 const auto &queueInfo = mQueueFamilyProperties[familyIndex];
320 if ((queueInfo.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
321 {
322 ASSERT(queueInfo.queueCount > 0);
323 graphicsQueueFamilyCount++;
324 if (firstGraphicsQueueFamily == 0)
325 {
326 firstGraphicsQueueFamily = familyIndex;
327 }
328 break;
329 }
330 }
331
332 ANGLE_VK_CHECK(graphicsQueueFamilyCount > 0, VK_ERROR_INITIALIZATION_FAILED);
333
334 // If only one queue family, go ahead and initialize the device. If there is more than one
335 // queue, we'll have to wait until we see a WindowSurface to know which supports present.
336 if (graphicsQueueFamilyCount == 1)
337 {
338 ANGLE_TRY(initializeDevice(firstGraphicsQueueFamily));
339 }
340
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500341 VkPhysicalDeviceMemoryProperties memoryProperties;
342 vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &memoryProperties);
343
344 for (uint32_t memoryIndex = 0; memoryIndex < memoryProperties.memoryTypeCount; ++memoryIndex)
345 {
346 if ((memoryProperties.memoryTypes[memoryIndex].propertyFlags &
347 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
348 {
349 mHostVisibleMemoryIndex = memoryIndex;
350 break;
351 }
352 }
353
354 ANGLE_VK_CHECK(mHostVisibleMemoryIndex < std::numeric_limits<uint32_t>::max(),
355 VK_ERROR_INITIALIZATION_FAILED);
356
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500357 mGlslangWrapper = GlslangWrapper::GetReference();
358
Jamie Madill327ba852016-11-30 12:38:28 -0500359 return vk::NoError();
Jamie Madill9e54b5a2016-05-25 12:57:39 -0400360}
361
Jamie Madill4d0bf552016-12-28 15:45:24 -0500362vk::Error RendererVk::initializeDevice(uint32_t queueFamilyIndex)
363{
364 uint32_t deviceLayerCount = 0;
365 ANGLE_VK_TRY(vkEnumerateDeviceLayerProperties(mPhysicalDevice, &deviceLayerCount, nullptr));
366
367 std::vector<VkLayerProperties> deviceLayerProps(deviceLayerCount);
368 if (deviceLayerCount > 0)
369 {
370 ANGLE_VK_TRY(vkEnumerateDeviceLayerProperties(mPhysicalDevice, &deviceLayerCount,
371 deviceLayerProps.data()));
372 }
373
374 uint32_t deviceExtensionCount = 0;
375 ANGLE_VK_TRY(vkEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr,
376 &deviceExtensionCount, nullptr));
377
378 std::vector<VkExtensionProperties> deviceExtensionProps(deviceExtensionCount);
379 if (deviceExtensionCount > 0)
380 {
381 ANGLE_VK_TRY(vkEnumerateDeviceExtensionProperties(
382 mPhysicalDevice, nullptr, &deviceExtensionCount, deviceExtensionProps.data()));
383 }
384
385 if (mEnableValidationLayers)
386 {
387 if (!HasStandardValidationLayer(deviceLayerProps))
388 {
Yuly Novikovbcb3f9b2017-01-27 22:45:18 -0500389 WARN() << "Vulkan standard validation layer is missing.";
Jamie Madill4d0bf552016-12-28 15:45:24 -0500390 mEnableValidationLayers = false;
391 }
392 }
393
394 std::vector<const char *> enabledDeviceExtensions;
395 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
396
397 ANGLE_VK_TRY(VerifyExtensionsPresent(deviceExtensionProps, enabledDeviceExtensions));
398
399 VkDeviceQueueCreateInfo queueCreateInfo;
400
401 float zeroPriority = 0.0f;
402
403 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
404 queueCreateInfo.pNext = nullptr;
405 queueCreateInfo.flags = 0;
406 queueCreateInfo.queueFamilyIndex = queueFamilyIndex;
407 queueCreateInfo.queueCount = 1;
408 queueCreateInfo.pQueuePriorities = &zeroPriority;
409
410 // Initialize the device
411 VkDeviceCreateInfo createInfo;
412
413 createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
414 createInfo.pNext = nullptr;
415 createInfo.flags = 0;
416 createInfo.queueCreateInfoCount = 1;
417 createInfo.pQueueCreateInfos = &queueCreateInfo;
418 createInfo.enabledLayerCount = mEnableValidationLayers ? 1u : 0u;
419 createInfo.ppEnabledLayerNames =
420 mEnableValidationLayers ? &g_VkStdValidationLayerName : nullptr;
421 createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size());
422 createInfo.ppEnabledExtensionNames =
423 enabledDeviceExtensions.empty() ? nullptr : enabledDeviceExtensions.data();
424 createInfo.pEnabledFeatures = nullptr; // TODO(jmadill): features
425
426 ANGLE_VK_TRY(vkCreateDevice(mPhysicalDevice, &createInfo, nullptr, &mDevice));
427
428 mCurrentQueueFamilyIndex = queueFamilyIndex;
429
430 vkGetDeviceQueue(mDevice, mCurrentQueueFamilyIndex, 0, &mQueue);
431
432 // Initialize the command pool now that we know the queue family index.
433 VkCommandPoolCreateInfo commandPoolInfo;
434 commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
435 commandPoolInfo.pNext = nullptr;
436 // TODO(jmadill): Investigate transient command buffers.
437 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
438 commandPoolInfo.queueFamilyIndex = mCurrentQueueFamilyIndex;
439
Jamie Madill5deea722017-02-16 10:44:46 -0500440 ANGLE_TRY(mCommandPool.init(mDevice, commandPoolInfo));
Jamie Madill4d0bf552016-12-28 15:45:24 -0500441
Jamie Madill5deea722017-02-16 10:44:46 -0500442 mCommandBuffer.setCommandPool(&mCommandPool);
Jamie Madill4d0bf552016-12-28 15:45:24 -0500443
444 return vk::NoError();
445}
446
447vk::ErrorOrResult<uint32_t> RendererVk::selectPresentQueueForSurface(VkSurfaceKHR surface)
448{
449 // We've already initialized a device, and can't re-create it unless it's never been used.
450 // TODO(jmadill): Handle the re-creation case if necessary.
451 if (mDevice != VK_NULL_HANDLE)
452 {
453 ASSERT(mCurrentQueueFamilyIndex != std::numeric_limits<uint32_t>::max());
454
455 // Check if the current device supports present on this surface.
456 VkBool32 supportsPresent = VK_FALSE;
457 ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceSupportKHR(mPhysicalDevice, mCurrentQueueFamilyIndex,
458 surface, &supportsPresent));
459
460 return (supportsPresent == VK_TRUE);
461 }
462
463 // Find a graphics and present queue.
464 Optional<uint32_t> newPresentQueue;
465 uint32_t queueCount = static_cast<uint32_t>(mQueueFamilyProperties.size());
466 for (uint32_t queueIndex = 0; queueIndex < queueCount; ++queueIndex)
467 {
468 const auto &queueInfo = mQueueFamilyProperties[queueIndex];
469 if ((queueInfo.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
470 {
471 VkBool32 supportsPresent = VK_FALSE;
472 ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceSupportKHR(mPhysicalDevice, queueIndex, surface,
473 &supportsPresent));
474
475 if (supportsPresent == VK_TRUE)
476 {
477 newPresentQueue = queueIndex;
478 break;
479 }
480 }
481 }
482
483 ANGLE_VK_CHECK(newPresentQueue.valid(), VK_ERROR_INITIALIZATION_FAILED);
484 ANGLE_TRY(initializeDevice(newPresentQueue.value()));
485
486 return newPresentQueue.value();
487}
488
489std::string RendererVk::getVendorString() const
490{
491 switch (mPhysicalDeviceProperties.vendorID)
492 {
493 case VENDOR_ID_AMD:
494 return "Advanced Micro Devices";
495 case VENDOR_ID_NVIDIA:
496 return "NVIDIA";
497 case VENDOR_ID_INTEL:
498 return "Intel";
499 default:
500 {
501 // TODO(jmadill): More vendor IDs.
502 std::stringstream strstr;
503 strstr << "Vendor ID: " << mPhysicalDeviceProperties.vendorID;
504 return strstr.str();
505 }
506 }
507}
508
Jamie Madille09bd5d2016-11-29 16:20:35 -0500509std::string RendererVk::getRendererDescription() const
510{
Jamie Madill4d0bf552016-12-28 15:45:24 -0500511 std::stringstream strstr;
512
513 uint32_t apiVersion = mPhysicalDeviceProperties.apiVersion;
514
515 strstr << "Vulkan ";
516 strstr << VK_VERSION_MAJOR(apiVersion) << ".";
517 strstr << VK_VERSION_MINOR(apiVersion) << ".";
518 strstr << VK_VERSION_PATCH(apiVersion);
519
520 strstr << "(" << mPhysicalDeviceProperties.deviceName << ")";
521
522 return strstr.str();
Jamie Madille09bd5d2016-11-29 16:20:35 -0500523}
524
Jamie Madillacccc6c2016-05-03 17:22:10 -0400525void RendererVk::ensureCapsInitialized() const
526{
527 if (!mCapsInitialized)
528 {
529 generateCaps(&mNativeCaps, &mNativeTextureCaps, &mNativeExtensions, &mNativeLimitations);
530 mCapsInitialized = true;
531 }
532}
533
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500534void RendererVk::generateCaps(gl::Caps *outCaps,
Jamie Madillacccc6c2016-05-03 17:22:10 -0400535 gl::TextureCapsMap * /*outTextureCaps*/,
Jamie Madillb8353b02017-01-25 12:57:21 -0800536 gl::Extensions *outExtensions,
Jamie Madillacccc6c2016-05-03 17:22:10 -0400537 gl::Limitations * /* outLimitations */) const
538{
Jamie Madill327ba852016-11-30 12:38:28 -0500539 // TODO(jmadill): Caps.
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500540 outCaps->maxDrawBuffers = 1;
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800541 outCaps->maxVertexAttributes = gl::MAX_VERTEX_ATTRIBS;
542 outCaps->maxVertexAttribBindings = gl::MAX_VERTEX_ATTRIB_BINDINGS;
Jamie Madillb8353b02017-01-25 12:57:21 -0800543
544 // Enable this for simple buffer readback testing, but some functionality is missing.
545 // TODO(jmadill): Support full mapBufferRange extension.
546 outExtensions->mapBuffer = true;
547 outExtensions->mapBufferRange = true;
Jamie Madillacccc6c2016-05-03 17:22:10 -0400548}
549
550const gl::Caps &RendererVk::getNativeCaps() const
551{
552 ensureCapsInitialized();
553 return mNativeCaps;
554}
555
556const gl::TextureCapsMap &RendererVk::getNativeTextureCaps() const
557{
558 ensureCapsInitialized();
559 return mNativeTextureCaps;
560}
561
562const gl::Extensions &RendererVk::getNativeExtensions() const
563{
564 ensureCapsInitialized();
565 return mNativeExtensions;
566}
567
568const gl::Limitations &RendererVk::getNativeLimitations() const
569{
570 ensureCapsInitialized();
571 return mNativeLimitations;
572}
573
Jamie Madill4d0bf552016-12-28 15:45:24 -0500574vk::CommandBuffer *RendererVk::getCommandBuffer()
575{
Jamie Madill5deea722017-02-16 10:44:46 -0500576 return &mCommandBuffer;
Jamie Madill4d0bf552016-12-28 15:45:24 -0500577}
578
Jamie Madillf651c772017-02-21 15:03:51 -0500579vk::Error RendererVk::submitCommandBuffer(const vk::CommandBuffer &commandBuffer)
Jamie Madill4d0bf552016-12-28 15:45:24 -0500580{
581 VkFenceCreateInfo fenceInfo;
582 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
583 fenceInfo.pNext = nullptr;
584 fenceInfo.flags = 0;
585
586 VkCommandBuffer commandBufferHandle = commandBuffer.getHandle();
587
588 VkSubmitInfo submitInfo;
589 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
590 submitInfo.pNext = nullptr;
591 submitInfo.waitSemaphoreCount = 0;
592 submitInfo.pWaitSemaphores = nullptr;
593 submitInfo.pWaitDstStageMask = nullptr;
594 submitInfo.commandBufferCount = 1;
595 submitInfo.pCommandBuffers = &commandBufferHandle;
596 submitInfo.signalSemaphoreCount = 0;
597 submitInfo.pSignalSemaphores = nullptr;
598
599 // TODO(jmadill): Investigate how to properly submit command buffers.
Jamie Madill4c26fc22017-02-24 11:04:10 -0500600 ANGLE_TRY(submit(submitInfo));
Jamie Madill4d0bf552016-12-28 15:45:24 -0500601
Jamie Madillf651c772017-02-21 15:03:51 -0500602 return vk::NoError();
603}
604
605vk::Error RendererVk::submitAndFinishCommandBuffer(const vk::CommandBuffer &commandBuffer)
606{
607 ANGLE_TRY(submitCommandBuffer(commandBuffer));
Jamie Madill4c26fc22017-02-24 11:04:10 -0500608 ANGLE_TRY(finish());
Jamie Madill4d0bf552016-12-28 15:45:24 -0500609
610 return vk::NoError();
611}
612
Jamie Madille918de22017-04-12 10:21:11 -0400613vk::Error RendererVk::submitCommandsWithSync(const vk::CommandBuffer &commandBuffer,
614 const vk::Semaphore &waitSemaphore,
615 const vk::Semaphore &signalSemaphore)
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500616{
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 Madille918de22017-04-12 10:21:11 -0400626 submitInfo.pCommandBuffers = commandBuffer.ptr();
627 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 Madill4c26fc22017-02-24 11:04:10 -0500631 ANGLE_TRY(submit(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 Madillf651c772017-02-21 15:03:51 -0500640 checkInFlightCommands();
Jamie Madill4c26fc22017-02-24 11:04:10 -0500641 return vk::NoError();
642}
643
644vk::Error RendererVk::checkInFlightCommands()
645{
Jamie Madillf651c772017-02-21 15:03:51 -0500646 bool anyFinished = false;
647
Jamie Madill4c26fc22017-02-24 11:04:10 -0500648 // Check if any in-flight command buffers are finished.
649 for (size_t index = 0; index < mInFlightCommands.size();)
650 {
651 auto *inFlightCommand = &mInFlightCommands[index];
652
653 bool done = false;
654 ANGLE_TRY_RESULT(inFlightCommand->finished(mDevice), done);
655 if (done)
656 {
657 ASSERT(inFlightCommand->queueSerial() > mLastCompletedQueueSerial);
658 mLastCompletedQueueSerial = inFlightCommand->queueSerial();
659 inFlightCommand->destroy(mDevice);
660 mInFlightCommands.erase(mInFlightCommands.begin() + index);
Jamie Madillf651c772017-02-21 15:03:51 -0500661 anyFinished = true;
Jamie Madill4c26fc22017-02-24 11:04:10 -0500662 }
663 else
664 {
665 ++index;
666 }
667 }
668
Jamie Madillf651c772017-02-21 15:03:51 -0500669 if (anyFinished)
670 {
671 size_t freeIndex = 0;
672 for (; freeIndex < mGarbage.size(); ++freeIndex)
673 {
674 if (!mGarbage[freeIndex]->destroyIfComplete(mDevice, mLastCompletedQueueSerial))
675 break;
676 }
677
678 // Remove the entries from the garbage list - they should be ready to go.
679 if (freeIndex > 0)
680 {
681 mGarbage.erase(mGarbage.begin(), mGarbage.begin() + freeIndex);
682 }
683 }
684
Jamie Madill4c26fc22017-02-24 11:04:10 -0500685 return vk::NoError();
686}
687
688vk::Error RendererVk::submit(const VkSubmitInfo &submitInfo)
689{
690 checkInFlightCommands();
691
692 // Start a Fence to record when this command buffer finishes.
693 VkFenceCreateInfo fenceInfo;
694 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
695 fenceInfo.pNext = nullptr;
696 fenceInfo.flags = 0;
697
698 vk::Fence fence;
699 ANGLE_TRY(fence.init(mDevice, fenceInfo));
700
701 ANGLE_VK_TRY(vkQueueSubmit(mQueue, 1, &submitInfo, fence.getHandle()));
702
703 // Store this command buffer in the in-flight list.
704 mInFlightCommands.emplace_back(vk::FenceAndCommandBuffer(mCurrentQueueSerial, std::move(fence),
705 std::move(mCommandBuffer)));
706
707 // Sanity check.
708 ASSERT(mInFlightCommands.size() < 1000u);
709
710 // Increment the command buffer serial. If this fails, we need to restart ANGLE.
711 ANGLE_VK_CHECK(++mCurrentQueueSerial, VK_ERROR_OUT_OF_HOST_MEMORY);
712 return vk::NoError();
713}
714
Jamie Madill5deea722017-02-16 10:44:46 -0500715vk::Error RendererVk::createStagingImage(TextureDimension dimension,
716 const vk::Format &format,
717 const gl::Extents &extent,
718 vk::StagingImage *imageOut)
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500719{
720 ASSERT(mHostVisibleMemoryIndex != std::numeric_limits<uint32_t>::max());
721
Jamie Madill5deea722017-02-16 10:44:46 -0500722 ANGLE_TRY(imageOut->init(mDevice, mCurrentQueueFamilyIndex, mHostVisibleMemoryIndex, dimension,
723 format.native, extent));
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500724
Jamie Madill5deea722017-02-16 10:44:46 -0500725 return vk::NoError();
Jamie Madill7b57b9d2017-01-13 09:33:38 -0500726}
727
Jamie Madill8ecf7f92017-01-13 17:29:52 -0500728GlslangWrapper *RendererVk::getGlslangWrapper()
729{
730 return mGlslangWrapper;
731}
732
Jamie Madill4c26fc22017-02-24 11:04:10 -0500733Serial RendererVk::getCurrentQueueSerial() const
734{
735 return mCurrentQueueSerial;
736}
737
Jamie Madill9e54b5a2016-05-25 12:57:39 -0400738} // namespace rx