import vulkan
, vkTypes
, re
, bitops
, ../utils/lets
type
GPU* = object
handle*: VkPhysicalDevice
features*: VkPhysicalDeviceFeatures
properties*: VkPhysicalDeviceProperties
memory_properties*: VkPhysicalDeviceMemoryProperties
queueFamilyProperties*: seq[VkQueueFamilyProperties]
requestedFeatures*: VkPhysicalDeviceFeatures
#from sets import toHashSet, excl, len
from vulkan_utils import `<`, `==`, `>`
from ../utils/etc import toString, flatten2
from sequtils import anyIt, mapIt, filterIt, maxIndex, toSeq
from strutils import contains, isAlphaNumeric
proc getQProperties*(gpu: VkPhysicalDevice): seq[VkQueueFamilyProperties] =
var
queueCount : uint32
# formatCount: uint32
# supportsPresent: seq[VkBool32]
# gqni: uint32 = uint32.high
# pqni: uint32 = uint32.high
vkGetPhysicalDeviceQueueFamilyProperties(gpu, queueCount.addr, nil)
result = newSeq[VkQueueFamilyProperties](queueCount)
vkGetPhysicalDeviceQueueFamilyProperties(gpu, queueCount.addr, result[0].addr)
proc getSupportedDepthFormat*( gpu: VkPhysicalDevice
, depthFormat: var VkFormat
)
=
var
formatProps: VkFormatProperties
formats = [ VK_FORMAT_D32_SFLOAT_S8_UINT
, VK_FORMAT_D32_SFLOAT
, VK_FORMAT_D24_UNORM_S8_UINT
, VK_FORMAT_D16_UNORM_S8_UINT
, VK_FORMAT_D16_UNORM
]
for format in formats:
vkGetPhysicalDeviceFormatProperties( gpu
, format
, addr formatProps
)
if bitand(formatProps.optimalTilingFeatures.int
, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT.int
) > 0:
depthFormat = format
#echo "FOUND DEPTH_FORMAT:" & $depthFormat
break
else: echo "nope!" & $bitand(formatProps.optimalTilingFeatures.int
, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT.int
)
proc get_gpu*( instance: VkInstance
#, surface: VkSurfaceKHR
): GPU =
load_vulkan_functions_for_gpu(instance)
var gpuCount: uint32 = 0
discard vkEnumeratePhysicalDevices(instance, gpuCount.addr, nil)
var gpus = newSeq[VkPhysicalDevice](gpuCount)
discard vkEnumeratePhysicalDevices(instance, gpuCount.addr, gpus[0].addr)
case gpus.len
of 0: quit "ERROR: No GPUs found by `vkEnumeratePhysicalDevices`. This is probably a driver-related issue."
of 1:
var
devProps0: VKPhysicalDeviceProperties
features0: VkPhysicalDeviceFeatures
memoryProperties0: VkPhysicalDeviceMemoryProperties
#qFamilyProperties0: seq[VkQueueFamilyProperties]
vkGetPhysicalDeviceProperties( gpus[0]
, addr devProps0
)
if devProps0.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU or
devProps0.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
vkGetPhysicalDeviceFeatures(gpus[0], addr features0)
vkGetPhysicalDeviceMemoryProperties(gpus[0], addr memoryProperties0)
result = GPU( handle: gpus[0]
, features: features0
, properties: devProps0
, memory_properties: memoryProperties0
, queueFamilyProperties: gpus[0].getQProperties
)
else: quit "ERROR: The only GPU/device found is not a Discrete or Integrated type, it is: " & $devProps0.deviceType & " \n Which is currently not supported."
of 2:
# Handle:
# 1 GPU with 2 different drivers -> Use the first
# 2 GPUs: 1 Discrete 1 integrated -> Use the Discrete
# 2 GPUs: 2 Integrated || 2 Discrete -> Use the better one
var
devProps0: VKPhysicalDeviceProperties
devProps1: VKPhysicalDeviceProperties
features0: VkPhysicalDeviceFeatures
memoryProperties0: VkPhysicalDeviceMemoryProperties
#qFamilyProperties0: seq[VkQueueFamilyProperties]
vkGetPhysicalDeviceProperties(gpus[0], addr devProps0)
vkGetPhysicalDeviceProperties(gpus[1], addr devProps1)
# 1 GPU with 2 different drivers -> Use the first
if devProps0.deviceID == devProps1.deviceID:
vkGetPhysicalDeviceFeatures(gpus[0], addr features0)
vkGetPhysicalDeviceMemoryProperties(gpus[0], addr memoryProperties0)
result = GPU( handle: gpus[0]
, features: features0
, properties: devProps0
, memory_properties: memoryProperties0
, queueFamilyProperties: gpus[0].getQProperties
)
#2 GPUs: 1 Discrete 1 integrated, Discrete is the first GPU
if devProps0.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU and
devProps1.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
vkGetPhysicalDeviceFeatures(gpus[0], addr features0)
vkGetPhysicalDeviceMemoryProperties(gpus[0], addr memoryProperties0)
result = GPU( handle: gpus[0]
, features: features0
, properties: devProps0
, memory_properties: memoryProperties0
, queueFamilyProperties: gpus[0].getQProperties
)
#2 GPUs: 1 Discrete 1 integrated, Integrated is the first GPU, so we choose the second (Discrete)
elif devProps0.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU and
devProps1.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
var
features1: VkPhysicalDeviceFeatures
memoryProperties1: VkPhysicalDeviceMemoryProperties
vkGetPhysicalDeviceFeatures(gpus[1], addr features1)
vkGetPhysicalDeviceMemoryProperties(gpus[1], addr memoryProperties1)
result = GPU( handle: gpus[1]
, features: features1
, properties: devProps1
, memory_properties: memoryProperties1
, queueFamilyProperties: gpus[1].getQProperties
)
#2 GPUs: 2 Integrated || 2 Discrete -> Find VRAM sizes, and use the GPU with the larger one, or if they're the same, use the first
if devProps0.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU and
devProps1.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU or
devProps0.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU and
devProps1.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
var
memoryProperties0: VkPhysicalDeviceMemoryProperties
memoryProperties1: VkPhysicalDeviceMemoryProperties
features1: VkPhysicalDeviceFeatures
vkGetPhysicalDeviceMemoryProperties(gpus[0], addr memoryProperties0)
vkGetPhysicalDeviceMemoryProperties(gpus[1], addr memoryProperties1)
if memoryProperties0.memoryHeaps[0].size > memoryProperties1.memoryHeaps[0].size or
memoryProperties0.memoryHeaps[0].size == memoryProperties1.memoryHeaps[0].size:
result = GPU( handle: gpus[0]
, features: features0
, properties: devProps0
, memory_properties: memoryProperties0
, queueFamilyProperties: gpus[0].getQProperties
)
else:
vkGetPhysicalDeviceFeatures(gpus[0], addr features1)
result = GPU( handle: gpus[1]
, features: features1
, properties: devProps1
, memory_properties: memoryProperties1
, queueFamilyProperties: gpus[1].getQProperties
)
# 3 or more GPUs, -> Find Discrete, or Integrated, else error
else:
var
memoryProperties: seq[VkPhysicalDeviceMemoryProperties]
devProps: seq[VKPhysicalDeviceProperties]
features: seq[VkPhysicalDeviceFeatures]
gpuIndex: Natural
for i, d in gpus:
var
someFeatures: VkPhysicalDeviceFeatures
someMemoryProperties: VkPhysicalDeviceMemoryProperties
someDevProps: VKPhysicalDeviceProperties
vkGetPhysicalDeviceFeatures(d, addr someFeatures)
vkGetPhysicalDeviceMemoryProperties(d, addr someMemoryProperties)
vkGetPhysicalDeviceProperties(d, addr someDevProps)
features.add someFeatures
memoryProperties.add someMemoryProperties
devProps.add someDevProps
gpuIndex = maxIndex toSeq memoryProperties.mapit(it.memoryHeaps[0].size)
result = GPU( handle: gpus[gpuIndex]
, features: features[gpuIndex]
, properties: devProps[gpuIndex]
, memory_properties: memoryProperties[gpuIndex]
, queueFamilyProperties: gpus[gpuIndex].getQProperties
)
# NOTE: All of this is probably not needed, because i'm pretty sure there's
# just some temp-bug or something with q'ing extensions.
# It's UB to have a device extension that is not supported by the GPU (?)
# so we check that all coreDeviceExts exist in the q'd extensions from the GPU
# and when an ext is found, we "check it off" by popping it off the seq
# if there's any that are not found, we quit, and the resulting exts are shown
proc check_gpu_extensions*( gpu: VkPhysicalDevice
, dump_extensions: bool = false
) =
var
extCount: uint32
checkList: seq[string] = toSeq coreDeviceExts
#extsNotFound: seq[string]
checkCount = checkList.len
#[ doubleExt = re"VK.*VK"
doubleExtToSplit = re"VK.*(?=VK)"
corruptedExt = re"VK.*[0-9](?=.*)"
allExts: seq[string]
]#
# var fixedList = availableExts.mapIt(it.extensionName.toString)
# .mapIt(it.split anExt)
# .flatten
# #.filterIt(it == "")
discard vkEnumerateDeviceExtensionProperties(gpu, nil, extCount.addr, nil)
var availableExts = newSeq[VkExtensionProperties](extCount)
discard vkEnumerateDeviceExtensionProperties(gpu, nil, extCount.addr, availableExts[0].addr)
for ext in availableExts.mapIt(it.extensionName):
var ne = ext.filterIt((it.isAlphaNumeric or it == '_') ).toString
if dump_extensions: echo ne
# for ext in allExts:
# echo ext
# for chExt in coreDeviceExts:
# echo availableExts.mapIt($it).contains chExt
if checkCount > 0:
echo checkList
# quit "wew ladddddddddddddddddddddddd"