好的,现在是时候创建Vulkan表面,物理和逻辑设备了。Vulkan surface是我们已经创建的Windows,Linux或Android窗口(或其他支持的平台)的抽象。物理设备就是它所说的 - 安装了物理设备。从用户的角度来看,逻辑设备是物理设备。此外,在创建逻辑设备时,我们将创建命令池和队列。但首先,让我对代码进行一些小改动。当我们在一个且只有一个平台上工作时,我们会将Platform
类更改为单例。在Kotlin,这很容易 - 只需class
改为object
。相应地,它应该为两者expect
和actual
。
我们将在实际Platform
类中创建的Vulkan表面,因为它的创建对于每个平台是不同的。这取决于是否支持相应的扩展。VK_KHR_WIN32_SURFACE_EXTENSION_NAME
- 对于Windows,VK_KHR_XCB_SURFACE_EXTENSION_NAME
- 对于Linux等。对于Linux,我们也已经知道xcb_connection_t
并且有一个窗口id
。对于Windows - HWND
和HINSTANCE
。
因此,对于Windows,它将如下所示:
...
val surfaceInfo = alloc<VkWin32SurfaceCreateInfoKHR> {
sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR
pNext = null
flags = 0u
@Suppress("UNCHECKED_CAST")
hinstance = sharedData.hInstance!! as vulkan.HINSTANCE
@Suppress("UNCHECKED_CAST")
hwnd = sharedData.hwnd!! as vulkan.HWND
}
if (!VK_CHECK(vkCreateWin32SurfaceKHR
(instance, surfaceInfo.ptr, null, surfaceVar.ptr))) {
throw RuntimeException("Failed to create surface.")
}
...
而对于Linux:
...
val surfaceinfo = alloc<VkXcbSurfaceCreateInfoKHR> {
sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR
pNext = null
flags = 0u
window = sharedData.wnd
connection = sharedData.connection
}
val surface = alloc<VkSurfaceKHRVar>()
if (!VK_CHECK(vkCreateXcbSurfaceKHR
(instance, surfaceinfo.ptr, null, surface.ptr))) {
throw RuntimeException("Failed to create surface.")
}
...
没什么新的,只是结构和功能调用。
在这里,我们会更有趣。我们将枚举物理设备,选择第一个离散设备,获取驱动程序版本,表面功能,设备扩展。现在让我们在系统中查找并选择支持我们所需功能的显卡。为此,请使用我们已使用的标准方法:
...
var buffer: CArrayPointer<VkPhysicalDeviceVar>? = null
while (result == VK_INCOMPLETE) {
if (!VK_CHECK(vkEnumeratePhysicalDevices(instance, gpuCount.ptr, null)))
throw RuntimeException("Could not enumerate GPUs.")
buffer?.let {
nativeHeap.free(it)
buffer = null
}
buffer = nativeHeap.allocArray(gpuCount.value.toInt())
result = vkEnumeratePhysicalDevices(instance, gpuCount.ptr, buffer)
if (result != VK_INCOMPLETE && !VK_CHECK(result))
throw RuntimeException("Could not enumerate GPUs.")
}
...
拥有物理设备后,我们可以获得其属性。为此,我们将为表面功能,设备属性,队列属性等创建延迟初始化属性。例如,如果我们只想获得一个可呈现的队列,它将如下所示:
...
val presentableQueue by lazy {
val props = queueProperties.filter {
(it.queueFlags and VK_QUEUE_GRAPHICS_BIT) > 0u
}
memScoped {
props.mapIndexed { index, it ->
Pair(index, it)
}.indexOfFirst {
val p = alloc<VkBool32Var>()
vkGetPhysicalDeviceSurfaceSupportKHR(device, it.first.toUInt(), surface, p.ptr)
if (p.value == 1u) true else false
}
}
}
...
好的,现在我们掌握了有关物理设备的所有信息。
现在我们将创建与物理设备的连接。根据Vulkan规范:“ 应用程序必须为它将使用的每个物理设备创建一个单独的逻辑设备。创建的逻辑设备是物理设备的主要接口。 ”所以,让我们这样做,一路上也创建一个队列和命令池:
...
val queueCreateInfos: ArrayList<VkDeviceQueueCreateInfo> = ArrayList()
val defaultQueuePriority = allocArrayOf(1.0f)
val queueInfo = alloc<VkDeviceQueueCreateInfo>().apply {
sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO
queueCount = 1u
pQueuePriorities = defaultQueuePriority
}
if (presentable) {
val queue = pdevice.presentableQueue
if (queue < 0)
throw RuntimeException("Presentable queue not found")
_queueFamilyIndices.graphics = queue.toUInt()
queueInfo.queueFamilyIndex = _queueFamilyIndices.graphics!!
_poolType = PoolType.GRAPHICS
else {
...
}
if (useSwapChain && !enabledExtensions.contains(VK_KHR_SWAPCHAIN_EXTENSION_NAME))
enabledExtensions.add(VK_KHR_SWAPCHAIN_EXTENSION_NAME)
var idx = 0
val queueInfos = allocArray<VkDeviceQueueCreateInfo>(queueCreateInfos.size) {
val info = queueCreateInfos[idx++]
this.flags = info.flags
this.sType = info.sType
this.flags = info.flags
this.pNext = info.pNext
this.pQueuePriorities = info.pQueuePriorities
this.queueCount = info.queueCount
this.queueFamilyIndex = info.queueFamilyIndex
}
val deviceCreateInfo = alloc<VkDeviceCreateInfo>().apply {
sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO
queueCreateInfoCount = queueCreateInfos.size.toUInt()
pQueueCreateInfos = queueInfos
pEnabledFeatures = enabledFeatures?.ptr
}
if (enabledExtensions.size > 0) {
deviceCreateInfo.enabledExtensionCount = enabledExtensions.size.toUInt()
deviceCreateInfo.ppEnabledExtensionNames =
enabledExtensions.toCStringArray(memScope)
}
if (!VK_CHECK(vkCreateDevice
(pdevice.device, deviceCreateInfo.ptr, null, _device.ptr)))
throw RuntimeException("Failed to create _device")
logDebug("Ok logical device")
....
if (!VK_CHECK(vkCreateCommandPool
(_device.value, commandPoolCreateInfo.ptr, null, _commandPool.ptr)))
throw RuntimeException("Failed to create command pool")
vkGetDeviceQueue(
_device.value, when (_poolType) {
PoolType.GRAPHICS -> _queueFamilyIndices.graphics!!
PoolType.COMPUTE -> _queueFamilyIndices.compute!!
PoolType.TRANSFER -> _queueFamilyIndices.transfer!!
}, 0u, _deviceQueue.ptr
)
...
精细。现在我们有了物理设备,逻辑设备,命令池和队列。将它们添加到我们的渲染器类中,不要忘记处置资源和释放已分配的内存。
使用Kotlin Native的Vulkan表面,物理和逻辑设备 转载https://www.codesocang.com/appboke/39912.html
热门源码