iOS avanzado: dibujo UIView
Si desea estudiar OpenGL ES y GPU, este artículo es de gran valor de referencia introductorio.
En primer lugar, comencemos con Runloop de iOS, que es una devolución de llamada de 60 fps. Es decir, la pantalla se dibujará una vez cada 16,7 ms (milisegundos) y debe completarse dentro de este período de tiempo:
El trabajo de estas CPU
Luego. este búfer se entrega a la GPU para su renderizado, este proceso también incluye:
La realidad final está en la pantalla. Por lo tanto, si estas operaciones no se pueden completar en 16,7 ms, por ejemplo: la CPU lo ha hecho. demasiado trabajo, o los niveles de visualización son demasiados y la imagen es demasiado grande, lo que resulta en Demasiada presión sobre la GPU provocará fenómenos de "bloqueo", es decir, caída de fotogramas
Lo mejor. La velocidad de fotogramas proporcionada oficialmente por Apple es: 60 fps (60 Hz), lo que significa que no se pierde un fotograma. Por supuesto, esta es una experiencia ideal y excelente.
En términos generales, si la velocidad de fotogramas alcanza los 60 fps (. fps gt; = más de 60 fotogramas, si la velocidad de fotogramas fps gt es 50, el ojo humano básicamente sentirá que no se congelará, por lo que si puede mantener su programa iOS estable a 60 fps, ya es muy bueno. es "estable" a 60 fps, no a 10 fps, 40 fps, 20 fps, tales saltos no son estables, es realmente difícil lograr 60 fps, especialmente en máquinas de 32 bits como el iPhone 4/4s. Sin embargo, ahora que Apple ha abandonado por completo los 32 bits, será mucho mejor admitir el mínimo de 64 bits.
En general, el proceso desde el dibujo hasta la representación de UIView tiene los siguientes pasos:
<. p> El dibujo y la representación de UIView son dos procesos:De la CPU a la GPU mencionado anteriormente. No se producirá ninguna operación. Dado que UILabel anula el método drawRect, esta Vista se marcará como "sucia":
Similar a esto:
Luego llega un nuevo Runloop. Como se mencionó anteriormente, la interfaz debe renderizarse en este Runloop. Para el renderizado de UIKit, Apple. utiliza su animación central. El método es llamar cuando se inicia Runloop:
Llamar cuando finaliza Runloop
Lo que se hace entre el inicio y la confirmación es agregar la vista a la jerarquía de vistas. No se producirán operaciones de dibujo.
Cuando se ejecuta [compromiso de CATransaction], la CPU comienza a dibujar esta vista:
Primero, la CPU asignará una parte de memoria para que la capa dibuje el mapa de bits, llamada almacén de respaldo
Crea un puntero a este buffer de mapa de bits, llamado CGContextRef
Dibuja el mapa de bits a través de la API de Core Graphic, también llamado Quartz2D
Apunta el contenido de la capa al mapa de bits generado
p>Borre la bandera sucia
De esta manera, el dibujo de la CPU básicamente se completa.
Puede ver completamente el proceso a través del perfilador de tiempo:
Si el texto de la etiqueta se modifica en algún momento:
Dado que el contenido ha cambiado, el tamaño del mapa de bits del contenido de la capa también cambiará. cuando llegue el nuevo Runloop en este momento, la CPU tendrá que volver a crear la capa. Un almacén de respaldo y volver a dibujar el mapa de bits.
La parte de la CPU que consume más tiempo suele ser el dibujo de Core Graphic. La optimización del rendimiento de Core Graphic es otro tema e involucra muchas cosas que no discutiré aquí.
GPU vinculada:
La CPU ha completado su tarea: girar. la vista en un mapa de bits, y luego es trabajo de la GPU. La unidad de procesamiento de la GPU es la Textura.
Básicamente controlamos la GPU a través de OpenGL, pero se necesita un puente del mapa de bits a la Textura. y Core Animation juega exactamente este papel:
Core Animation tiene razón. La API de OpenGL tiene una capa de encapsulación. Cuando la capa que queremos renderizar ya tiene contenido de mapa de bits, este contenido generalmente es un CGImageRef. Textura OpenGL y vincule CGImageRef (mapa de bits) a esta textura a través de TextureID para identificar.
Una vez establecida esta correspondencia, la tarea restante es cómo la GPU renderiza la textura en la pantalla. El modo de trabajo general de la GPU es el siguiente:
Todo el proceso es una cosa:
La CPU coloca el mapa de bits preparado en la RAM y el La GPU lo mueve. Esta memoria rápida se procesa en VRAM. El límite que la GPU puede soportar en este proceso es de aproximadamente 16,7 ms para completar un cuadro de procesamiento, por lo que los 60 fps mencionados al principio es en realidad la frecuencia más alta que la GPU puede procesar.
Por lo tanto, existen Dos desafíos para la GPU:
El cuello de botella entre estos dos es básicamente el segundo punto.
Rendering Texture básicamente necesita abordar los siguientes problemas:
La composición se refiere al proceso de juntar múltiples texturas. Correspondiente a UIKit, se refiere al procesamiento de la situación de combinar múltiples vistas, como:
Si no hay superposición entre vistas, la GPU solo necesita realizar una representación normal.
Si hay superposición entre varias vistas, la GPU debe realizar una combinación
> Agrega dos vistas del mismo tamaño, una superpuesta a la otra, luego la fórmula de cálculo es la siguiente:
R = S D *( 1 - Sa )
Entre ellas, S y D han sido valores alfa respectivos premultiplicados.
Sa representa el valor alfa de Textura.
Si el valor alfa de Top Texture (vista superior) es 1, es opaco. Entonces oscurecerá la textura subyacente.
Es decir, R = S. es razonable.
Si el valor alfa de Top Texture (vista superior) es 0,5,
S es (1, 0, 0), que es (0,5, 0, 0) después de multiplicar por alfa.
D es (0, 0, 1).
La R obtenida es (0,5, 0, 0,5).
Básicamente, cada píxel debe calcularse de esta manera.
Por lo tanto, si la jerarquía de vistas es compleja o si todas las vistas son translúcidas (el valor alfa no es 1), provocará trabajo informático adicional para la GPU.
Este problema se debe principalmente al procesamiento de imágenes. Si hay una imagen de 400x400 en la memoria y es necesario colocarla en una vista de imagen de 100x100, si no se realiza ningún procesamiento y simplemente se agrega, el problema desaparecerá. ser enorme, lo que significa que la GPU necesita escalar la imagen grande a un área pequeña para su visualización y necesita realizar un muestreo de píxeles. Este tipo de muestreo es muy costoso y también debe tener en cuenta la alineación de los píxeles. La cantidad de cálculo se disparará.
Si hacemos esto con la capa:
Se producirá renderizado fuera de la pantalla. El mayor problema que trae es que al renderizar dicha capa, es necesario asignar memoria adicional para dibujar el radio. y máscara, y luego reasigne el mapa de bits dibujado a la capa.
Por lo tanto, continuando considerando el rendimiento, Quartz proporciona una API optimizada:
En pocas palabras, este es un mecanismo de caché.
De manera similar, el rendimiento de la GPU también se puede medir a través de un instrumento:
Rojo significa que la GPU necesita hacer trabajo adicional para renderizar la Vista, verde significa que la GPU no necesita hacer trabajo adicional. El trabajo es procesar mapas de bits.
Texto completo
Incluye: Dirección original