Рисовать из отдельной темы с NSOpenGLLayer
Я работаю над приложением, которое должно рисовать с OpengGL с частотой обновления, по крайней мере равной частоте обновления монитора. И мне нужно выполнить рисунок в отдельном потоке, чтобы рисунок никогда не блокировался интенсивными действиями пользовательского интерфейса.
На самом деле я использую NSOpenGLView
в комбинации с CVDisplayLink
и я могу достичь 60-80FPS без каких-либо проблем.
Так как мне нужно также отобразить некоторые элементы управления какао поверх этого представления, я попытался создать подкласс NSOpenGLView
и сделайте его слоями, следуя примеру Apple LayerBackedOpenGLView.
Результат неудовлетворительный, и я получаю много артефактов.
Поэтому я решил проблему с помощью отдельного NSWindow
разместить элементы управления какао и добавив это окно в качестве дочернего окна главного окна, содержащего NSOpenGLView
, Он отлично работает, и я могу получить тот же FPS, что и первоначальная реализация.
Поскольку я рассматриваю это решение как грязный взлом, я ищу альтернативный и более чистый способ достижения того, что мне нужно.
Несколько дней назад я наткнулся NSOpenGLLayer
и я подумал, что это может быть использовано в качестве жизнеспособного решения моей проблемы.
Итак, наконец, после всей этой преамбулы, возникает вопрос: можно ли NSOpenGLLayer
из отдельного потока, используя CVDisplayLink
Перезвоните?.
До сих пор я пытался реализовать это, но я не могу извлечь из CVDisplayLink
Перезвоните. я могу только -setNeedsDisplay:TRUE
на NSOpenGLLayer
от CVDisplayLink
обратный вызов, а затем выполнить рисование в -drawInOpenGLContext:pixelFormat:forLayerTime:displayTime:
когда он автоматически вызывается какао. Но я полагаю, что так я рисую из основного потока, не так ли?
После поиска в Google я даже нашел этот пост, в котором пользователь утверждает, что под рисунком Lion может происходить только внутри -drawInOpenGLContext:pixelFormat:forLayerTime:displayTime:
,
Я сейчас на Snow Leopard, но приложение должно работать без сбоев даже на Lion.
Я что-то пропустил?
1 ответ
Да, это возможно, хотя и не рекомендуется. Вызов display
на слое из вашего CVDisplayLink. Это приведет к canDrawInContext:...
быть вызванным и если он вернет ДА, drawInContext:...
будет вызываться и все это на что-нить называется display
, Чтобы сделать отображаемое изображение видимым на экране, вы должны позвонить [CATransaction flush]
, Этот метод был предложен в списке рассылки Apple, хотя он не является полностью беспроблемным (метод отображения другого представления также может вызываться в фоновом потоке, и не все представления поддерживают рендеринг из фонового потока).
Рекомендуемый способ - сделать слой асинхронным и визуализировать контекст OpenGL в главном потоке. Если вы не можете достичь хорошей частоты кадров таким образом, так как ваш основной поток занят в другом месте, рекомендуется переместить все остальное (в значительной степени всю логику вашего приложения) в другие потоки (например, с помощью Grand Central Dispatch) и сохранять только пользовательский ввод и рисование кода в основном потоке. Если ваше окно очень большое, вы все равно не получите ничего лучше, чем 30 кадров в секунду (один кадр на два обновления экрана), но это связано с тем фактом, что композиция CALayer кажется довольно дорогим процессом, и он был оптимизирован для более или менее статические слои (например, слои, содержащие изображение), а не для слоев, обновляющих себя 60 FPS.
Например, если вы пишете 3D-игру, советуем вам вообще не смешивать CALayers с контентом OpenGL. Если вам нужны элементы пользовательского интерфейса Какао, либо отделите их от содержимого OpenGL (например, разделите окно по горизонтали на часть, которая отображает только OpenGL, и часть, которая отображает только элементы управления), либо нарисуйте все элементы управления самостоятельно (что довольно часто встречается в играх).
И последнее, но не менее важное: подход с двумя окнами не так экзотичен, как вы можете подумать, именно так VLC (видеоплеер) рисует свои элементы управления видеоизображением (которое также отображается в OpenGL на Mac).