Я создаю приложение, которое подклассов 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]
.