2013-03-13 2 views
2

Я делаю простое графическое приложение на OSX. Я только начал контролировать частоту кадров, проверив разницу в системном времени между кадрами. Кажется, он висит немного каждые несколько кадров.Почему двойная буферизация OpenGL кажется непоследовательной по производительности?

Приложение работает на объекте NSTimer, в настоящее время установленном на 200 кадров в секунду (5 мс кадров). Чтобы убедиться, что не только мой основной код работает медленно, я прокомментировал весь основной цикл, за исключением [self.context flushBuffer]; (и, конечно, код выборки частоты кадров). Даже повторение этого единственного вызова заставляет его зависать в течение нескольких кадров за раз. Вот пример моего консольного вывода:

4 
5 
6 
10 
5 
5 
5 
4 
6 
10 
5 
5 
5 
5 
5 
5 
20 
4 
5 
6 
20 
5 
5 
5 

Это время в миллисекундах между каждой итерацией цикла. При скорости 200 кадров в секунду он должен составлять около 5 мс для каждого кадра, но он несколько раз висит на 10, 15 или даже 20 мс. Vsyncing отключен, как вы можете видеть в моей функции -initOpenGL.

-(void)initOpenGL{ 
    NSOpenGLPixelFormatAttribute attributes[] = {NSOpenGLPFADoubleBuffer, 0}; 
    NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes: attributes]; 
    self.context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil]; 
    [self.context setView:[self.window contentView]]; 
    [self.context makeCurrentContext]; 

    //Disable Vsync 
    int temp = 0; 
    [self.context setValues: &temp forParameter: NSOpenGLCPSwapInterval]; 

    glViewport(0, 0, windowWidth, windowHeight); 
    glMatrixMode(GL_PROJECTION); 
    glOrtho(0, windowWidth, 0, windowHeight, -1, 100); 

    //Flip all textures right side up 
    glMatrixMode(GL_TEXTURE); 
    glLoadIdentity(); 
    glScalef(1.0f, -1.0f, 1.0f); 

    glMatrixMode(GL_MODELVIEW); 

    glEnable(GL_SCISSOR_TEST); 
    glEnable(GL_BLEND); 
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
    } 

Edit, новая информация: Я могу подтвердить, что это что-то делать с двойной буферизацией против сингла. Когда я инициализирую NSOpenGLPixelFormat без атрибута DoubleBuffer, он отлично работает со скоростью 200 кадров в секунду. Принимая во внимание, что с этим атрибутом я продолжаю заикаться.

ответ

5

Не зная фактического кода рендеринга (который не был отправлен), одна из возможных причин заключается в том, что использование функции управления частотой кадров в NSTimer в первую очередь не является такой замечательной идеей. Обратитесь к документации (курсив):

Таймер является не в режиме реального времени механизм; он срабатывает только тогда, когда работает один из режимов цикла запуска, к которому был добавлен таймер, и он может проверить, прошло ли время срабатывания таймера. Из-за различных источников входного сигнала управляется типичный цикл запуска, эффективное разрешение временного интервала для таймера ограничено порядком 50-100 миллисекунд.

Таким образом, ожидание использования таймера для чего-то вроде 5 миллисекунд в корне ошибочно.

В дополнение к этому могут быть другие эффекты (планирование процесса, загрузка текстур и киосков в OpenGL и т. Д.), Которые сделают время кадра не постоянным на 100%. Хотя вызванный ими дрожание обычно будет в гораздо меньших масштабах.

+1

Спасибо, что ответили! Мне всегда казалось, что NSTimer является стандартом для управления частотой кадров на устройствах Apple; он, кажется, используется чаще, чем что-либо еще. Что было бы лучшей альтернативой? Кроме того, я опустил код рендеринга, потому что он, похоже, не имеет отношения к проблеме. Как я уже сказал, это происходит, даже когда все прокомментировано, и я буквально называю [context flushBuffer] ;. Поэтому представляется логичным, что мы можем исключить что-либо в моем коде (если я неправильно выполнил что-то в OpenGL). –

+0

Я также немного сузил его немного; прочитайте редактирование на OP. –

+1

Стандарт для управления частотой кадров на Apple, а также любая другая платформа, которую я знаю, это включить v-sync.Таймеры (или, что еще хуже, сон) не являются и никогда не были «стандартными» из-за их довольно непредсказуемого не-реального времени (в операционных системах, отличных от RT, например, OSX). Кроме того, использование таймера неразумно, потому что два разных часовых пояса (таймер приложения и v-sync) в конечном итоге всегда будут выходить из синхронизации (думаю, загорается индикатор на двух автомобилях!). Я не могу сказать, почему отключение двойной буферизации, похоже, «работает» лучше, но это не меняет того факта, что подход является ошибочным. – Damon

2

Если вам нужна хорошая синхронизация на OSX, вы должны использовать CoreVideo DisplayLink. Это обратный вызов, вызываемый при каждом обновлении по вертикали экрана, поэтому, если ваш экран имеет значение 60 FPS, этот обратный вызов будет вызван (в отдельном потоке, будьте осторожны с потоковой обработкой OpenGL) 60 раз в секунду, и именно это должно вызвать обновление OpenGL ,

Смежные вопросы