c++ - Nvidia 图形驱动程序导致明显的帧卡顿

标签 c++ multithreading graphics synchronization nvidia

好的,我已经研究这个问题几天了,所以让我回顾一下我到目前为止知道的内容,这让我相信这可能是 NVidia 驱动程序的问题,而不是我的代码.

基本上,我的游戏在运行几秒钟后就开始卡顿(随机帧需要 70 毫秒而不是 16 毫秒,在正常模式下)。仅当在 Nvidia 控制面板(最新驱动程序,Windows 10)中启用名为“线程优化”的设置时才会发生这种情况。不幸的是,此设置默认启用,我不想让人们调整他们的设置来获得愉快的体验。

  • 游戏不是 CPU 或 GPU 密集型游戏(不开启垂直同步时每帧 2 毫秒)。它没有调用任何需要同步数据的 openGL 函数,也没有流式传输任何缓冲区或从 GPU 或任何东西读回数据。关于最简单的渲染器。

  • 问题一直存在,当我在 fmod 中添加音频时,它才开始变得明显。 fmod 不是造成这种情况的原因(后面会详细介绍)

  • 尝试使用 NVidia Nsight 调试问题后,问题就消失了。 “开始收集数据”会立即让口吃消失。这里没有骰子。

  • 在 Profiler 中,大量 cpu 时间花在“nvoglv32.dll”中。此过程仅在启用线程优化时才会产生。我怀疑这是一个同步问题,所以我使用 Visual Studio Concurrency Viewer 进行调试。

  • 啊-哈! vsyncs

  • 在 nvidia 线程上调查这些 CPU 时间 block ,我可以在它们的调用堆栈中得到最早的命名函数是“CreateToolhelp32Snapshot”,然后在 Thread32Next 中花费了大量时间.我在前面查看 CPU 时间时注意到分析器中的 Thread32Next,所以这看起来确实是在正确的轨道上。

  • 所以看起来 nvidia 驱动程序出于某种原因会定期抓取整个过程的快照?可能是什么原因,为什么会这样,我该如何阻止它?

  • 这也解释了为什么在我添加 fmod 后问题开始变得明显,因为它会获取所有进程线程的信息,并且 fmod 会产生很多线程。

  • 有什么帮助吗?这只是 nvidia 驱动程序中的一个错误,还是我可以做些什么来修复它,告诉人们禁用线程“优化”?

编辑 1:我的笔记本电脑上当前的 nvidia 驱动程序也会出现同样的问题。所以我没疯

编辑 2:同样的问题出现在 362 版(以前的主要版本)的 nvidia 驱动程序上

最佳答案

... or is there something I can do to fix it other telling people to disable Threaded "Optimization"?

是的。

您可以使用 NVAPI 为您的游戏创建自定义“应用程序配置文件”并禁用其中的“线程优化”设置。

有一个.PDF file在 NVIDIA 网站上提供有关 NVAPI 使用的一些帮助和代码示例。

为了查看和管理您的所有 NVIDIA 配置文件,我建议使用 NVIDIA Inspector。它比默认的 NVIDIA 控制面板更方便。

另外,这是我的代码示例,它创建了禁用“线程优化”的“应用程序配置文件”:

#include <stdlib.h>
#include <stdio.h>

#include <nvapi.h>
#include <NvApiDriverSettings.h>


const wchar_t*  profileName             = L"Your Profile Name";
const wchar_t*  appName                 = L"YourGame.exe";
const wchar_t*  appFriendlyName         = L"Your Game Casual Name";
const bool      threadedOptimization    = false;


void CheckError(NvAPI_Status status)
{
    if (status == NVAPI_OK)
        return;

    NvAPI_ShortString szDesc = {0};
    NvAPI_GetErrorMessage(status, szDesc);
    printf("NVAPI error: %s\n", szDesc);
    exit(-1);
}


void SetNVUstring(NvAPI_UnicodeString& nvStr, const wchar_t* wcStr)
{
    for (int i = 0; i < NVAPI_UNICODE_STRING_MAX; i++)
        nvStr[i] = 0;

    int i = 0;
    while (wcStr[i] != 0)
    {
        nvStr[i] = wcStr[i];
        i++;
    }
}


int main(int argc, char* argv[])
{
    NvAPI_Status status;
    NvDRSSessionHandle hSession;

    status = NvAPI_Initialize();
    CheckError(status);

    status = NvAPI_DRS_CreateSession(&hSession);
    CheckError(status);

    status = NvAPI_DRS_LoadSettings(hSession);
    CheckError(status);


    // Fill Profile Info
    NVDRS_PROFILE profileInfo;
    profileInfo.version             = NVDRS_PROFILE_VER;
    profileInfo.isPredefined        = 0;
    SetNVUstring(profileInfo.profileName, profileName);

    // Create Profile
    NvDRSProfileHandle hProfile;
    status = NvAPI_DRS_CreateProfile(hSession, &profileInfo, &hProfile);
    CheckError(status);


    // Fill Application Info
    NVDRS_APPLICATION app;
    app.version                     = NVDRS_APPLICATION_VER_V1;
    app.isPredefined                = 0;
    SetNVUstring(app.appName, appName);
    SetNVUstring(app.userFriendlyName, appFriendlyName);
    SetNVUstring(app.launcher, L"");
    SetNVUstring(app.fileInFolder, L"");

    // Create Application
    status = NvAPI_DRS_CreateApplication(hSession, hProfile, &app);
    CheckError(status);


    // Fill Setting Info
    NVDRS_SETTING setting;
    setting.version                 = NVDRS_SETTING_VER;
    setting.settingId               = OGL_THREAD_CONTROL_ID;
    setting.settingType             = NVDRS_DWORD_TYPE;
    setting.settingLocation         = NVDRS_CURRENT_PROFILE_LOCATION;
    setting.isCurrentPredefined     = 0;
    setting.isPredefinedValid       = 0;
    setting.u32CurrentValue         = threadedOptimization ? OGL_THREAD_CONTROL_ENABLE : OGL_THREAD_CONTROL_DISABLE;
    setting.u32PredefinedValue      = threadedOptimization ? OGL_THREAD_CONTROL_ENABLE : OGL_THREAD_CONTROL_DISABLE;

    // Set Setting
    status = NvAPI_DRS_SetSetting(hSession, hProfile, &setting);
    CheckError(status);


    // Apply (or save) our changes to the system
    status = NvAPI_DRS_SaveSettings(hSession);
    CheckError(status);


    printf("Success.\n");

    NvAPI_DRS_DestroySession(hSession);

    return 0;
}

关于c++ - Nvidia 图形驱动程序导致明显的帧卡顿,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36959508/

相关文章:

c# - C#图形矩形剧烈旋转

c++ - 这是将指向对象的指针分配给函数的正确方法吗?

c++ - 使用 C++ 在 Linux 中更改当前目录

c++ - 类型没有命名类型或错误 : field has incomplete type

java - 从多个线程修改 hibernate 实体

.net - Visual Studio 的线程窗口如何识别 "Main Thread'

java - Android——在 OnDrawFrame 方法之外将 GLSurfaceView.Renderer 置于 sleep 状态(如 Thread.sleep(20))

c++ - 我在哪里可以找到 string.cpp 的来源

Python 3 - 托管服务器

java - 输出到屏幕时图像定位不正确