Sprite Kit серьезная проблема FPS в полноэкранном режиме на OS X

Я делаю довольно сложную игру sprite kit. Недавно я добавил поддержку OS X. Я всегда получаю 60 fps, независимо от того, как масштабируется моя игра при изменении размера окна (даже при изменении размера на максимальное пространство экрана). Однако в тот момент, когда я заставляю свое приложение войти в "полный экран", fps падает до 30-40 fps и остается таким? Но если я возьму курсор мыши и открою панель меню, когда включен полный экран, fps вернется к 60 fps!

вы даже можете проверить эту ошибку, делая спрайт комплект игры для mac в Xcode с использованием шаблона по умолчанию. Вот скриншоты, которые я сделал из шаблона игры по умолчанию для mac.

Я предлагаю попробовать это для себя, вам даже не нужно писать код, если вы используете шаблон набора спрайтов Apple по умолчанию для OS X.

максимальное окно (без проблем FPS: 59-60 FPS) enter image description here

полноэкранный режим (FPS падает до 30-40 FPS) enter image description here

Полноэкранный Режим С Мышью На Верхняя раскрывающая строка меню (удивительно, нет проблем с FPS: 59-60 FPS) enter image description here

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

3 ответов


хорошо, после нескольких недель изучения этой проблемы я нашел некоторые обходные пути к этой проблеме. Прежде чем я начну, позвольте мне начать с объяснения моей установки. Я использую NSViewController в раскадровке, которая содержит SKView. Я протестировал обходной путь на MacBook Pro (Retina, 15-inch, Early 2013), я понятия не имею, будут ли обходные пути, которые я представляю ниже, работать на других Mac. Я считаю, что это должно, когда у меня будет шанс, я проверю и посмотрю, работают ли обходные пути ниже.

Итак, прежде чем начать, давайте напомним, в чем проблема. Проблема в том, что включение вашего приложения в полноэкранный режим, нажав кнопку полноэкранного режима, вызывает массовое падение FPS. Ниже показано, как вы включаете полноэкранную кнопку:

self.view.window!.collectionBehavior = .FullScreenPrimary

Итак, я искал вокруг и нашел другой способ ввода полноэкранного режима с помощью этого кода:

 self.view.enterFullScreenMode(NSScreen.mainScreen()!, withOptions: nil)

но у меня все еще было массовое падение FPS. Имейте в виду, у меня не было проблем с fps, когда в режиме максимального окна или даже в полноэкранном режиме видна строка меню! (видеть фотографии в вопросе).

Итак, я попробовал менее высокоуровневый подход к полноэкранному режиму. Я нашел руководство от Apple здесь

используя часть кода из руководства, мне удалось войти в полноэкранный режим, установив размер окна на размер дисплея и расположив окно над всеми OS X UI. Код для этого выглядит следующим образом:

self.view.window!.styleMask = NSBorderlessWindowMask
self.view.window!.level = Int(CGWindowLevelForKey(Int32(kCGMainMenuWindowLevelKey))) + 1
self.view.window!.opaque = true
self.view.window!.hidesOnDeactivate = true
let size = NSScreen.mainScreen()!.frame.size
self.view.window!.setFrame(CGRect(x: 0, y: 0, width: size.width, height: size.height), display:true)

но, к сожалению, та же проблема... FPS просто упал, как и раньше.

тогда я подумал, что, если я испорчу размер / положение окна. Поэтому я попытался переместить окно вниз, чтобы была видна только строка меню, как показано ниже. И ЭТО СРАБОТАЛО. У меня больше не было падения в fps. Но, очевидно, это не действительно полноэкранный режим, потому что строка меню видна

self.view.window!.setFrame(CGRect(x: 0, y: 0, width: size.width, height: size.height-NSApplication.sharedApplication().mainMenu!.menuBarHeight), display:true)

на самом деле, как оказалось, просто регулировать размер окна на 1 пункт фиксирует падение в fps. таким образом, ошибка должна быть связана с оптимизацией (как иронично) apple, когда ваш размер окна соответствует размеру экрана.

Не веришь мне? Вот цитата из ссылки.

OS X v10.6 и позже автоматически оптимизируют производительность экран-размером окна

таким образом, чтобы решить эту проблему, все, что нам нужно сделать, это сделать нашу высоту размера окна на 1 пункт больше, что предотвратит OS X от попытки оптимизировать наше окно. Это приведет к тому, что ваше приложение будет немного отрезано сверху, но 1 пиксель не должен быть заметны вообще. И в худшем случае вы можете настроить свое положение узлов на 1 пункт, чтобы учесть это.


для вашего удобства, ниже перечислены 2 решения. Оба эти обходные пути не вызывают никакого падения FPS. Ваше приложение должно работать так же, как и в режиме максимального окна. Первый обходной путь помещает ваше приложение в полноэкранный режим и отображает строку меню в верхней части. Второй обходной путь помещает ваше приложение в полный экран без меню бар.

обходной путь 1: полноэкранный режим с панелью меню

self.view.window!.styleMask = NSBorderlessWindowMask
self.view.window!.level = Int(CGWindowLevelForKey(Int32(kCGMainMenuWindowLevelKey))) + 1
self.view.window!.opaque = true
self.view.window!.hidesOnDeactivate = true

let size = NSScreen.mainScreen()!.frame.size
self.view.window!.setFrame(CGRect(x: 0, y: 0, width: size.width, height: size.height-NSApplication.sharedApplication().mainMenu!.menuBarHeight), display:true)

обходной путь 2: полноэкранный режим без строки меню

self.view.window!.styleMask = NSBorderlessWindowMask
self.view.window!.level = Int(CGWindowLevelForKey(Int32(kCGMainMenuWindowLevelKey))) + 1
self.view.window!.opaque = true
self.view.window!.hidesOnDeactivate = true
let size = NSScreen.mainScreen()!.frame.size
NSMenu.setMenuBarVisible(false)
self.view.window!.setFrame(CGRect(x: 0, y: 0, width: size.width, height: size.height+1), display:true)

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


Дополнительная Информация О NSBorderlessWindowMask

эти обходные пути используют маску NSBorderlessWindowMask. Эти типы окон не принимают ввод с клавиатуры при изменении ключевого окна. Поэтому, если ваша игра использует ввод с клавиатуры, вы должны переопределить следующее. См.здесь

 class CustomWindow: NSWindow {
    override var canBecomeKeyWindow: Bool {
        get {
            return true
        }
    }
    override var canBecomeMainWindow: Bool {
        get {
            return true
        }
    }
}

Update: некоторые плохие новости

протестировал этот обходной путь на Mac Book Air, и он сделал не работает, если не было вычтено около 100 очков (что, очевидно, чрезвычайно заметно). Понятия не имею почему. То же самое касается решения andyvn22. Я также заметил, что очень редко, возможно, раз в 60 запускает обходные пути, предоставленные просто не работают на Mac Book Air вообще. И единственный способ исправить это перезапустить приложение. Может быть, Max Book Air-это особый случай. Возможно, отсутствие видеокарты связано с этой проблемой. Надеюсь, Apple разберется с проблемой. Я разрываюсь между ... поддержка полноэкранного режима и не поддержка полноэкранного режима. Я действительно хочу, чтобы пользователи могли войти в полноэкранный режим, но в то же время я не хочу, чтобы пользователи теряли половину своих FPS.


основываясь на очень полезной работе Epic Byte, я нашел еще более простой способ отключить полноэкранную "оптимизацию"Apple. Вы все еще можете использовать встроенные возможности OS X в полноэкранном режиме; все, что вам нужно сделать, это реализовать следующий метод в делегате вашего окна:

func window(window: NSWindow, willUseFullScreenContentSize proposedSize: NSSize) -> NSSize {
    return NSSize(width: proposedSize.width, height: proposedSize.height - 1)
}

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


Я считаю, что эта проблема возникает во всех приложениях, использующих OpenGL для рендеринга. MPV (video player) со следующей конфигурацией видео имеет те же проблемы: vo=opengl hwdec=no

использование ЦП-оконные: в среднем 42%

использование ЦП-полноэкранный режим (родной): 62%

использование процессора-полноэкранный режим (не родной / в приложении): 60%

использование ЦП-полноэкранный режим (родной со строкой меню): 45%

Cpu usage-offscreen (с использованием собственного полного экрана): 95%

этот также происходит на PPSSPP с бэкэндом OpenGL, за исключением увеличенного GPU вместо использования процессора:

использование Gpu-windowed: в среднем 20%

использование Gpu-полноэкранный режим (со строкой меню): 20%

использование Gpu-полноэкранный режим (родной): 35%

использование Gpu-offscreen (с использованием собственного полного экрана): 90%

эта проблема, однако, не возникает, когда разработчики реализуют свой собственный" специальный " полноэкранный режим. В случае ввода Gungeon, где используется cpu и использование gpu не показывает никакой разницы между оконным и FS. Хотя у меня еще не было времени проверить, как они реализовали полноэкранный режим.

протестировано на MBP в конце 2015 13' на OSX 10.11.6

немного увеличенное использование во время полноэкранного режима немного раздражает, как вы сказали, и может вызвать framedrops, но что беспокоит меня больше всего, это почти 100% использование как CPU, так и GPU в приложениях openGL, когда в фоновом режиме. (Примечание: это 90% на ppsspp независимо от того, что он делает, даже когда остановился).