macos - sirve - Sprite Kit Problema serio de FPS en modo de pantalla completa en OS X
optimizacion de pantalla completa (3)
Estoy haciendo un juego de sprite kit bastante complejo. Recientemente agregué soporte para OS X. Obtuve 60 fps siempre, independientemente de cómo se escala mi juego cuando se cambia el tamaño de la ventana (incluso cuando se cambia el tamaño al espacio máximo en la pantalla). Sin embargo, en el momento en que hago que mi aplicación ingrese "Pantalla completa", el fps cae a 30-40 fps y se mantiene de esa manera? Pero si tomo el cursor de mi mouse y dejo ver la barra de menú mientras la pantalla completa está habilitada, ¡el fps vuelve a subir a 60 fps!
Incluso puedes probar este error haciendo un juego de sprite kit para mac en Xcode usando la plantilla predeterminada. Estas son las capturas de pantalla que tomé de la plantilla de juego predeterminada para Mac.
Sugiero probarlo por ti mismo, ni siquiera tienes que escribir ningún código si usas la plantilla de kit de sprite predeterminada de Apple para OS X.
Ventana máxima (sin problemas de FPS: 59-60 FPS)
Modo de pantalla completa (FPS cae a 30-40 FPS)
Modo de pantalla completa con el mouse en la barra de menú superior que revela (Sorprendentemente, NO hay problemas de FPS: 59-60 FPS)
Alguien tiene alguna idea de lo que podría estar causando este problema. No deseo lanzar mi aplicación con el modo de pantalla completa si esto significa que los usuarios perderán el rendimiento. Se podría pensar que el modo de pantalla completa podría optimizar mejor el dibujo, pero aparentemente es todo lo contrario. Estoy ejecutando esto en Yosemite.
Basado en el trabajo muy útil de Epic Byte, encontré una forma aún más fácil de deshabilitar la "optimización" de pantalla completa de Apple. Aún puede usar la capacidad de pantalla completa de OS X; todo lo que tienes que hacer es implementar el siguiente método en el delegado de tu ventana:
func window(window: NSWindow, willUseFullScreenContentSize proposedSize: NSSize) -> NSSize {
return NSSize(width: proposedSize.width, height: proposedSize.height - 1)
}
Desafortunadamente, agregar un píxel no parece funcionar de esta manera, solo restando uno, por lo que pierde una fila de espacio en la pantalla. Sin embargo, me valdrá la pena seguir utilizando la función integrada de pantalla completa, especialmente mientras espero que Apple solucione su error de optimización.
Ok, después de semanas investigando este problema, he encontrado algunas soluciones para este problema. Antes de comenzar, permítanme comenzar explicando mi configuración. Estoy usando un NSViewController en un guión gráfico que contiene un SKView. He probado la solución en MacBook Pro (Retina, 15 pulgadas, principios de 2013), no tengo idea si las soluciones provisionales que presento a continuación funcionarán en otros Mac. Creo que debería, cuando tenga la oportunidad, probaré y veré si las soluciones alternativas a continuación funcionan.
Entonces, antes de comenzar, repasemos cuál es el problema. El problema es que hacer que tu aplicación entre en pantalla completa haciendo clic en el botón de pantalla completa provoca una caída masiva de FPS. A continuación se muestra cómo habilitar el botón de pantalla completa:
self.view.window!.collectionBehavior = .FullScreenPrimary
Entonces busqué y encontré una manera diferente de ingresar a pantalla completa usando este código:
self.view.enterFullScreenMode(NSScreen.mainScreen()!, withOptions: nil)
Pero todavía tuve una caída masiva en FPS. Tenga en cuenta que no tuve problemas de fps cuando estaba en modo de ventana maximizada o incluso en pantalla completa con la barra de menú visible. (ver imágenes en cuestión).
Entonces probé un enfoque de menor nivel para ir a pantalla completa. Encontré una guía de Apple aquí
Utilizando parte del código de la guía, pude ingresar a pantalla completa ajustando el tamaño de la ventana al tamaño de la pantalla y posicionando la ventana sobre toda la interfaz de usuario de OS X. El código para esto es el siguiente:
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)
Pero, lamentablemente, el mismo problema ... El FPS acaba de caer como antes.
Entonces pensé qué pasaría si me metía con el tamaño / posición de la ventana. Así que traté de mover la ventana hacia abajo para que solo la barra de menú fuera visible como se muestra a continuación. Y esto funcionó. Ya no tuve una caída en fps. Pero obviamente no es realmente pantalla completa porque la barra de menú es visible
self.view.window!.setFrame(CGRect(x: 0, y: 0, width: size.width, height: size.height-NSApplication.sharedApplication().mainMenu!.menuBarHeight), display:true)
De hecho, como resulta, simplemente ajustar el tamaño de la ventana en 1 punto corrige la caída en fps. Por lo tanto, el error debe estar relacionado con una optimización (qué irónico) que hace Apple cuando el tamaño de la ventana coincide con el tamaño de la pantalla.
No me creas? Aquí hay una cita del enlace.
OS X v10.6 y posterior optimizan automáticamente el rendimiento de las ventanas de tamaño de pantalla
Entonces, para solucionar el problema, todo lo que tenemos que hacer es aumentar el tamaño de la ventana 1 punto más, lo que evitará que OS X intente optimizar nuestra ventana. Esto hará que su aplicación quede ligeramente cortada en la parte superior, pero 1 píxel no debería ser notable en absoluto. Y en el peor de los casos, podrías ajustar la posición de tus nodos en 1 punto para dar cuenta de esto.
Para su comodidad, a continuación se detallan las 2 soluciones. Ambas soluciones alternativas no causan ninguna caída en FPS. Su aplicación debería funcionar como lo hizo en el modo de ventana maximizada. La primera solución pone tu aplicación en pantalla completa y muestra la barra de menú en la parte superior. La segunda solución pone su aplicación en pantalla completa completa sin barra de menú.
Solución 1: pantalla completa con barra de menú
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)
Solución 2: pantalla completa sin barra de menús
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)
Si por alguna razón estas soluciones no funcionan, trate de jugar un poco más con el tamaño / posición de la ventana. También es posible que deba cambiar el nivel de la ventana según si tiene otras vistas, como diálogos, que su aplicación no debe solaparse. Además, recuerde presentar informes de errores con Apple.
Información adicional sobre NSBorderlessWindowMask
Estas soluciones temporales usan NSBorderlessWindowMask. Este tipo de ventanas no aceptan entrada de teclado cuando cambia la ventana clave. Entonces, si tu juego usa la entrada de teclado, debes anular lo siguiente. Mira aquí
class CustomWindow: NSWindow {
override var canBecomeKeyWindow: Bool {
get {
return true
}
}
override var canBecomeMainWindow: Bool {
get {
return true
}
}
}
Actualización: algunas malas noticias
Probé esta solución alternativa en Mac Book Air, y no funcionó a menos que se restaran unos 100 puntos (lo que obviamente es muy notable). No tengo ni idea de porqué. Lo mismo aplica para la solución de andyvn22. También me he dado cuenta de que muy rara vez, quizás una vez cada 60 inicie las soluciones provistas simplemente no funcionan en el Mac Book Air en absoluto. Y la única forma de solucionarlo es reiniciar la aplicación. Quizás el Max Book Air es un caso especial. Tal vez la falta de una tarjeta gráfica tenga que ver con el problema. Con suerte, Apple soluciona el problema. Ahora estoy dividido entre admitir pantalla completa y no admitir pantalla completa. Realmente quiero que los usuarios puedan ingresar al modo de pantalla completa, pero al mismo tiempo no quiero arriesgar a los usuarios a perder la mitad de sus FPS.
Creo que este problema ocurre en todas las aplicaciones que usan OpenGL para renderizar. MPV (reproductor de video) con la siguiente configuración de video tiene los mismos problemas: vo = opengl hwdec = no
Uso de la CPU - con ventana: promedio 42%
Uso de la CPU: pantalla completa (nativo): 62%
Uso de la CPU: pantalla completa (no nativo / en la aplicación): 60%
Uso de la CPU: pantalla completa (nativo con barra de menús): 45%
Uso de la CPU: fuera de pantalla (con pantalla completa nativa): 95%
Esto también ocurre en PPSSPP con back-end OpenGL, excepto con una GPU incrementada en lugar del uso de la CPU:
Uso de la GPU: con ventana: promedio del 20%
Uso de la GPU: pantalla completa (con la barra de menú): 20%
Uso de la GPU: pantalla completa (nativo): 35%
Uso de la GPU: fuera de pantalla (con pantalla completa nativa): 90%
Sin embargo, este problema no parece ocurrir cuando los desarrolladores implementan su propia pantalla completa "Especial". En el caso de Enter the Gungeon, donde el uso de la CPU y el uso de la GPU no muestran diferencia entre Windows y FS. Aunque todavía no he tenido tiempo de comprobar cómo implementaron la pantalla completa.
Probado en MBP a fines de 2015 13 ''en OSX 10.11.6
El uso ligeramente mayor durante la pantalla completa es un poco molesto, como ya dijiste, y puede causar framedrops, pero lo que más me preocupa es el uso cercano al 100% tanto de la CPU como de la GPU en aplicaciones OpenGL cuando estás en segundo plano. (Nota: es 90% en ppsspp sin importar lo que esté haciendo, incluso cuando está en pausa).