Рисовать из отдельной темы с 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).

Другие вопросы по тегам