view semicongine/vulkan/device.nim @ 1091:b9401944ba0a

do: try to increase compatability with older hardware...
author sam <sam@basx.dev>
date Sat, 06 Apr 2024 17:29:48 +0700
parents 450b8a5042cd
children a4aa9f374d44
line wrap: on
line source

import std/sequtils
import std/options
import std/tables

import ../core
import ./instance
import ./physicaldevice

type
  Device* = object
    physicalDevice*: PhysicalDevice
    vk*: VkDevice
    queues*: Table[QueueFamily, Queue]
    enabledFeatures*: VkPhysicalDeviceFeatures
  Queue* = object
    vk*: VkQueue
    family*: QueueFamily
    presentation: bool
    graphics: bool

proc `$`*(device: Device): string =
  "Device: vk=" & $device.vk

proc createDevice*(
  instance: Instance,
  physicalDevice: PhysicalDevice,
  enabledExtensions: seq[string],
  queueFamilies: seq[QueueFamily],
): Device =
  assert instance.vk.valid
  assert physicalDevice.vk.valid
  assert queueFamilies.len > 0

  result.physicalDevice = physicalDevice
  # TODO: allowing support for physical devices without hasUniformBufferStandardLayout
  # would require us to ship different shaders, so we don't support standard layout
  # if that will be added, check the function vulkan/shaders.nim:glslUniforms and update accordingly
  # let hasUniformBufferStandardLayout = "VK_KHR_uniform_buffer_standard_layout" in physicalDevice.getExtensions()
  let hasUniformBufferStandardLayout = false

  var allExtensions = enabledExtensions & @["VK_KHR_swapchain"]
  if hasUniformBufferStandardLayout:
    allExtensions.add "VK_KHR_uniform_buffer_standard_layout"
  for extension in allExtensions:
    instance.vk.loadExtension(extension)

  var
    enabledExtensionsC = allocCStringArray(allExtensions)
    priority = 1'f32
  var deviceQueues: Table[QueueFamily, VkDeviceQueueCreateInfo]
  for family in queueFamilies:
    deviceQueues[family] = VkDeviceQueueCreateInfo(
      sType: VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
      queueFamilyIndex: family.index,
      queueCount: 1,
      pQueuePriorities: addr(priority),
    )
  var queueList = deviceQueues.values.toSeq

  var uniformBufferLayoutFeature = VkPhysicalDeviceUniformBufferStandardLayoutFeatures(
    stype: VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES,
    uniformBufferStandardLayout: true,
  )
  var features2 = VkPhysicalDeviceFeatures2(
    stype: VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
    features: result.enabledFeatures,
    pnext: if hasUniformBufferStandardLayout: addr uniformBufferLayoutFeature else: nil,
  )
  var createInfo = VkDeviceCreateInfo(
    sType: VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
    queueCreateInfoCount: uint32(queueList.len),
    pQueueCreateInfos: queueList.toCPointer,
    enabledLayerCount: 0,
    ppEnabledLayerNames: nil,
    enabledExtensionCount: uint32(allExtensions.len),
    ppEnabledExtensionNames: enabledExtensionsC,
    pEnabledFeatures: nil,
    pnext: addr features2,
  )

  checkVkResult vkCreateDevice(
    physicalDevice = physicalDevice.vk,
    pCreateInfo = addr createInfo,
    pAllocator = nil,
    pDevice = addr result.vk
  )
  deallocCStringArray(enabledExtensionsC)
  for family in deviceQueues.keys:
    var queue: VkQueue
    vkGetDeviceQueue(result.vk, family.index, 0, addr queue)
    result.queues[family] = Queue(vk: queue, family: family, presentation: family.canDoPresentation(physicalDevice.surface), graphics: family.canDoGraphics())

func firstGraphicsQueue*(device: Device): Option[Queue] =
  assert device.vk.valid
  for family, queue in device.queues:
    if queue.graphics:
      return some(queue)

proc firstPresentationQueue*(device: Device): Option[Queue] =
  assert device.vk.valid
  for family, queue in device.queues:
    if queue.presentation:
      return some(queue)

proc destroy*(device: var Device) =
  assert device.vk.valid
  device.vk.vkDestroyDevice(nil)
  device.vk.reset()