Vulkan difiere de las APIs de gráficos anteriores en que los controladores no realizan determinadas optimizaciones para apps, como la reutilización de la canalización. En cambio, las apps que usan Vulkan deben implementar esas optimizaciones por sí mismas. Si no lo hacen, su rendimiento puede ser peor que el de las apps que ejecutan OpenGL ES.
Cuando las apps implementan esas optimizaciones por sí mismas, tienen la posibilidad de hacerlo de manera más satisfactoria que el controlador, ya que tienen acceso a información más específica sobre un caso práctico determinado. Como resultado, optimizar con habilidad una app con Vulkan puede proporcionar un mejor rendimiento que si usa OpenGL ES.
En esta página, se presentan varias optimizaciones que tu app para Android puede implementar a fin de obtener un mayor rendimiento gracias a Vulkan.
Aceleración de hardware
La mayoría de los dispositivos admiten Vulkan 1.1 mediante la aceleración de hardware, mientras que un pequeño subconjunto lo admite mediante emulación de software. Para detectar un dispositivo Vulkan basado en software, las apps pueden usar vkGetPhysicalDeviceProperties
y verificar el campo deviceType
de la estructura que se muestra.
SwiftShader y otras implementaciones basadas en CPU tienen el valor VK_PHYSICAL_DEVICE_TYPE_CPU
.
Las apps pueden buscar SwiftShader específicamente; para esto, deben buscar valores específicos de SwiftShader en los campos vendorID
y deviceID
de esta misma estructura.
Las apps fundamentales para el rendimiento deben evitar el uso de implementaciones de Vulkan emuladas por software y, en su lugar, recurrir a OpenGL ES.
Cómo aplicar la rotación de pantalla durante el procesamiento
Cuando la orientación hacia arriba de una app no coincide con la orientación de la pantalla del dispositivo, el compositor gira las imágenes de la cadena de intercambio de la app de modo que coincidan. La rotación ocurre mientras se muestran las imágenes, lo cual genera un mayor consumo de energía (a veces, mucho mayor) que cuando estas no rotan.
Por el contrario, rotar las imágenes de la cadena de intercambio mientras se generan produce un consumo de energía adicional muy reducido o nulo. En el campo VkSurfaceCapabilitiesKHR::currentTransform
, se indica la rotación que el compositor aplica a la ventana. Después de aplicar esa rotación durante el procesamiento, la app usa el campo VkSwapchainCreateInfoKHR::preTransform
para informar que la rotación se completó.
Cómo minimizar los pases de procesamiento por fotograma
En la mayoría de las arquitecturas de GPU para dispositivos móviles, comenzar y finalizar un pase de procesamiento es una operación que consume muchos recursos. Tu app puede mejorar el rendimiento si organiza las operaciones de procesamiento con la menor cantidad de pases de procesamiento posible.
Las diferentes operaciones de carga y almacenamiento de datos adjuntos ofrecen niveles de rendimiento distintos. Por ejemplo, si no necesitas preservar el contenido de datos adjuntos, puedes usar VK_ATTACHMENT_LOAD_OP_CLEAR
o VK_ATTACHMENT_LOAD_OP_DONT_CARE
en lugar de VK_ATTACHMENT_LOAD_OP_LOAD
, ya que son mucho más rápidos. Asimismo, si no necesitas escribir los valores finales de los datos adjuntos en la memoria para usarlos más adelante, puedes usar VK_ATTACHMENT_STORE_OP_DONT_CARE
para obtener un rendimiento mucho mejor que con VK_ATTACHMENT_STORE_OP_STORE
.
En la mayoría de los pases de procesamiento, tu app no necesita cargar ni almacenar los datos adjuntos de profundidad/símbolos. En esos casos, puedes evitar tener que asignar memoria física para los datos adjuntos si usas la marca VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
cuando creas la imagen de datos adjuntos. Este bit proporciona los mismos beneficios que glFramebufferDiscard
en OpenGL ES.
Cómo elegir los tipos adecuados de memoria
Al asignar la memoria del dispositivo, las apps deben elegir un tipo de memoria. El tipo de memoria determina la manera en que una app puede usar la memoria y también describe propiedades de almacenamiento en caché y coherencia de la memoria. Diferentes dispositivos tienen diferentes tipos de memoria disponibles, y diferentes tipos de memoria exhiben distintas características de rendimiento.
Una app puede usar un algoritmo simple para elegir el mejor tipo de memoria para un uso determinado. Este algoritmo selecciona el primer tipo de memoria del arreglo VkPhysicalDeviceMemoryProperties::memoryTypes
que cumpla con dos criterios: el tipo de memoria debe estar permitido para el búfer o la imagen, y debe contar con las propiedades mínimas que requiere la app.
Por lo general, los sistemas móviles no tienen montones de memoria física separados para la CPU y la GPU. En esos sistemas, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
no es tan significativo como en sistemas que tienen GPU discretas con su propia memoria dedicada. Una app no debe suponer que esta propiedad es obligatoria.
Cómo agrupar conjuntos de descriptores por frecuencia
Si tienes vinculaciones de recursos que cambian en frecuencias diferentes, usa varios conjuntos de descriptores por canalización en lugar de volver a vincular todos los recursos para cada dibujo. Por ejemplo, puedes tener un conjunto de descriptores para las vinculaciones por escena, otro conjunto para las vinculaciones por material y un tercer conjunto para vinculaciones por instancia de malla.
Usa constantes inmediatas para los cambios de mayor frecuencia, como los que se ejecutan con cada llamada de dibujo.