SDL3_API分类参考_Vulkan 支持(CategoryVulkan)

2026-3-6 / 0 评论 / 4 阅读

Vulkan 适配子系统(CategoryVulkan)

SDL 提供一套专门用于在 SDL 窗口上创建 Vulkan 渲染表面(Surface)的函数集。

Vulkan 大部分功能可脱离 SDL 独立运行,但在初始化阶段需要 SDL 提供少量关键支持:

  1. 调用 SDL_Vulkan_GetInstanceExtensions() 获取创建 VkInstance 所需的平台相关扩展;
  2. 调用 SDL_Vulkan_GetVkGetInstanceProcAddr() 获取查询 Vulkan 入口点的适配函数;
  3. 调用 SDL_Vulkan_CreateSurface() 创建最终的 Vulkan 表面,完成 SDL 窗口与 Vulkan 渲染的绑定。

与 OpenGL 不同:Vulkan 的「上下文创建」「窗口缓冲区交换」等核心逻辑由 Vulkan API 直接处理,因此 SDL 无需提供 SDL_GL_SwapWindow() 等接口的 Vulkan 等效实现——这些接口在 Vulkan 中无必要。


函数

  • SDL_Vulkan_CreateSurface:为 SDL 窗口创建 Vulkan 渲染表面(VkSurfaceKHR),完成窗口与 Vulkan 的绑定
  • SDL_Vulkan_DestroySurface:销毁由 SDL 创建的 Vulkan 表面(释放关联资源)
  • SDL_Vulkan_GetInstanceExtensions:获取创建 VkInstance 所需的平台特定扩展列表(如 Windows 下的 VK_KHR_win32_surface)
  • SDL_Vulkan_GetPresentationSupport:检查指定的 Vulkan 物理设备/队列族是否支持在 SDL 窗口上进行图像展示
  • SDL_Vulkan_GetVkGetInstanceProcAddr:获取 Vulkan 实例的函数地址查询入口(vkGetInstanceProcAddr),适配不同平台的函数加载逻辑
  • SDL_Vulkan_LoadLibrary:加载系统中的 Vulkan 动态库(如 Windows 下的 vulkan-1.dll,Linux 下的 libvulkan.so)
  • SDL_Vulkan_UnloadLibrary:卸载已加载的 Vulkan 动态库(释放库资源)

数据类型

  • (无)

结构体

  • (无)

枚举

  • (无)

  • (无)

FreeBASIC 示例代码

' 注意:需提前安装 Vulkan SDK,并在编译时链接 Vulkan 库和 SDL 库
' 编译示例:fbc -lSDL3 -lvulkan vulkan_sdl.bas

' 引入 SDL 和 Vulkan 头文件
#Include "SDL.bi"
#Include "vulkan/vulkan.bi"

' 类型别名(简化 Vulkan 函数指针声明)
Type PFN_vkGetInstanceProcAddr As Function (ByVal instance As VkInstance, ByVal pName As ZString Ptr) As PFN_vkVoidFunction
Type PFN_vkCreateInstance As Function (ByVal pCreateInfo As VkInstanceCreateInfo Ptr, ByVal pAllocator As VkAllocationCallbacks Ptr, ByVal pInstance As VkInstance Ptr) As VkResult
Type PFN_vkDestroyInstance As Function (ByVal instance As VkInstance, ByVal pAllocator As VkAllocationCallbacks Ptr) As Void

' 错误处理辅助函数
Sub CheckResult(ByVal res As VkResult, ByVal msg As String)
    If (res <> VK_SUCCESS) Then
        SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "%s 失败,错误码:%d", msg, res)
        End 1
    End If
End Sub

' 主程序
Dim As SDL_Window Ptr window = NULL
Dim As VkInstance vulkanInstance
Dim As VkSurfaceKHR vulkanSurface
Dim As ZString Ptr extensions = NULL
Dim As UInteger extensionCount = 0
Dim As PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL
Dim As PFN_vkCreateInstance vkCreateInstance = NULL
Dim As PFN_vkDestroyInstance vkDestroyInstance = NULL
Dim As VkInstanceCreateInfo createInfo
Dim As VkResult res

' 1. 初始化 SDL 视频子系统
If (SDL_Init(SDL_INIT_VIDEO) < 0) Then
    SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "SDL 初始化失败:%s", SDL_GetError())
    End 1
End If

' 2. 加载 Vulkan 动态库
If (SDL_Vulkan_LoadLibrary(NULL) < 0) Then
    SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "加载 Vulkan 库失败:%s", SDL_GetError())
    SDL_Quit()
    End 1
End If
SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "Vulkan 库加载成功")

' 3. 创建 SDL 窗口(需指定 Vulkan 兼容标志)
window = SDL_CreateWindow("SDL + Vulkan 示例", _
    SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _
    800, 600, SDL_WINDOW_VULKAN Or SDL_WINDOW_SHOWN)
If (window = NULL) Then
    SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "创建 SDL 窗口失败:%s", SDL_GetError())
    SDL_Vulkan_UnloadLibrary()
    SDL_Quit()
    End 1
End If

' 4. 获取 Vulkan 实例所需的扩展列表
If (SDL_Vulkan_GetInstanceExtensions(window, @extensionCount, NULL) < 0) Then
    SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "获取扩展列表长度失败:%s", SDL_GetError())
    goto cleanup
End If
SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "需要 %d 个 Vulkan 扩展", extensionCount)

If (extensionCount > 0) Then
    extensions = Callocate(extensionCount * SizeOf(ZString Ptr))
    If (SDL_Vulkan_GetInstanceExtensions(window, @extensionCount, extensions) < 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "获取扩展列表失败:%s", SDL_GetError())
        goto cleanup
    End If

    ' 打印扩展名称
    For i As Integer = 0 To extensionCount - 1
        SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "扩展 %d:%s", i, extensions[i])
    Next
End If

' 5. 获取 Vulkan 入口函数
vkGetInstanceProcAddr = SDL_Vulkan_GetVkGetInstanceProcAddr()
If (vkGetInstanceProcAddr = NULL) Then
    SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "获取 vkGetInstanceProcAddr 失败")
    goto cleanup
End If

' 6. 创建 Vulkan 实例
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
createInfo.enabledExtensionCount = extensionCount
createInfo.ppEnabledExtensionNames = extensions
createInfo.enabledLayerCount = 0
createInfo.ppEnabledLayerNames = NULL

vkCreateInstance = Cast(PFN_vkCreateInstance, vkGetInstanceProcAddr(NULL, "vkCreateInstance"))
res = vkCreateInstance(@createInfo, NULL, @vulkanInstance)
CheckResult(res, "创建 VkInstance")
SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "VkInstance 创建成功")

' 7. 为 SDL 窗口创建 Vulkan 表面
If (SDL_Vulkan_CreateSurface(window, vulkanInstance, NULL, @vulkanSurface) < 0) Then
    SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "创建 Vulkan Surface 失败:%s", SDL_GetError())
    goto cleanup
End If
SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "Vulkan Surface 创建成功")

' 8. 检查展示支持(示例:使用第一个物理设备的第0个队列族)
Dim As VkPhysicalDevice physicalDevices(0 To 10)
Dim As UInteger physDevCount = 0
Dim As PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices = Cast(PFN_vkEnumeratePhysicalDevices, vkGetInstanceProcAddr(vulkanInstance, "vkEnumeratePhysicalDevices"))
res = vkEnumeratePhysicalDevices(vulkanInstance, @physDevCount, NULL)
CheckResult(res, "枚举物理设备")
res = vkEnumeratePhysicalDevices(vulkanInstance, @physDevCount, @physicalDevices(0))
CheckResult(res, "获取物理设备列表")

If (physDevCount > 0) Then
    Dim As Integer support = SDL_Vulkan_GetPresentationSupport(vulkanInstance, physicalDevices(0), 0)
    SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "物理设备 0 队列族 0 是否支持展示:%s", IIf(support, "是", "否"))
End If

' 等待用户输入后清理
SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "按任意键退出...")
Dim As String dummy
Input dummy

' 9. 清理资源
cleanup:
If (vulkanSurface <> VK_NULL_HANDLE) Then
    Dim As PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR = Cast(PFN_vkDestroySurfaceKHR, vkGetInstanceProcAddr(vulkanInstance, "vkDestroySurfaceKHR"))
    vkDestroySurfaceKHR(vulkanInstance, vulkanSurface, NULL)
End If

If (vulkanInstance <> VK_NULL_HANDLE) Then
    vkDestroyInstance = Cast(PFN_vkDestroyInstance, vkGetInstanceProcAddr(vulkanInstance, "vkDestroyInstance"))
    vkDestroyInstance(vulkanInstance, NULL)
End If

If (extensions <> NULL) Then
    Deallocate(extensions)
End If

If (window <> NULL) Then
    SDL_DestroyWindow(window)
End If

SDL_Vulkan_UnloadLibrary()
SDL_Quit()
SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "程序正常退出")
End 0

总结

  1. SDL Vulkan 子系统核心作用是桥接 SDL 窗口与 Vulkan 渲染,关键接口是 SDL_Vulkan_CreateSurface(创建渲染表面)和 SDL_Vulkan_GetInstanceExtensions(获取平台扩展);
  2. FreeBASIC 中使用时,需先加载 Vulkan 动态库(SDL_Vulkan_LoadLibrary),创建带 SDL_WINDOW_VULKAN 标志的 SDL 窗口,再按「获取扩展→创建 VkInstance→创建 Surface」的流程初始化;
  3. Vulkan 的核心逻辑(如缓冲区交换、命令提交)由 Vulkan API 直接处理,SDL 仅负责窗口与 Vulkan 的基础绑定,无需额外的渲染同步接口。

评论一下?

OωO
取消