Поддержка слоя NSOpenGLView + таймер анимации = странное поведение при рисовании? - PullRequest
0 голосов
/ 18 декабря 2011

Я создаю приложение, которое подклассов NSOpenGLView, чтобы сделать некоторые рисунки OpenGL. Теперь я хотел добавить элемент управления наложением, подобный QuickTime X. Сначала я попытался установить значение NSOpenGLCPSurfaceOrder в -1 и сделать мое окно не непрозрачным. Это сработало, но я потерял тень от окон, так что это нереальное решение.

Затем я создал слой подкласса NSOpenGLView, вызвав [setWantsLayer:YES] и добавив свой блок управления в качестве подпредставления. Это сработало, но я заметил большое падение производительности. Я провел некоторое исследование и нашел это:

Я использую объект NSTimer для вызова метода [timerFired:] 60 раз в секунду. Работает отлично. Единственное, что я делаю в этом методе, - это вызов [self setNeedsDisplay:YES], потому что при использовании OpenGLView с поддержкой слоя необходимо перегрузить метод [drawRect:rect] и выполнить там весь рисунок OpenGL. Проблема: [drawRect:rect] часто вызывается, хотя таймер не срабатывает.

Сначала я подумал: "Конечно, это так, он рисует NSOpenGLView, поэтому он может вызываться оконным менеджером или что-то в этом роде". Поэтому удалил мой объект таймера, чтобы определить, как он вызывался между [timerFired:] вызовами. Результат: он вообще не вызывался, по крайней мере, если не изменять размер или перетаскивать окно.

Итак, затем я экспериментировал с интервалом времени моих таймеров. Оказывается, до 55 раз в секунду [drawRect:rect] вызывается от 60 до 70 раз в секунду, а с интервалом таймера 59 раз в секунду [drawRect:rect] вызывается от 100 до 120 раз в секунду.

Я подозреваю, что этот крайне непредсказуемый способ, которым вызывается мой рисунок, приводит к снижению производительности, либо из-за неравномерности, либо из-за засорения потока большим количеством рисунков OpenGL и нехваткой времени для выполнения или чего-то еще. Я также читал, что слоистые OpenGLViews не работают с vsync, хотя я не могу это подтвердить.

У кого-нибудь есть объяснение? У кого-нибудь есть идеи о том, как рисовать мой OpenGL только при пожарах по таймеру?

Я уже попробовал наивный подход и добавил логическую переменную, установил значение true в моем [timerFired:] и заставил [drawRect:rect] вызывать метод рисования OpenGL, только если переменная равна true. В результате получилась чрезвычайно мерцающая и заикающаяся анимация, поэтому не повезло.

А как насчет использования CAOpenGLLayer с асинхронной анимацией или CVDisplayLink? Может ли помочь?

edit еще одна вещь, которая может быть полезной информацией: я уже использовал [setNeedsDisplay:YES] без моего представления с поддержкой слоев, так что я мог легко переключаться между слоями и без слоев, и я У меня не было никаких проблем, описанных выше, так что это определенно связано с тем, что мой взгляд поддерживается на слое. Все становится беспорядок, просто позвонив [setWantsLayer:YES].

1 Ответ

0 голосов
/ 21 декабря 2011

Итак, я заменил свой объект NSTimer на CVDisplayLink, и все снова стало гладким.Хотя на самом деле я не понимаю, почему.Кажется, что запрос на резервный слой нарушил вертикальную синхронизацию, но он не объясняет случайные вызовы drawRect, которые появились из ниоткуда.

Также мне бы очень хотелось, чтобы vsync работал с NSOpenGLView, поддерживаемым слоеми / или с CAOpenGLLayer.Я не могу найти официальную информацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...