2016-04-30 7 views
29

Ok Ich habe dieses Problem für ein paar Tage jetzt untersucht, so lassen Sie mich gehen, was ich wissen bisher, was mich zu glauben, dass dies ein Problem mit NVidia Treiber und nicht sein könnte mein Code.Nvidia Grafiktreiber verursacht merkliche Frame Stottern

Grundsätzlich beginnt mein Spiel nach ein paar Sekunden zu stottern (zufällige Bilder nehmen 70ms anstelle von 16ms, auf einem regelmäßigen Muster). Dies geschieht NUR, wenn im Nvidia Control Panel (neueste Treiber, Windows 10) eine Einstellung namens "Threaded Optimization" aktiviert ist. Leider ist diese Einstellung standardmäßig aktiviert und ich möchte lieber nicht, dass die Benutzer ihre Einstellungen ändern müssen, um eine angenehme Erfahrung zu machen.

  • Das Spiel ist nicht CPU oder GPU intensiv (2ms ein Frame ohne VSync an). Es ruft keine openGL-Funktionen auf, die Daten synchronisieren müssen, und es streamt keine Puffer oder liest Daten von der GPU oder irgendetwas zurück. Über den einfachsten möglichen Renderer.

  • Das Problem war immer da, es fing erst an bemerkbar zu werden, wenn ich fmod für Audio hinzufügte. fmod ist nicht die Ursache dafür (mehr später in der Post)

  • Der Versuch, das Problem mit NVidia Nsight zu debuggen, machte das Problem weg. "Start Collecting Data" bewirkt, dass das Stottern sofort verschwindet. Kein Würfel hier.

  • Im Profiler wird viel CPU-Zeit in "nvoglv32.dll" verbracht. Dieser Prozess wird nur generiert, wenn die Threading-Optimierung aktiviert ist. Ich vermute, dass es ein Synchronisationsproblem ist, also debugge ich mit Visual Studio Concurrency Viewer.

  • A-HA! vsyncs

  • diese Blöcke der CPU-Zeit auf dem nvidia Thread Untersuchung, die früheste benannte Funktion, die ich in ihrer Aufrufliste bekommen ist „CreateToolhelp32Snapshot“, gefolgt von viel Zeit in Thread32Next verbracht. Ich habe Thread32Next im Profiler gesehen, als ich mir die CPU-Zeiten früher angesehen habe, also scheint es, als wäre ich auf dem richtigen Weg.

  • Es sieht also so aus, als würde der nvidia-Treiber aus irgendeinem Grund einen Schnappschuss des gesamten Prozesses aufnehmen? Was könnte der Grund sein, warum tut es das, und wie halte ich es an?

  • Auch dies erklärt, warum das Problem begann, bemerkbar zu werden, sobald ich in fmod hinzugefügt, weil es Informationen für alle Prozesse Threads greift, und fmod erzeugt viele Threads.

  • Irgendwelche Hilfe? Ist das nur ein Fehler in Nvidias Treiber oder gibt es etwas, was ich tun kann, um es zu reparieren, andere Leute zu sagen, Threads "Optimierung" zu deaktivieren?

  • bearbeiten 1: Das gleiche Problem tritt auch mit aktuellen nvidia-Treibern auf meinem Laptop auf. So bin ich nicht verrückt

    bearbeiten 2: das gleiche Problem tritt auf Version 362 (iV Hauptversion) von Nvidias Treiber

    +0

    Hey, Tyler. :) Aus Neugier - haben Sie einige Debug-Treiber installiert oder so? Ich kann nicht für das Leben von mir erraten, warum ein Graphiktreiber diese Art von Informationen ergreifen sollte, es sei denn, es ist für irgendeine Art von Debugging/Logging Gründen. –

    +0

    nein. Sie sind die öffentlich verfügbaren Treiber von Nvidias Website. Ich bin nicht einmal sicher, wo ich einen Debug-Modus-Treiber bekommen würde ... – TylerGlaiel

    +0

    auch sollte ich erwähnen, ich habe es auch selbst ohne Visual Studio ausgeführt, nur für den Fall, dass Visual Studio Debug-Code injiziert ... gleich Ausgabe – TylerGlaiel

    Antwort

    0

    Hass, das Offensichtliche zu erklären, aber ich fühle mich wie es gesagt werden muss.

    Die Optimierung von Threads ist dafür bekannt, in vielen Spielen Stottern zu verursachen, sogar bei denen, die Multithreading nutzen.Wenn Ihre Anwendung nicht gut mit der Einstellung für die Thread-Optimierung funktioniert, besteht die einzige logische Antwort darin, Ihren Benutzern zu sagen, dass sie sie deaktivieren müssen. Wenn Benutzer stur sind und das nicht wollen, ist das ihre Schuld.

    Der einzige Fehler in der aktuellen Erinnerung, den ich mir vorstellen kann, ist, dass ältere Versionen des Nvidia-Treibers Anwendungen mit Thread-Optimierung in Wine zum Absturz gebracht haben, aber das hat nichts mit dem Stottern zu tun, das Sie beschreiben.

    +0

    Wenn es nicht etwas ist, das Nvidia reparieren will (Ich habe die Windows-Funktion genagelt, was das Stottern verursacht, denke ich), werde ich einfach zu directx wechseln, wo es nicht so aussieht, als sei das Problem vorhanden. – TylerGlaiel

    +0

    "Das ist ihre Schuld"?! Nein, wenn Ihre Anwendung nicht funktioniert, ist es Ihre Schuld. – Calvin1602

    6

    ... oder gibt es etwas ich tun kann, um es zu beheben andere Leute sagen, Threaded „Optimierung“ zu deaktivieren?

    Ja.

    Sie können ein benutzerdefiniertes "Anwendungsprofil" für Ihr Spiel erstellen, indem Sie NVAPI verwenden und die Einstellung "Threaded Optimization" darin deaktivieren.

    Es gibt eine .PDF file auf der NVIDIA-Website mit einigen Hilfe- und Codebeispielen zur NVAPI-Nutzung.

    Um alle Ihre NVIDIA-Profile zu sehen und zu verwalten, empfehle ich die Verwendung von NVIDIA Inspector. Es ist bequemer als die Standard-NVIDIA-Systemsteuerung.

    Auch hier ist mein Codebeispiel, das „Application Profile“ mit „Threaded-Optimierung“ disabled: Zuerst würde auf diesem Vorschlag auf der Grundlage

    #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; 
    } 
    
    +0

    danke für den Code, wahrscheinlich wird am Ende zu verwenden, wenn Nvidia es nicht bis zum Zeitpunkt meines Spiels behoben – TylerGlaiel

    +0

    Beachten Sie, dass Profile vom Treiber beim Start der Anwendung (von seinem Namen) geladen werden, so dass Sie brauchen um es neu zu starten, damit Ihr benutzerdefiniertes Profil wirksam wird. Dies im Installationsprogramm zu tun ist wahrscheinlich am besten. – Calvin1602

    1

    Dank für subGlitch Antwort, ich mache nur einen sichereren ein, das würde es Ihnen ermöglichen, die Thread-Optimierung zwischenzuspeichern und zu ändern und sie anschließend wiederherzustellen.

    -Code ist wie unten:

    #include <stdlib.h> 
    #include <stdio.h> 
    #include <nvapi.h> 
    #include <NvApiDriverSettings.h> 
    
    enum NvThreadOptimization { 
        NV_THREAD_OPTIMIZATION_AUTO   = 0, 
        NV_THREAD_OPTIMIZATION_ENABLE  = 1, 
        NV_THREAD_OPTIMIZATION_DISABLE  = 2, 
        NV_THREAD_OPTIMIZATION_NO_SUPPORT = 3 
    }; 
    
    bool NvAPI_OK_Verify(NvAPI_Status status) 
    { 
        if (status == NVAPI_OK) 
         return true; 
    
        NvAPI_ShortString szDesc = {0}; 
        NvAPI_GetErrorMessage(status, szDesc); 
    
        char szResult[255]; 
        sprintf(szResult, "NVAPI error: %s\n\0", szDesc); 
        printf(szResult); 
    
        return false; 
    } 
    
    NvThreadOptimization GetNVidiaThreadOptimization() 
    { 
        NvAPI_Status status; 
        NvDRSSessionHandle hSession; 
        NvThreadOptimization threadOptimization = NV_THREAD_OPTIMIZATION_NO_SUPPORT; 
    
        status = NvAPI_Initialize(); 
        if(!NvAPI_OK_Verify(status)) 
         return threadOptimization; 
    
        status = NvAPI_DRS_CreateSession(&hSession); 
        if(!NvAPI_OK_Verify(status)) 
         return threadOptimization; 
    
        status = NvAPI_DRS_LoadSettings(hSession); 
        if(!NvAPI_OK_Verify(status)) 
        { 
         NvAPI_DRS_DestroySession(hSession); 
         return threadOptimization;; 
        } 
    
    
        NvDRSProfileHandle hProfile; 
        status = NvAPI_DRS_GetBaseProfile(hSession, &hProfile); 
        if(!NvAPI_OK_Verify(status)) 
        { 
         NvAPI_DRS_DestroySession(hSession); 
         return threadOptimization;; 
        } 
    
        NVDRS_SETTING originalSetting; 
        originalSetting.version = NVDRS_SETTING_VER; 
        status = NvAPI_DRS_GetSetting(hSession, hProfile, OGL_THREAD_CONTROL_ID, &originalSetting); 
        if(NvAPI_OK_Verify(status)) 
        { 
         threadOptimization = (NvThreadOptimization)originalSetting.u32CurrentValue; 
        } 
    
        NvAPI_DRS_DestroySession(hSession); 
    
        return threadOptimization; 
    } 
    
    void SetNVidiaThreadOptimization(NvThreadOptimization threadedOptimization) 
    { 
        NvAPI_Status status; 
        NvDRSSessionHandle hSession; 
    
        if(threadedOptimization == NV_THREAD_OPTIMIZATION_NO_SUPPORT) 
         return; 
    
        status = NvAPI_Initialize(); 
        if(!NvAPI_OK_Verify(status)) 
         return; 
    
        status = NvAPI_DRS_CreateSession(&hSession); 
        if(!NvAPI_OK_Verify(status)) 
         return; 
    
        status = NvAPI_DRS_LoadSettings(hSession); 
        if(!NvAPI_OK_Verify(status)) 
        { 
         NvAPI_DRS_DestroySession(hSession); 
         return; 
        } 
    
        NvDRSProfileHandle hProfile; 
        status = NvAPI_DRS_GetBaseProfile(hSession, &hProfile); 
        if(!NvAPI_OK_Verify(status)) 
        { 
         NvAPI_DRS_DestroySession(hSession); 
         return; 
        } 
    
        NVDRS_SETTING setting; 
        setting.version     = NVDRS_SETTING_VER; 
        setting.settingId    = OGL_THREAD_CONTROL_ID; 
        setting.settingType    = NVDRS_DWORD_TYPE; 
        setting.u32CurrentValue   = (EValues_OGL_THREAD_CONTROL)threadedOptimization; 
    
        status = NvAPI_DRS_SetSetting(hSession, hProfile, &setting); 
        if(!NvAPI_OK_Verify(status)) 
        { 
         NvAPI_DRS_DestroySession(hSession); 
         return; 
        } 
    
        status = NvAPI_DRS_SaveSettings(hSession); 
        NvAPI_OK_Verify(status); 
    
        NvAPI_DRS_DestroySession(hSession); 
    } 
    

    Basierend auf den beiden Schnittstellen (Get/Set) oben, Sie auch die ursprüngliche Einstellung speichern können und es wieder, wenn die Anwendung beendet wird. Das bedeutet, dass Ihre Einstellung zum Deaktivieren der Thread-Optimierung nur Auswirkungen auf Ihre eigene Anwendung hat.

    static NvThreadOptimization s_OriginalNVidiaThreadOptimization = NV_THREAD_OPTIMIZATION_NO_SUPPORT; 
    
    // Set 
    s_OriginalNVidiaThreadOptimization = GetNVidiaThreadOptimization(); 
    if( s_OriginalNVidiaThreadOptimization != NV_THREAD_OPTIMIZATION_NO_SUPPORT 
        && s_OriginalNVidiaThreadOptimization != NV_THREAD_OPTIMIZATION_DISABLE) 
    { 
        SetNVidiaThreadOptimization(NV_THREAD_OPTIMIZATION_DISABLE); 
    } 
    
    //Restore 
    if( s_OriginalNVidiaThreadOptimization != NV_THREAD_OPTIMIZATION_NO_SUPPORT 
        && s_OriginalNVidiaThreadOptimization != NV_THREAD_OPTIMIZATION_DISABLE) 
    { 
        SetNVidiaThreadOptimization(s_OriginalNVidiaThreadOptimization); 
    };