Nvidia图形驱动程序导致明显的框架口吃

Tyl*_*iel 30 c++ graphics multithreading synchronization nvidia

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

基本上我的游戏在运行几秒后开始出现口吃(随机帧需要70ms而不是16ms,在规则模式上).仅当在Nvidia控制面板中启用了"线程优化"设置(最新驱动程序,Windows 10)时才会发生这种情况.不幸的是,此设置默认启用,我宁愿不必让人们调整他们的设置以获得愉快的体验.

  • 游戏不是CPU或GPU密集型(没有vsync的帧为2ms).它没有调用任何需要同步数据的openGL函数,也没有流式传输任何缓冲区或从GPU或其他任何东西读取数据.关于最简单的渲染器.

  • 问题始终存在,当我在fmod中添加音频时,它才开始变得明显.fmod不是这个的原因(更多在后期)

  • 尝试使用NVidia Nsight调试问题使问题消失."开始收集数据"立即导致口吃消失.这里没有骰子.

  • 在Profiler中,"nvoglv32.dll"花费了大量的cpu时间.如果启用了线程优化,则此过程仅生成.我怀疑这是一个同步问题,因此我使用visual studio Concurrency Viewer进行调试.

  • A-HA! vsyncs

  • 调查nvidia线程上的这些CPU时间块,我可以在其callstack中获得的最早命名函数是" CreateToolhelp32Snapshot ",然后在Thread32Next中花费了大量时间.我在早期查看CPU时间时发现了分析器中的Thread32Next,所以这看起来好像我在正确的轨道上.

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

  • 这也解释了为什么一旦我在fmod中添加问题就开始变得明显,因为它抓取了所有进程线程的信息,而fmod产生了很多线程.

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

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

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

sub*_*tch 6

...或者我可以做些什么来修复它,告诉人们禁用线程"优化"?

是.

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

NVIDIA网站上有一个.PDF文件,其中包含一些有关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;
}
Run Code Online (Sandbox Code Playgroud)


小智 1

不想说显而易见的事情,但我觉得有必要说一下。

线程优化因在许多游戏中导致卡顿而臭名昭著,甚至是那些利用多线程的游戏。除非您的应用程序与线程优化设置配合良好,否则唯一合乎逻辑的答案是告诉您的用户禁用它。如果用户固执地不想这样做,那是他们的错。

我最近能想到的唯一错误是旧版本的 nvidia 驱动程序导致在 Wine 中运行的带有线程优化的应用程序崩溃,但这与您描述的口吃问题无关。