Vulkan API with Kotlin Native - Draw





5.00/5 (1投票)
Kotlin Native 与 Vulkan API。绘制循环。
引言
好的,在之前的章节中,我们几乎准备好了所有东西来绘制一些内容。现在我将简要描述最后需要的类 - FrameBuffers
、Sync
和 CommandBuffers
。
首先是 FrameBuffers
类 - 用于定义我们将使用的附件、它们将使用的 ImageViews 以及它们各自的尺寸,符合规范。以及 FrameBuffers 类。它以标准方式创建,并使用相应的结构和 Vulkan API 函数调用。
接下来是 Sync
类。它将包含一个信号量来检查演示是否完成,以及一个信号量来检查渲染是否完成。以及用于命令缓冲区的栅栏列表。所有这些也都以标准方式创建。
最后一个是 CommandBuffers
类 - 为每个图像视图的命令缓冲区列表。在这里,我们将定义清除值(颜色/深度模板)、视口、剪切等。以标准方式创建。
主循环
最后,我们可以使用 Kotlin Native 绘制我们的第一个三角形。之前我们添加了用于创建其顶点和索引的缓冲区的辅助函数
triangle = VertexBuffer.Triangle(_physicalDevice!!, _logicalDevice!!)
步骤与我们使用 C++ 编码时相同
- 更新统一缓冲区
- 使用
vkAcquireNextImageKHR
函数获取下一个图像,并设置演示信号量 - 使用栅栏等待命令缓冲区完成执行
- 重置栅栏
- 提交到队列,并使用栅栏
- 将当前缓冲区呈现给交换链并传递
所以,它看起来会是这样
fun draw() {
_uniformBuffers!!.update()
// wait for a success or error
if (VK_CHECK(
vkAcquireNextImageKHR(
_logicalDevice!!.device,
_swapchain!!.swapchain,
UINT64_MAX,
_sync!!.presentSemaphore,
null,
currentBuffer.ptr
)
)
) {
// wait until the command buffer has finished execution
if (VK_CHECK(
vkWaitForFences(
_logicalDevice!!.device,
1u,
_sync!!.waitFences[currentBuffer.value.toInt()].ptr,
VK_TRUE.toUInt(),
UINT64_MAX
)
)
) {
if (VK_CHECK(
vkResetFences(
_logicalDevice!!.device,
1u,
_sync!!.waitFences[currentBuffer.value.toInt()].ptr
)
)
) {
memScoped {
// Pipeline stage for the queue to wait
val pipelineStageWaitFlags = alloc<VkPipelineStageFlagsVar>()
pipelineStageWaitFlags.value =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
val submitInfo = alloc<VkSubmitInfo>().apply {
sType = VK_STRUCTURE_TYPE_SUBMIT_INFO
pWaitDstStageMask = pipelineStageWaitFlags.ptr
pWaitSemaphores = _sync!!.presentSemaphorePtr
waitSemaphoreCount = 1u
pSignalSemaphores = _sync!!.renderSemaphorePtr
signalSemaphoreCount = 1u
commandBufferCount = 1u
pCommandBuffers =
_commandBuffers!!
.drawCmdBuffers[currentBuffer.value.toInt()].ptr
}
// Submit to the graphics queue
if (VK_CHECK(
vkQueueSubmit(
_logicalDevice!!.deviceQueue,
1u,
submitInfo.ptr,
_sync!!.waitFences[currentBuffer.value.toInt()]
.value
)
)
) {
// Present the current buffer to the swap chain
val swapchains = allocArray<VkSwapchainKHRVar>(1.toInt()) {
this.value = _swapchain!!.swapchain
}
val presentInfo = alloc<VkPresentInfoKHR>().apply {
sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR
pNext = null
swapchainCount = 1u
pSwapchains = swapchains
waitSemaphoreCount = 1u
pWaitSemaphores = _sync!!.renderSemaphorePtr
pImageIndices = currentBuffer.ptr
}
if (!VK_CHECK(vkQueuePresentKHR(_logicalDevice!!
.deviceQueue, presentInfo.ptr))) {
logError("Failed present queue")
}
} else {
logError("Failed submit queue")
}
}
} else {
logError("Failed fences reset")
}
} else {
logError("Failed fences wait")
}
} else {
logError("Failed aquire next image")
}
}
结果
这是我们的三角形
因此,我们使用稳定的 FPS 绘制了一些内容(现在它仅在 Windows 平台上工作)。当然,对于这样一个简单的场景,很难说性能如何。但作为 POC,我们证明了使用 Kotlin Native 与 Vulkan API 协同工作是可行的,而且非常容易。下一步我计划完成 Linux 平台,添加 ImGUI 并尝试一些复杂的场景。所有更改都将在 master 分支中提供。