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