1 /// Vulkan implementation of GrAAL 2 module gfx.vulkan; 3 4 import gfx.bindings.vulkan; 5 import gfx.core.log : LogTag; 6 import gfx.graal; 7 8 enum gfxVkLogMask = 0x2000_0000; 9 package(gfx) immutable gfxVkLog = LogTag("GFX-VK", gfxVkLogMask); 10 11 // some standard layers 12 13 enum lunarGValidationLayers = [ 14 "VK_LAYER_LUNARG_core_validation", 15 "VK_LAYER_LUNARG_standard_validation", 16 "VK_LAYER_LUNARG_parameter_validation", 17 ]; 18 19 @property ApiProps vulkanApiProps() { 20 return ApiProps( 21 "vulkan", CoordSystem.rightHanded 22 ); 23 } 24 25 /// Load global level vulkan functions, and instance level layers and extensions 26 /// This function must be called before any other in this module 27 void vulkanInit() 28 { 29 synchronized { 30 _globCmds = loadVulkanGlobalCmds(); 31 _instanceLayers = loadInstanceLayers(); 32 _instanceExtensions = loadInstanceExtensions(); 33 } 34 } 35 36 struct VulkanVersion 37 { 38 import std.bitmanip : bitfields; 39 mixin(bitfields!( 40 uint, "patch", 12, 41 uint, "minor", 10, 42 uint, "major", 10, 43 )); 44 45 this (in uint major, in uint minor, in uint patch) { 46 this.major = major; this.minor = minor; this.patch = patch; 47 } 48 49 this (in uint vkVer) { 50 this(VK_VERSION_MAJOR(vkVer), VK_VERSION_MINOR(vkVer), VK_VERSION_PATCH(vkVer)); 51 } 52 53 static VulkanVersion fromUint(in uint vkVer) { 54 return *cast(VulkanVersion*)(cast(void*)&vkVer); 55 } 56 57 uint toUint() const { 58 return *cast(uint*)(cast(void*)&this); 59 } 60 61 string toString() { 62 import std.format : format; 63 return format("VulkanVersion(%s, %s, %s)", this.major, this.minor, this.patch); 64 } 65 } 66 67 unittest { 68 const vkVer = VK_MAKE_VERSION(12, 7, 38); 69 auto vv = VulkanVersion.fromUint(vkVer); 70 assert(vv.major == 12); 71 assert(vv.minor == 7); 72 assert(vv.patch == 38); 73 assert(vv.toUint() == vkVer); 74 } 75 76 struct VulkanLayerProperties 77 { 78 string layerName; 79 VulkanVersion specVer; 80 VulkanVersion implVer; 81 string description; 82 83 @property VulkanExtensionProperties[] instanceExtensions() 84 { 85 return loadInstanceExtensions(layerName); 86 } 87 } 88 89 struct VulkanExtensionProperties 90 { 91 string extensionName; 92 VulkanVersion specVer; 93 } 94 95 /// Retrieve available instance level layer properties 96 @property VulkanLayerProperties[] vulkanInstanceLayers() { 97 return _instanceLayers; 98 } 99 /// Retrieve available instance level extensions properties 100 @property VulkanExtensionProperties[] vulkanInstanceExtensions() 101 { 102 return _instanceExtensions; 103 } 104 105 /// Creates a vulkan instance with default layers and extensions 106 VulkanInstance createVulkanInstance(in string appName=null, 107 in VulkanVersion appVersion=VulkanVersion(0, 0, 0)) 108 { 109 debug { 110 const wantedLayers = lunarGValidationLayers; 111 const wantedExts = [ "VK_KHR_debug_report", "VK_EXT_debug_report" ]; 112 } 113 else { 114 const string[] wantedLayers = []; 115 const string[] wantedExts = []; 116 } 117 118 import gfx.vulkan.wsi : surfaceInstanceExtensions; 119 120 import std.algorithm : canFind, filter, map; 121 import std.array : array; 122 import std.range : chain; 123 124 const layers = wantedLayers 125 .filter!(l => _instanceLayers.map!(il => il.layerName).canFind(l)) 126 .array; 127 const exts = wantedExts 128 .filter!(e => _instanceExtensions.map!(ie => ie.extensionName).canFind(e)) 129 .array 130 ~ surfaceInstanceExtensions; 131 132 return createVulkanInstance(layers, exts, appName, appVersion); 133 } 134 135 /// Creates an Instance object with Vulkan backend with user specified layers and extensions 136 VulkanInstance createVulkanInstance(in string[] layers, in string[] extensions, 137 in string appName=null, 138 in VulkanVersion appVersion=VulkanVersion(0, 0, 0)) 139 { 140 import gfx : gfxVersionMaj, gfxVersionMin, gfxVersionMic; 141 import std.algorithm : all, canFind, map; 142 import std.array : array; 143 import std.exception : enforce; 144 import std.string : toStringz; 145 146 // throw if some requested layers or extensions are not available 147 // TODO: specific exception 148 foreach (l; layers) { 149 enforce( 150 _instanceLayers.map!(il => il.layerName).canFind(l), 151 "Could not find layer " ~ l ~ " when creating Vulkan instance" 152 ); 153 } 154 foreach (e; extensions) { 155 enforce( 156 _instanceExtensions.map!(ie => ie.extensionName).canFind(e), 157 "Could not find extension " ~ e ~ " when creating Vulkan instance" 158 ); 159 } 160 161 VkApplicationInfo ai; 162 ai.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; 163 if (appName.length) { 164 ai.pApplicationName = toStringz(appName); 165 } 166 ai.applicationVersion = appVersion.toUint(); 167 ai.pEngineName = "gfx-d\0".ptr; 168 ai.engineVersion = VK_MAKE_VERSION(gfxVersionMaj, gfxVersionMin, gfxVersionMic); 169 ai.apiVersion = VK_API_VERSION_1_0; 170 171 auto vkLayers = layers.map!toStringz.array; 172 auto vkExts = extensions.map!toStringz.array; 173 174 gfxVkLog.info("Opening Vulkan instance."); 175 gfxVkLog.infof("Vulan layers:%s", layers.length?"":" none"); 176 foreach (l; layers) { 177 gfxVkLog.infof(" %s", l); 178 } 179 gfxVkLog.infof("Vulan extensions:%s", extensions.length?"":" none"); 180 foreach (e; extensions) { 181 gfxVkLog.infof(" %s", e); 182 } 183 184 185 186 VkInstanceCreateInfo ici; 187 ici.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 188 ici.pApplicationInfo = &ai; 189 ici.enabledLayerCount = cast(uint)vkLayers.length; 190 ici.ppEnabledLayerNames = vkLayers.ptr; 191 ici.enabledExtensionCount = cast(uint)vkExts.length; 192 ici.ppEnabledExtensionNames = vkExts.ptr; 193 194 auto vk = _globCmds; 195 VkInstance vkInst; 196 vulkanEnforce(vk.CreateInstance(&ici, null, &vkInst), "Could not create Vulkan instance"); 197 198 return new VulkanInstance(vkInst); 199 } 200 201 /// Retrieve available device level layers 202 @property VulkanLayerProperties[] vulkanDeviceLayers(PhysicalDevice device) { 203 auto pd = cast(VulkanPhysicalDevice)device; 204 if (!pd) return []; 205 206 return pd._availableLayers; 207 } 208 /// Retrieve available instance level extensions properties 209 VulkanExtensionProperties[] vulkanDeviceExtensions(PhysicalDevice device, in string layerName=null) 210 { 211 auto pd = cast(VulkanPhysicalDevice)device; 212 if (!pd) return []; 213 214 if (!layerName) { 215 return pd._availableExtensions; 216 } 217 else { 218 return pd.loadDeviceExtensions(layerName); 219 } 220 } 221 222 void overrideDeviceOpenVulkanLayers(PhysicalDevice device, string[] layers) 223 { 224 auto pd = cast(VulkanPhysicalDevice)device; 225 if (!pd) return; 226 227 pd._openLayers = layers; 228 } 229 230 void overrideDeviceOpenVulkanExtensions(PhysicalDevice device, string[] extensions) 231 { 232 auto pd = cast(VulkanPhysicalDevice)device; 233 if (!pd) return; 234 235 pd._openExtensions = extensions; 236 } 237 238 239 package: 240 241 import gfx.core.rc; 242 import gfx.graal.device; 243 import gfx.graal.format; 244 import gfx.graal.memory; 245 import gfx.graal.presentation; 246 import gfx.graal.queue; 247 import gfx.vulkan.conv; 248 import gfx.vulkan.device; 249 import gfx.vulkan.error; 250 import gfx.vulkan.wsi : VulkanSurface; 251 252 import std.exception : enforce; 253 254 __gshared VkGlobalCmds _globCmds; 255 __gshared VulkanLayerProperties[] _instanceLayers; 256 __gshared VulkanExtensionProperties[] _instanceExtensions; 257 258 VulkanLayerProperties[] loadInstanceLayers() 259 { 260 auto vk = _globCmds; 261 uint count; 262 vulkanEnforce( 263 vk.EnumerateInstanceLayerProperties(&count, null), 264 "Could not retrieve Vulkan instance layers" 265 ); 266 if (!count) return[]; 267 268 auto vkLayers = new VkLayerProperties[count]; 269 vulkanEnforce( 270 vk.EnumerateInstanceLayerProperties(&count, &vkLayers[0]), 271 "Could not retrieve Vulkan instance layers" 272 ); 273 274 import std.algorithm : map; 275 import std.array : array; 276 import std.string : fromStringz; 277 278 return vkLayers 279 .map!((ref VkLayerProperties vkLp) { 280 return VulkanLayerProperties( 281 fromStringz(&vkLp.layerName[0]).idup, 282 VulkanVersion.fromUint(vkLp.specVersion), 283 VulkanVersion.fromUint(vkLp.implementationVersion), 284 fromStringz(&vkLp.description[0]).idup, 285 ); 286 }) 287 .array; 288 } 289 290 VulkanExtensionProperties[] loadInstanceExtensions(in string layerName=null) 291 { 292 import std.string : toStringz; 293 294 const(char)* layer; 295 if (layerName.length) { 296 layer = toStringz(layerName); 297 } 298 auto vk = _globCmds; 299 uint count; 300 vulkanEnforce( 301 vk.EnumerateInstanceExtensionProperties(layer, &count, null), 302 "Could not retrieve Vulkan instance extensions" 303 ); 304 if (!count) return[]; 305 306 auto vkExts = new VkExtensionProperties[count]; 307 vulkanEnforce( 308 vk.EnumerateInstanceExtensionProperties(layer, &count, &vkExts[0]), 309 "Could not retrieve Vulkan instance extensions" 310 ); 311 312 import std.algorithm : map; 313 import std.array : array; 314 import std.string : fromStringz; 315 316 return vkExts 317 .map!((ref VkExtensionProperties vkExt) { 318 return VulkanExtensionProperties( 319 fromStringz(&vkExt.extensionName[0]).idup, 320 VulkanVersion.fromUint(vkExt.specVersion) 321 ); 322 }) 323 .array; 324 } 325 326 VulkanLayerProperties[] loadDeviceLayers(VulkanPhysicalDevice pd) 327 { 328 auto vk = pd.vk; 329 uint count; 330 vulkanEnforce( 331 vk.EnumerateDeviceLayerProperties(pd.vkObj, &count, null), 332 "Could not retrieve Vulkan device layers" 333 ); 334 if (!count) return[]; 335 336 auto vkLayers = new VkLayerProperties[count]; 337 vulkanEnforce( 338 vk.EnumerateDeviceLayerProperties(pd.vkObj, &count, &vkLayers[0]), 339 "Could not retrieve Vulkan device layers" 340 ); 341 342 import std.algorithm : map; 343 import std.array : array; 344 import std.string : fromStringz; 345 346 return vkLayers 347 .map!((ref VkLayerProperties vkLp) { 348 return VulkanLayerProperties( 349 fromStringz(&vkLp.layerName[0]).idup, 350 VulkanVersion.fromUint(vkLp.specVersion), 351 VulkanVersion.fromUint(vkLp.implementationVersion), 352 fromStringz(&vkLp.description[0]).idup, 353 ); 354 }) 355 .array; 356 } 357 358 VulkanExtensionProperties[] loadDeviceExtensions(VulkanPhysicalDevice pd, in string layerName=null) 359 { 360 import std.string : toStringz; 361 362 const(char)* layer; 363 if (layerName.length) { 364 layer = toStringz(layerName); 365 } 366 367 auto vk = pd.vk; 368 uint count; 369 vulkanEnforce( 370 vk.EnumerateDeviceExtensionProperties(pd.vkObj, layer, &count, null), 371 "Could not retrieve Vulkan device extensions" 372 ); 373 if (!count) return[]; 374 375 auto vkExts = new VkExtensionProperties[count]; 376 vulkanEnforce( 377 vk.EnumerateDeviceExtensionProperties(pd.vkObj, layer, &count, &vkExts[0]), 378 "Could not retrieve Vulkan device extensions" 379 ); 380 381 import std.algorithm : map; 382 import std.array : array; 383 import std.string : fromStringz; 384 385 return vkExts 386 .map!((ref VkExtensionProperties vkExt) { 387 return VulkanExtensionProperties( 388 fromStringz(&vkExt.extensionName[0]).idup, 389 VulkanVersion.fromUint(vkExt.specVersion) 390 ); 391 }) 392 .array; 393 } 394 395 class VulkanObj(VkType) 396 { 397 this (VkType vkObj) { 398 _vkObj = vkObj; 399 } 400 401 final @property VkType vkObj() { 402 return _vkObj; 403 } 404 405 private VkType _vkObj; 406 } 407 408 class VulkanInstObj(VkType) : Disposable 409 { 410 this (VkType vkObj, VulkanInstance inst) 411 { 412 _vkObj = vkObj; 413 _inst = inst; 414 _inst.retain(); 415 } 416 417 override void dispose() { 418 _inst.release(); 419 _inst = null; 420 } 421 422 final @property VkType vkObj() { 423 return _vkObj; 424 } 425 426 final @property VulkanInstance inst() { 427 return _inst; 428 } 429 430 final @property VkInstance vkInst() { 431 return _inst.vkObj; 432 } 433 434 private VkType _vkObj; 435 private VulkanInstance _inst; 436 } 437 438 final class VulkanInstance : VulkanObj!(VkInstance), Instance 439 { 440 mixin(atomicRcCode); 441 442 this(VkInstance vkObj) { 443 super(vkObj); 444 _vk = new VkInstanceCmds(vkObj, _globCmds); 445 } 446 447 override void dispose() { 448 if (_vkCb) { 449 vk.DestroyDebugReportCallbackEXT(vkObj, _vkCb, null); 450 _vkCb = VK_NULL_ND_HANDLE; 451 _callback = null; 452 } 453 vk.DestroyInstance(vkObj, null); 454 } 455 456 override @property Backend backend() { 457 return Backend.vulkan; 458 } 459 460 override @property ApiProps apiProps() { 461 return vulkanApiProps; 462 } 463 464 @property VkInstanceCmds vk() { 465 return _vk; 466 } 467 468 override PhysicalDevice[] devices() 469 { 470 import std.algorithm : map; 471 import std.array : array, uninitializedArray; 472 473 if (!_phDs.length) { 474 uint count; 475 vulkanEnforce(vk.EnumeratePhysicalDevices(vkObj, &count, null), 476 "Could not enumerate Vulkan devices"); 477 auto devices = uninitializedArray!(VkPhysicalDevice[])(count); 478 vulkanEnforce(vk.EnumeratePhysicalDevices(vkObj, &count, devices.ptr), 479 "Could not enumerate Vulkan devices"); 480 481 _phDs = devices 482 .map!(vkD => cast(PhysicalDevice)new VulkanPhysicalDevice(vkD, this)) 483 .array(); 484 } 485 return _phDs; 486 } 487 488 override void setDebugCallback(DebugCallback callback) { 489 VkDebugReportCallbackCreateInfoEXT ci; 490 ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; 491 ci.flags = 0x1f; 492 ci.pfnCallback = &gfxd_vk_DebugReportCallback; 493 ci.pUserData = cast(void*)this; 494 495 vk.CreateDebugReportCallbackEXT(vkObj, &ci, null, &_vkCb); 496 _callback = callback; 497 } 498 499 VkInstanceCmds _vk; 500 PhysicalDevice[] _phDs; 501 VkDebugReportCallbackEXT _vkCb; 502 DebugCallback _callback; 503 } 504 505 extern(C) nothrow { 506 VkBool32 gfxd_vk_DebugReportCallback(VkDebugReportFlagsEXT flags, 507 VkDebugReportObjectTypeEXT objectType, 508 ulong object, 509 size_t location, 510 int messageCode, 511 const(char)* pLayerPrefix, 512 const(char)* pMessage, 513 void* pUserData) 514 { 515 auto vkInst = cast(VulkanInstance)pUserData; 516 if (vkInst && vkInst._callback) { 517 import gfx.vulkan.conv : debugReportFlagsToGfx; 518 import std.string : fromStringz; 519 try { 520 vkInst._callback(debugReportFlagsToGfx(flags), fromStringz(pMessage).idup); 521 } 522 catch(Exception ex) { 523 import std.exception : collectException; 524 import std.stdio : stderr; 525 collectException( 526 stderr.writefln("Exception thrown in debug callback: %s", ex.msg) 527 ); 528 } 529 } 530 531 return VK_FALSE; 532 } 533 } 534 535 final class VulkanPhysicalDevice : PhysicalDevice 536 { 537 this(VkPhysicalDevice vkObj, VulkanInstance inst) { 538 _vkObj = vkObj; 539 _inst = inst; 540 _vk = _inst.vk; 541 542 vk.GetPhysicalDeviceProperties(_vkObj, &_vkProps); 543 544 _availableLayers = loadDeviceLayers(this); 545 _availableExtensions = loadDeviceExtensions(this); 546 547 import std.algorithm : canFind, map; 548 import std.exception : enforce; 549 debug { 550 foreach (l; lunarGValidationLayers) { 551 if (_availableLayers.map!"a.layerName".canFind(l)) { 552 _openLayers ~= l; 553 } 554 } 555 } 556 version(GfxOffscreen) {} 557 else { 558 import gfx.vulkan.wsi : swapChainExtension; 559 enforce(_availableExtensions.map!"a.extensionName".canFind(swapChainExtension)); 560 _openExtensions ~= swapChainExtension; 561 } 562 } 563 564 @property VkPhysicalDevice vkObj() { 565 return _vkObj; 566 } 567 568 @property VkInstanceCmds vk() { 569 return _vk; 570 } 571 572 override @property Instance instance() 573 { 574 auto inst = lockObj(_inst); 575 if (!inst) return null; 576 return giveAwayObj(inst); 577 } 578 579 override @property string name() { 580 import std.string : fromStringz; 581 return fromStringz(_vkProps.deviceName.ptr).idup; 582 } 583 override @property DeviceType type() { 584 return devTypeToGfx(_vkProps.deviceType); 585 } 586 override @property DeviceFeatures features() { 587 import std.algorithm : canFind, map; 588 import gfx.vulkan.wsi : swapChainExtension; 589 590 VkPhysicalDeviceFeatures vkFeats; 591 vk.GetPhysicalDeviceFeatures(vkObj, &vkFeats); 592 593 DeviceFeatures features; 594 features.anisotropy = vkFeats.samplerAnisotropy == VK_TRUE; 595 features.presentation = vulkanDeviceExtensions(this) 596 .map!(e => e.extensionName) 597 .canFind(swapChainExtension); 598 return features; 599 } 600 override @property DeviceLimits limits() 601 { 602 DeviceLimits limits; 603 limits.linearOptimalGranularity = 604 cast(size_t)_vkProps.limits.bufferImageGranularity; 605 return limits; 606 } 607 608 override @property MemoryProperties memoryProperties() 609 { 610 VkPhysicalDeviceMemoryProperties vkProps=void; 611 vk.GetPhysicalDeviceMemoryProperties(_vkObj, &vkProps); 612 613 MemoryProperties props; 614 615 foreach(i; 0 .. vkProps.memoryHeapCount) { 616 const vkHeap = vkProps.memoryHeaps[i]; 617 props.heaps ~= MemoryHeap( 618 cast(size_t)vkHeap.size, (vkHeap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0 619 ); 620 } 621 foreach(i; 0 .. vkProps.memoryTypeCount) { 622 const vkMemType = vkProps.memoryTypes[i]; 623 props.types ~= MemoryType( 624 memPropsToGfx(vkMemType.propertyFlags), 625 vkMemType.heapIndex, 626 ); 627 } 628 629 return props; 630 } 631 632 override @property QueueFamily[] queueFamilies() 633 { 634 import std.array : array, uninitializedArray; 635 uint count; 636 vk.GetPhysicalDeviceQueueFamilyProperties(_vkObj, &count, null); 637 638 auto vkQueueFams = uninitializedArray!(VkQueueFamilyProperties[])(count); 639 vk.GetPhysicalDeviceQueueFamilyProperties(_vkObj, &count, vkQueueFams.ptr); 640 641 import std.algorithm : map; 642 return vkQueueFams.map!(vkObj => QueueFamily( 643 queueCapToGfx(vkObj.queueFlags), vkObj.queueCount 644 )).array; 645 } 646 647 override FormatProperties formatProperties(in Format format) 648 { 649 VkFormatProperties vkFp; 650 vk.GetPhysicalDeviceFormatProperties(_vkObj, format.toVk(), &vkFp); 651 652 return FormatProperties( 653 vkFp.linearTilingFeatures.toGfx(), 654 vkFp.optimalTilingFeatures.toGfx(), 655 vkFp.bufferFeatures.toGfx(), 656 ); 657 } 658 659 override bool supportsSurface(uint queueFamilyIndex, Surface graalSurface) { 660 auto surf = enforce( 661 cast(VulkanSurface)graalSurface, 662 "Did not pass a Vulkan surface" 663 ); 664 VkBool32 supported; 665 vulkanEnforce( 666 vk.GetPhysicalDeviceSurfaceSupportKHR(vkObj, queueFamilyIndex, surf.vkObj, &supported), 667 "Could not query vulkan surface support" 668 ); 669 return supported != VK_FALSE; 670 } 671 672 override SurfaceCaps surfaceCaps(Surface graalSurface) { 673 auto surf = enforce( 674 cast(VulkanSurface)graalSurface, 675 "Did not pass a Vulkan surface" 676 ); 677 VkSurfaceCapabilitiesKHR vkSc; 678 vulkanEnforce( 679 vk.GetPhysicalDeviceSurfaceCapabilitiesKHR(vkObj, surf.vkObj, &vkSc), 680 "Could not query vulkan surface capabilities" 681 ); 682 return vkSc.toGfx(); 683 } 684 685 override Format[] surfaceFormats(Surface graalSurface) { 686 auto surf = enforce( 687 cast(VulkanSurface)graalSurface, 688 "Did not pass a Vulkan surface" 689 ); 690 691 uint count; 692 vulkanEnforce( 693 vk.GetPhysicalDeviceSurfaceFormatsKHR(vkObj, surf.vkObj, &count, null), 694 "Could not query vulkan surface formats" 695 ); 696 auto vkSf = new VkSurfaceFormatKHR[count]; 697 vulkanEnforce( 698 vk.GetPhysicalDeviceSurfaceFormatsKHR(vkObj, surf.vkObj, &count, &vkSf[0]), 699 "Could not query vulkan surface formats" 700 ); 701 702 import std.algorithm : filter, map; 703 import std.array : array; 704 return vkSf 705 .filter!(sf => sf.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) 706 .map!(sf => sf.format.toGfx()) 707 .array; 708 } 709 710 override PresentMode[] surfacePresentModes(Surface graalSurface) { 711 auto surf = enforce( 712 cast(VulkanSurface)graalSurface, 713 "Did not pass a Vulkan surface" 714 ); 715 716 uint count; 717 vulkanEnforce( 718 vk.GetPhysicalDeviceSurfacePresentModesKHR(vkObj, surf.vkObj, &count, null), 719 "Could not query vulkan surface present modes" 720 ); 721 auto vkPms = new VkPresentModeKHR[count]; 722 vulkanEnforce( 723 vk.GetPhysicalDeviceSurfacePresentModesKHR(vkObj, surf.vkObj, &count, &vkPms[0]), 724 "Could not query vulkan surface present modes" 725 ); 726 727 import std.algorithm : filter, map; 728 import std.array : array; 729 return vkPms 730 .filter!(pm => pm.hasGfxSupport) 731 .map!(pm => pm.toGfx()) 732 .array; 733 } 734 735 override Device open(in QueueRequest[] queues, in DeviceFeatures features=DeviceFeatures.all) 736 { 737 import std.algorithm : filter, map, sort; 738 import std.array : array; 739 import std.exception : enforce; 740 import std.string : toStringz; 741 import gfx.vulkan.wsi : swapChainExtension; 742 743 if (!queues.length) { 744 return null; 745 } 746 747 const qcis = queues.map!((const(QueueRequest) r) { 748 VkDeviceQueueCreateInfo qci; 749 qci.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 750 qci.queueFamilyIndex = r.familyIndex; 751 qci.queueCount = cast(uint)r.priorities.length; 752 qci.pQueuePriorities = r.priorities.ptr; 753 return qci; 754 }).array; 755 756 const layers = _openLayers.map!toStringz.array; 757 const extensions = _openExtensions 758 .filter!(e => e != swapChainExtension || features.presentation) 759 .map!toStringz.array; 760 VkPhysicalDeviceFeatures vkFeats; 761 vkFeats.samplerAnisotropy = features.anisotropy ? VK_TRUE : VK_FALSE; 762 763 VkDeviceCreateInfo ci; 764 ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 765 ci.queueCreateInfoCount = cast(uint)qcis.length; 766 ci.pQueueCreateInfos = qcis.ptr; 767 ci.enabledLayerCount = cast(uint)layers.length; 768 ci.ppEnabledLayerNames = layers.ptr; 769 ci.enabledExtensionCount = cast(uint)extensions.length; 770 ci.ppEnabledExtensionNames = extensions.ptr; 771 ci.pEnabledFeatures = &vkFeats; 772 773 VkDevice vkDev; 774 vulkanEnforce(vk.CreateDevice(_vkObj, &ci, null, &vkDev), 775 "Vulkan device creation failed"); 776 777 return new VulkanDevice(vkDev, this, _inst); 778 } 779 780 private VkPhysicalDevice _vkObj; 781 private VkPhysicalDeviceProperties _vkProps; 782 private VulkanInstance _inst; 783 784 private VkInstanceCmds _vk; 785 786 private VulkanLayerProperties[] _availableLayers; 787 private VulkanExtensionProperties[] _availableExtensions; 788 789 private string[] _openLayers; 790 private string[] _openExtensions; 791 } 792 793 DeviceType devTypeToGfx(in VkPhysicalDeviceType vkType) 794 { 795 switch (vkType) { 796 case VK_PHYSICAL_DEVICE_TYPE_OTHER: 797 return DeviceType.other; 798 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: 799 return DeviceType.integratedGpu; 800 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: 801 return DeviceType.discreteGpu; 802 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: 803 return DeviceType.virtualGpu; 804 case VK_PHYSICAL_DEVICE_TYPE_CPU: 805 return DeviceType.cpu; 806 default: 807 assert(false, "unexpected vulkan device type constant"); 808 } 809 }