Cómo mejorar los gráficos con un amplio contenido de color

Android 8.0 (nivel de API 26) incorporó compatibilidad de administración de color para brindar espacios de color además de RGB estándar (sRGB) para renderizar gráficos en dispositivos con pantallas compatibles. Gracias a este apoyo, tu app puede renderizar mapas de bits con perfiles de amplia gama de colores incorporados que se cargan desde archivos PNG, JPEG y WebP mediante Java o código nativo. Las apps que usan OpenGL o Vulkan pueden generar directamente contenido con una amplia gama de colores (con Display P3 y scRGB). Esta función es útil para crear aplicaciones que implican la reproducción de color de alta fidelidad, como imágenes y videos de edición de fotos.

Cómo funciona el modo de amplia gama de colores

Los perfiles amplios de color perfiles de ICC, como Adobe RGB, . Foto RGB DCI‐P3, que son es capaz de representar un rango de colores más amplio que sRGB. Pantallas que admiten perfiles amplios de color pueden mostrar imágenes con colores primarios más profundos (rojos, verdes y azules), así como con colores colores (como magentas, cian y amarillos).

En los dispositivos Android que ejecutan Android 8.0 (nivel de API 26) o versiones posteriores compatibles, tu app puede habilitar el modo de amplia gama de colores para una actividad mediante la cual el sistema reconoce y procesar correctamente las imágenes de mapas de bits con perfiles amplios de color incorporados. El La clase ColorSpace.Named enumera una lista parcial de los recursos de uso común los espacios de color compatibles con Android.

Nota: Cuando se habilita el modo de amplia gama de colores, el estado de la actividad usa más memoria y procesamiento de GPU para la composición de la pantalla. Antes de habilitar una amplia gama de colores debes considerar con cuidado si la actividad realmente se beneficia de él. Por ejemplo, un que muestra fotos en pantalla completa es una buena candidata para el modo de amplia gama de colores, pero pero no lo es una actividad que muestra miniaturas pequeñas.

Cómo habilitar el modo de amplia gama de colores

Usa el atributo colorMode para solicitar que se muestre la actividad. en el modo de amplia gama de colores en dispositivos compatibles. En el modo de amplia gama de colores, una ventana puede representar fuera del gamut sRGB para mostrar colores más vívidos. Si el dispositivo no admite la orientación ampliada, haz lo siguiente: gamut, este atributo no tiene efecto. Si tu app necesita determinar si un determinado pantalla admite una amplia gama de colores, llama al isWideColorGamut(). Tu app también puede llamar isScreenWideColorGamut(), que muestra true solo si la pantalla admite una amplia gama de colores y el dispositivo admite una amplia gama de colores. y la renderización de colores.

Una pantalla puede admitir una amplia gama de colores, pero no administrarla por color. En ese caso, la no otorgará a una aplicación el modo de amplia gama de colores. Cuando una pantalla no está administrada por color (como en todas las versiones de Android anteriores a la 8.0), el sistema reasigna la los colores que dibuja la app en la gama de la pantalla.

Para habilitar la amplia gama de colores en tu actividad, establece el colorMode a wideColorGamut en tu archivo AndroidManifest.xml. Tú deberás hacer esto para cada actividad para la que desees habilitar el modo de amplia gama de colores.

android:colorMode="wideColorGamut"

También puedes establecer el modo de color de manera programática en tu actividad llamando al setColorMode(int) y pasarlo COLOR_MODE_WIDE_COLOR_GAMUT

Cómo procesar una amplia gama de colores

Figura 1: Espacios de color Display P3 (naranja) en comparación con sRGB (blanco)

Para renderizar contenido con una amplia gama de colores, tu app debe cargar un mapa de bits de amplia gama de colores, es decir, un mapa de bits con un perfil de color que contiene un espacio de color más ancho que sRGB Los perfiles amplios comunes de color incluyen Adobe RGB, DCI-P3 y Display P3.

Tu app puede consultar el espacio de color de un mapa de bits llamando getColorSpace() Para determinar si el sistema reconoce un un espacio de color específico para que sea de una amplia gama, puedes llamar isWideGamut().

La clase Color te permite representar un color con cuatro componentes. empaquetado en un valor largo de 64 bits, en lugar de la representación más común que usa un número entero valor. Con valores largos, puedes definir colores con tienen más precisión que los valores de números enteros. Si necesitas crear o codificar un color como valor largo, usa uno de los métodos pack() de la clase Color

Para comprobar si la app solicitó correctamente el modo de amplia gama de colores, comprueba que el método getColorMode() muestra COLOR_MODE_WIDE_COLOR_GAMUT (este método no indica que sin embargo, si el modo de amplia gama de colores se otorgó realmente).

Cómo usar la compatibilidad con una amplia gama de colores en el código nativo

En esta sección, se describe cómo habilitar el modo de amplia gama de colores con OpenGL y APIs de Vulkan si tu app usa código nativo

OpenGL

Para usar el modo de amplia gama de colores en OpenGL, tu app debe incluir la biblioteca EGL 1.4 con una de las siguientes extensiones:

Para habilitar la función, primero debes crear un contexto de GL mediante eglChooseConfig, con uno de los tres admitidos los formatos de búfer de color para una amplia gama de colores en los atributos. El formato del búfer de color para la color debe ser uno de estos conjuntos de valores RGBA:

  • 8, 8, 8, 8
  • 10, 10, 10, 2
  • FP16, FP16, FP16, FP16

Luego, solicita la extensión de espacio de color P3 cuando crees tu los destinos de renderización, como se muestra en el siguiente fragmento de código:

std::vector<EGLint> attributes;
attributes.push_back(EGL_GL_COLORSPACE_KHR);
attributes.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
attributes.push_back(EGL_NONE);
engine->surface_ = eglCreateWindowSurface(
    engine->display_, config, engine->app->window, attributes.data());

Vulkan

La compatibilidad de Vulkan con la amplia gama de colores se proporciona a través del VK_EXT_swapchain_colorspace.

Antes de habilitar la compatibilidad con la amplia gama de colores en tu código Vulkan, comprueba que el elemento es compatible con vkEnumerateInstanceExtensionProperties Si la extensión está disponible, debes habilitarla durante vkCreateInstance antes de crear cualquier imagen de cadena de intercambio que usa los espacios de color adicionales definidos por la extensión.

Antes de crear la cadena de intercambio, debes elegir el espacio de color deseado y, luego, hacer un bucle a lo largo de los plataformas físicas disponibles de los dispositivos y elige un formato de color válido para ellas espacio de color.

En dispositivos Android, Vulkan admite una amplia gama de colores con los siguientes espacios de color y Formatos de color de VkSurfaceFormatKHR:

  • Espacios de color de la amplia gama de colores de Vulkan:
    • VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT
    • VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT
  • Formatos de color Vulkan compatibles con una amplia gama de colores:
    • VK_FORMAT_R16G16B16A16_SFLOAT
    • VK_FORMAT_A2R10G10B10_UNORM_PACK32
    • VK_FORMAT_R8G8B8A8_UNORM

En el siguiente fragmento de código, se muestra cómo puedes verificar que el dispositivo sea compatible con Display P3. espacio de color:

uint32_t formatCount = 0;
vkGetPhysicalDeviceSurfaceFormatsKHR(
       vkPhysicalDev,
       vkSurface,
       &formatCount,
       nullptr);
VkSurfaceFormatKHR *formats = new VkSurfaceFormatKHR[formatCount];
vkGetPhysicalDeviceSurfaceFormatsKHR(
       vkPhysicalDev,
       vkSurface,
       &formatCount,
       formats);

uint32_t displayP3Index = formatCount;
for (uint32_t idx = 0; idx < formatCount; idx++) {
 if (formats[idx].format == requiredSwapChainFmt &&
     formats[idx].colorSpace==VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT)
 {
   displayP3Index = idx;
   break;
 }
}
if (displayP3Index == formatCount) {
    // Display P3 is not supported on the platform
    // choose other format
}

En el siguiente fragmento de código, se muestra cómo solicitar una cadena de intercambio Vulkan con VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT:

uint32_t queueFamily = 0;
VkSwapchainCreateInfoKHR swapchainCreate {
   .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
   .pNext = nullptr,
   .surface = AndroidVkSurface_,
   .minImageCount = surfaceCapabilities.minImageCount,
   .imageFormat = requiredSwapChainFmt,
   .imageColorSpace = VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT,
   .imageExtent = surfaceCapabilities.currentExtent,
   .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
   .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
   .imageArrayLayers = 1,
   .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
   .queueFamilyIndexCount = 1,
   .pQueueFamilyIndices = &queueFamily,
   .presentMode = VK_PRESENT_MODE_FIFO_KHR,
   .oldSwapchain = VK_NULL_HANDLE,
   .clipped = VK_FALSE,
};
VkRresult status = vkCreateSwapchainKHR(
                       vkDevice,
                       &swapchainCreate,
                       nullptr,
                       &vkSwapchain);
if (status != VK_SUCCESS) {
    // Display P3 is not supported
    return false;
}