You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Vulkan获取游戏运行时的Overlay表面以实现帧率计数器?

如何在Vulkan游戏中获取Overlay表面实现帧率计数器类工具

核心思路

要实现这类Overlay,本质是注入到目标游戏的Vulkan上下文,获取其设备、队列等核心资源,然后通过Hook游戏的渲染关键函数,插入自己的Overlay绘制逻辑,最终实现画面叠加效果。

具体步骤

1. 进程注入与Vulkan函数Hook

  • 先通过DLL注入(比如调用CreateRemoteThread)将工具代码注入目标游戏进程。
  • Hook Vulkan核心函数,重点关注三个关键节点:
    • vkCreateInstance:捕获游戏创建的Vulkan实例句柄,可添加自定义调试回调辅助后续排查问题。
    • vkCreateDevice:获取游戏的VkDevice句柄,以及用于帧呈现的队列家族和VkQueue对象。
    • vkQueuePresentKHR:这是游戏帧提交呈现的终点,在这里插入Overlay绘制逻辑,同时可获取帧时间戳计算帧率。

2. 复用或创建Overlay的VkSurfaceKHR

  • 更高效的方式是复用游戏已有的VkSurfaceKHR:通过HookvkQueuePresentKHR直接拿到游戏要呈现的Surface,无需额外创建新表面,避免窗口层级冲突。
  • 若需独立Surface,可基于游戏窗口句柄创建(以Windows平台为例):
    VkWin32SurfaceCreateInfoKHR createInfo{};
    createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
    createInfo.hwnd = gameWindowHandle; // 已获取的游戏窗口HWND
    createInfo.hinstance = GetModuleHandle(nullptr);
    
    VkSurfaceKHR overlaySurface;
    vkCreateWin32SurfaceKHR(instance, &createInfo, nullptr, &overlaySurface);
    

3. 构建Overlay渲染资源

  • 基于游戏的VkDevice,创建匹配游戏参数的Swapchain:
    VkSwapchainCreateInfoKHR swapchainCreateInfo{};
    swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
    swapchainCreateInfo.surface = gameSurface; // 复用的游戏Surface
    swapchainCreateInfo.imageFormat = gameSwapchainFormat; // 匹配游戏Swapchain格式
    swapchainCreateInfo.imageExtent = gameSwapchainExtent; // 匹配游戏分辨率
    
    VkSwapchainKHR overlaySwapchain;
    vkCreateSwapchainKHR(device, &swapchainCreateInfo, nullptr, &overlaySwapchain);
    
  • 创建自定义渲染通道、帧缓冲与管线:渲染通道需设置VK_ATTACHMENT_LOAD_OP_LOAD,保留游戏原画面后再叠加UI元素。

4. 插入Overlay绘制逻辑

  • 在Hook的vkQueuePresentKHR函数中,按以下流程执行:
    // 获取游戏要呈现的图像索引
    uint32_t imageIndex;
    vkAcquireNextImageKHR(device, gameSwapchain, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
    
    // 记录Overlay渲染命令
    vkBeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo);
    vkCmdBeginRenderPass(cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
    // 用UI库绘制帧率文本(比如ImGui)
    ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuffer);
    vkCmdEndRenderPass(cmdBuffer);
    vkEndCommandBuffer(cmdBuffer);
    
    // 提交Overlay命令到队列
    VkSubmitInfo submitInfo{};
    submitInfo.waitSemaphores = &imageAvailableSemaphore;
    submitInfo.commandBuffers = &cmdBuffer;
    vkQueueSubmit(presentQueue, 1, &submitInfo, renderFinishedSemaphore);
    
    // 调用原函数完成帧呈现
    VkPresentInfoKHR presentInfo{};
    presentInfo.waitSemaphores = &renderFinishedSemaphore;
    presentInfo.swapchains = &gameSwapchain;
    presentInfo.imageIndices = &imageIndex;
    originalVkQueuePresentKHR(presentQueue, &presentInfo);
    
  • 同步信号必须与游戏的同步逻辑兼容,避免帧卡顿或渲染异常。

5. 帧率计算实现

  • 在vkQueuePresentKHR的Hook函数中,通过时间戳计算帧率:
    LARGE_INTEGER currentTime, frequency;
    QueryPerformanceFrequency(&frequency);
    QueryPerformanceCounter(&currentTime);
    float deltaTime = (currentTime.QuadPart - lastTime.QuadPart) / (float)frequency.QuadPart;
    float fps = 1.0f / deltaTime;
    lastTime = currentTime;
    
  • 将计算出的fps转为文本,通过UI库绘制到Overlay上即可。

关键注意事项

  • 权限与反作弊:部分带反作弊的游戏会阻止外部进程注入,需确保工具权限合规。
  • 版本兼容:不同游戏可能使用不同版本的Vulkan,Hook逻辑需适配对应函数签名。
  • 资源清理:游戏退出时,需正确销毁所有自定义Vulkan资源(Swapchain、帧缓冲等),避免内存泄漏。

内容的提问来源于stack exchange,提问作者David Carpenter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 06:45:34