2012-09-01 15 views
8

Ich versuche, meinen Renderer zu profilieren, und sehe ein seltsames Profiling-Verhalten, das ich nicht erklären kann.Warum blockiert GlClear in OpenGLES?

Ich benutze eine glSurfaceView, die ich eingestellt habe, um kontinuierlich zu rendern.

Dies ist, wie mein onDrawFrame()

strukturiert ist
public void onDrawFrame(GL10 unused) { 
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); 
    executeAllDrawCommands(); 
} 

Dies wurde langsam unter geringer Last zu verhalten, so habe ich eine Timer-Klasse und den Autor diese einige profilieren. Ich war ziemlich überrascht von dem, was ich sah.

Ich habe ein paar Sonden auf meine onDrawFrame Methode wie folgt:

public void onDrawFrame(GL10 unused) { 
    swapTimer.end(); 

    clearTimer.start(); 
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); 
    clearTimer.end(); 

    drawTimer.start(); 
    executeAllDrawCommands(); 
    drawTimer.end(); 

    swapTimer.start(); 
} 

clearTimer misst die Zeit, glClear, drawTimer misst die Zeit, alle Anrufe meine Unentschieden zu laufen braucht, um Anruf entgegennimmt, und swapTimer misst die Zeit ab wann onDrawFrame beendet wird und wann es zurückkehrt (die Zeit, die für den Aufruf von eglSwapBuffers benötigt wird).

Wenn ich eine sehr leicht belastet Szene lief, bekam ich ein paar wirklich seltsame Zahlen, die ich nicht erklären kann:

swapTimer : 20ms (average) 
clearTimer : 11ms (average) 
drawTimer : 2ms (average) 

ich die Swap-Zeit erwartet etwas largish zu sein, da ich das Gerät hat Vsync gezwungen glauben Aktivieren Sie bei ~ 30fps, obwohl ich nicht weiß, warum der tatsächliche 'freie' Anruf für 11 Millisekunden blockiert wird? Ich dachte, es sollte nur einen asynchronen Befehl ausgeben und zurückgeben?

Wenn ich eine viel mehr damit beschäftigt Szene zeichnen, die Zahlen etwas ganz ändern:

swapTimer : 2ms (average) 
clearTimer : 0ms (average) 
drawTimer : 44ms (average) 

so viel Zeit, um meine Auslosung Anrufe nehmen In dieser Szene, dass es wie sein sieht viel von der VSYNC-Periode versteckt , und der Block des Anrufs verschwindet vollständig.

Gibt es eine Erklärung dafür, warum glClear auf meiner leicht belasteten Szene blockiert?

Link zu meinem 'Timer' Klasse Quellcode, falls jemand verdächtig ist meine Messtechnik: http://pastebin.com/bhXt368W

+0

Könnten Sie versuchen, GLES20.glFinish() vor der Methode clearTimer.start() aufzurufen und zu sehen, wie sich die Zeit dann ändert? –

+0

Ich habe eine 'glFinish' (und finishTimer.start()/end()), und es dauert die ganze Zeit weg von GlClear. Statt dessen benötigt glFinish nun einige Millisekunden und glClear wird sofort. Es sieht so aus, als ob dies alles mit vsync zusammenhängt, obwohl ich überrascht war, dass vsync-Zeit innerhalb von glClear erscheint. – Tim

Antwort

10

Ich habe eine glFinish (und finishTimer.start()/end() um ihn herum), und es dauert die ganze Zeit von GlClear. Statt dessen benötigt glFinish nun einige Millisekunden und glClear wird sofort.

Das erklärt es.

Wenn Ihre Szene sehr hell ist und die Zeichnungen sehr schnell gerendert werden, dauert es einige Zeit, die Pixel mit der neuen Farbe zu löschen und zu füllen (es wird immer Zeit brauchen, da sonst der Renderer zurückliegt und aktuell gezeichnet wird) Neue Sachen). Die neueren Android-Geräte haben Füllgrenzen. Zum Beispiel hat Nexus One eine Füllstandssperre bei 30 Hz - der Bildschirm wird bei dieser Frequenz synchronisiert, egal wie schnell Ihre tatsächlichen Zeichnungen sind. Wenn die Zeichnungen unter 30 Hz enden, wird der Renderer mit dem Bildschirm synchronisiert. Aus diesem Grund bemerken Sie diese Verzögerung, die Sie bemerken sollten, auch wenn Sie den Anruf glClear() entfernen. Der Renderer ist vor und schneller als die Bildschirmaktualisierungen.

Wenn der Renderer viele Objekte zu zeichnen hat, wird die Synchronisierung angehalten (angesichts der Profildaten Ihrer belegten Szene), da der Renderer jetzt nach den Bildschirmaktualisierungen ist.

Wenn Sie glFinish(), entfernt es die Zeit, die glClear() Funktion sonst verursachen würde, die durch die Füllrate Logik folgt, bedeutet, dass glFinish() ist jetzt die Funktion, die Synchronisation mit dem Bildschirm zu gewährleisten.

Calculations:

F = 1/T

Einfache Szene:

F = 1/T = 1/((20 + 11 + 2) * 10^- 3) = ~ 30 Hz

Die Verzögerungszeit der Synchronisierung wird in Ihrem Profiler angezeigt. Der Renderer wird mit dem Bildschirm synchronisiert. Das heißt, wenn Sie den glClear() oder den glFinish() Anruf entfernen, wird die Verzögerung woanders angezeigt.

Schwer Szene:

F = 1/T = 1/((2 + 0 + 44) * 10^-3)) = ~ 22 Hz

Die Verzögerungszeit Synchronisation nicht erscheinen in Ihrem Profiler. Renderer ist nach der Aktualisierungsfrequenz des Bildschirms.

es so scheint, ist alles

vsync Zusammenhang Das ist richtig zu sein scheint.

Verwandte Themen