Рисовать из отдельной темы с NSOpenGLLayer - PullRequest
3 голосов
/ 25 февраля 2012

Я работаю над приложением, которое должно рисовать с помощью OpengGL с частотой обновления, по крайней мере равной частоте обновления монитора. И мне нужно выполнить рисунок в отдельном потоке, чтобы рисунок никогда не блокировался интенсивными действиями пользовательского интерфейса.

На самом деле я использую NSOpenGLView в сочетании с CVDisplayLink и могу без проблем набрать 60-80FPS.

Поскольку мне нужно также отобразить некоторые элементы управления какао поверх этого представления, я попытался создать подкласс NSOpenGLView и сделать его слоистым, следуя примеру LayerBackedOpenGLView Apple.

Результат неудовлетворительный, и у меня много артефактов.

Поэтому я решил проблему, используя отдельный 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 Ответ

4 голосов
/ 11 июля 2012

Да, это возможно, хотя и не рекомендуется. Вызовите display на слое из вашей CVDisplayLink. Это приведет к вызову canDrawInContext:..., и если он вернет YES, будет вызван drawInContext:..., и все это в любом потоке с именем display. Чтобы сделать отображаемое изображение видимым на экране, вы должны позвонить [CATransaction flush]. Этот метод был предложен в списке рассылки Apple, хотя он не является полностью беспроблемным (метод отображения другого представления также может вызываться в фоновом потоке, и не все представления поддерживают рендеринг из фонового потока).

Рекомендованный способ - сделать слой асинхронным и отобразить контекст OpenGL в основном потоке. Если вы не можете достичь хорошей частоты кадров таким образом, так как ваш основной поток занят в другом месте, рекомендуется переместить все остальное (в значительной степени всю логику вашего приложения) в другие потоки (например, с помощью Grand Central Dispatch) и сохранять только пользовательский ввод и рисование кода в основном потоке. Если ваше окно очень большое, вы все равно можете не получить ничего лучше, чем 30 FPS (один кадр на два обновления экрана), но это связано с тем фактом, что композиция CALayer кажется довольно дорогим процессом, и он был оптимизирован для более или менее статические слои (например, слои, содержащие изображение), а не слои, обновляющие себя 60 FPS.

например. если вы пишете 3D-игру, советуем вам вообще не смешивать CALayers с контентом OpenGL. Если вам нужны элементы пользовательского интерфейса Cocoa, либо отделите их от содержимого OpenGL (например, разделите окно по горизонтали на часть, которая отображает только OpenGL, и часть, которая отображает только элементы управления), либо нарисуйте все элементы управления самостоятельно (что довольно часто встречается в играх).

И последнее, но не менее важное: подход с двумя окнами не так экзотичен, как вы можете подумать, именно так VLC (видеопроигрыватель) рисует свои элементы управления видеоизображением (которое также отображается в OpenGL на Mac).

...