Специфичная для HTC Desire частота кадров OpenGL ES 1 - не получается правильно - PullRequest
2 голосов
/ 14 сентября 2010

Я пытаюсь заставить довольно простую программу openGL ES 1 запускать ровные твердые 60 кадров в секунду на паре устройств, и я застреваю на желании HTC.Сам телефон быстрый, быстрый, мощный и в целом удобный для использования;однако я не могу отобразить что-нибудь в полноэкранном режиме со скоростью 60 кадров в секунду с OpenGL.После долгого застревания с моим приложением я решил создать тестовое приложение с кодом прямо из примера кода из документации.

Вот что я делаю.Простой код инициализации с GLSurfaceView.У меня есть три версии onDrawFrame, все очень просто.Один пуст.Один содержит только glClear.Один содержит достаточно состояния, чтобы нарисовать только полноэкранный квад.Время трассировки до и после.В моей программе нет другого представления, кроме моего GLSurfaceView.Я не могу объяснить, сколько раз я получаю.

Во всех случаях сама функция onDrawFrame всегда заканчивается менее 2 мс.Но очень часто onDrawFrame не вызывается снова до 30 ~ 40 мс, снижая частоту кадров до 30 кадров в секунду или меньше.Я получаю около 50 кадров в секунду с пустым onDrawFrame, 45 с glClear и 35 с четырехугольником.Этот же код работает на скорости 60 кадров в секунду на HTC Magic, на Samsung Galaxy S, на Sharp ISO1.Sony Experia X10 показывает 30 кадров в секунду благодаря своему экрану.Я делал намного более сложные сцены с высокой частотой 60 кадров в секунду на HTC Magic, который на очень слабее по сравнению с Desire.У меня нет Nexus One, пригодного для тестирования.Конечно, я за исключением замены буфера в блоке на пару миллисекунд.Но он все время перепрыгивает через кадры.

Пытаясь выяснить, что делает телефон вне обработчика onDrawFrame, я попытался использовать Debug.startMethodTracing.Нет никакого способа, которым я мог бы заставить трассировку отражать фактическое время, которое телефон проводит вне цикла.В конце onDrawFrame я использую startMethodTracing, затем сохраняю текущее время (SystemClock.uptimeMillis) в переменной.В начале следующего я записываю разницу во времени с момента последнего выхода из функции и stopMethodTracing.Это будет вызываться снова и снова, поэтому я организую остановку, как только получу трассировку для итерации с паузой более 40 мс.Временная шкала на полученной трассировке составляет менее 2 мс, как если бы система тратила 38 мс вне моей программы.

Я много чего пробовал.Перечислите EGL-конфиги и попробуйте их все одно за другим.Чтобы посмотреть, изменилось ли что-нибудь, я переключился на рендер, когда грязная схема запрашивала перерисовку в каждом кадре.Но безрезультатно.Что бы я ни делал, ожидаемый промежуток в 14 ~ 16 мс для замены буферов займет около 30 мс примерно вдвое, и, независимо от того, что я делаю, кажется, что устройство ожидает двух обновлений экрана.PS на устройстве показывает мое приложение на уровне около 10% CPU, а System_server на уровне 35%.Конечно, я также пробовал очевидное, убивая другие процессы, перезагружая устройство ... Я всегда получаю один и тот же точный результат.

У меня нет той же проблемы с рисованием на холсте.

Кто-нибудь знает, почему Desire (и только Desire) ведет себя так?

Для справки, вот как выглядит мой тестовый код:

public class GLTest extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        mGLView = new GLSurfaceView(this);  
        mGLView.setRenderer(new ClearRenderer());  
        setContentView(mGLView);  
    }  

    @Override  
    protected void onPause() {  
        super.onPause();  
        mGLView.onPause();  
    }  

    @Override  
    protected void onResume() {  
        super.onResume();  
        mGLView.onResume();  
    }  

    private GLSurfaceView mGLView;  
}  

class ClearRenderer implements GLSurfaceView.Renderer {  
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {}  
    public void onSurfaceChanged(GL10 gl, int w, int h) { gl.glViewport(0, 0, w, h); }  

    long start;  
    long end;  
    public void onDrawFrame(GL10 gl)  
    {  
    start = System.currentTimeMillis();  
    if (start - end > 20)  
        Log.e("END TO START", Long.toString(start - end));  
    //        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);  
    end = System.currentTimeMillis();  
    if (end - start > 15)  
        Log.e("START TO END", Long.toString(end - start));  
    }  
}  

Ответы [ 2 ]

1 голос
/ 23 декабря 2010

Вы должны посмотреть на это http://www.google.com/events/io/2010/sessions/writing-real-time-games-android.html

Он рекомендует держать частоту кадров на уровне 30 кадров в секунду, а не 60 кадров в секунду.

0 голосов
/ 17 октября 2010

Может быть, у меня есть ответ: драйвер opengl может решить сделать большую часть фактического рендеринга на более позднем этапе.Этот шаг по умолчанию выполняется сразу после onDrawFrame и, по-видимому, является причиной того, что устройство бездействует после выхода из метода.Хорошая новость заключается в том, что вы можете включить этот шаг прямо в ваш onDrawFrame метод: просто вызовите gl.glFinish() - он выполнит окончательный рендеринг и вернется после его завершения.После этого не должно быть простоев.Тем не менее, плохая новость заключается в том, что на самом деле не было времени простоя, поэтому вы не сможете вернуть это время назад (у меня были некоторые иллюзии о том, насколько быстрым был мой рендеринг ... теперь мне приходится сталкиваться с реальной медлительностью моегореализация ;) ).Что вы должны знать о glFinish: Кажется, есть ошибка уровня ОС, которая вызывает взаимные блокировки на некоторых устройствах HTC (например, желание), которая все еще присутствует в 2.2, насколько я понял.Кажется, это происходит, если анимация запускается в течение нескольких часов.Однако в сети существует пропатченная реализация представления поверхности opengl, которую можно использовать, чтобы избежать этой проблемы.К сожалению, сейчас у меня нет ссылки, но вы сможете найти ее через Google (извините за это!).Может быть какой-то способ использовать время, потраченное на glFinish(): это может быть активность gpu для некоторой (всей?) Части, поэтому процессор может свободно выполнять другую обработку.

...