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