2017-12-07 3 views
6

Ich schreibe ein Programm, das extrem niedrige Latenz Textur zum Bildschirm Streaming (unter 10ms) erfordert, habe ich dies mit GL_ARB_buffer_storage, die gut funktioniert für das Streaming und vsync zu verhindern, dass reißen funktioniert.Verhindern OpenGL von Pufferrahmen

Allerdings habe ich entdeckt, dass die NVidia-Pipeline von 2 bis 8 Frames puffern wird, wenn sie Swap-Puffer aufrufen, bevor sie blockiert, muss ich dies verhindern.

Was ich getan habe ist folgendes:

uint64_t detectPresentTime() 
{ 
    // warm up first as the GPU driver may have multiple buffers 
    for(int i = 0; i < 10; ++i) 
    glxSwapBuffers(state.renderer); 

    // time 10 iterations and compute the average 
    const uint64_t start = microtime(); 
    for(int i = 0; i < 10; ++i) 
    glxSwapBuffers(state.renderer); 
    const uint64_t t = (microtime() - start)/10; 

    // ensure all buffers are flushed 
    glFinish(); 

    DEBUG_INFO("detected: %lu (%f Hz)", t, 1000000.0f/t); 
    return t; 
} 

Dann in der Zugfaden ich folgendes tun:

uint64_t presentTime = detectPresentTime(); 
if (presentTime > 1000) 
    presentTime -= 1000; 

while(running) 
{ 
    const uint64_t start = microtime(); 
    glClear(); 

    // copy the texture to the screen 

    glxSwapBuffers(); 

    const uint64_t delta = microtime() - start; 
    if (delta < presentTime) 
    { 
    glFlush(); 
    usleep(delta); 
    glFinish(); 
    } 
} 

Diese Lösung funktioniert auf NVidia Hardware, sondern wird berichtet, dass kein berechnen richtige Gegenwart auf AMD GPUs.

Gibt es einen besseren Weg, dies zu tun? Ich weiß, dass glFinish normalerweise nicht in einer Anwendung mit Ausnahme von Profiling verwendet werden sollte, aber ich kann keinen anderen Weg finden, um sicherzustellen, dass die GPU-Pipeline Frames nicht puffert.

Edit: Für diejenigen, die dies interessiert effektiv emuliert FastSync unter Linux, aber ohne Vsync zu deaktivieren.

Edit2: Vielleicht ist die gegenwärtige Zeit Funktion sollte etwas anders implementiert werden:

uint64_t detectPresentTime() 
{ 
    glFinish(); 

    // time 10 iterations and compute the average 
    const uint64_t start = microtime(); 
    for(int i = 0; i < 10; ++i) 
    { 
    glxSwapBuffers(state.renderer); 
    glFinish(); 
    } 
    const uint64_t t = (microtime() - start)/10; 

    DEBUG_INFO("detected: %lu (%f Hz)", t, 1000000.0f/t); 
    return t; 
} 
+0

Die OpenGL Wiki einen interessanten Artikel über diese hat: https://www.khronos.org/opengl/wiki/Swap_Interval – bernie

Antwort

2

ich die Antwort gefunden, gibt es eine wenig bekannte OpenGL-Erweiterung ist SGI_video_sync genannt, dies unter Verwendung es möglich ist, für die nächste warten Rahmen.

dh:

glFlush(); 
uint remainder; 
glXWaitVideoSyncSGI(1, 0, &remainder);