65.9K
CodeProject 正在变化。 阅读更多。
Home

Vulkan API with Kotlin Native - Draw

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2019年4月26日

GPL3

2分钟阅读

viewsIcon

7044

Kotlin Native 与 Vulkan API。绘制循环。

引言

好的,在之前的章节中,我们几乎准备好了所有东西来绘制一些内容。现在我将简要描述最后需要的类 - FrameBuffersSyncCommandBuffers

首先是 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 分支中提供。

 

历史

© . All rights reserved.