使用广色域内容增强图形效果

Android 8.0(API 级别 26)引入了颜色管理支持,以提供更多 颜色空间 用于在具有兼容显示屏的设备上渲染图形的标准 RGB (sRGB)。有了这些支持 您的应用可以渲染具有从 PNG、JPEG 和 WebP 文件加载的嵌入式广色域配置文件的位图 通过 Java 或原生代码创建使用 OpenGL 或 Vulkan 的应用可以直接输出广色域内容 (使用 Display P3scRGB)。此功能 有助于创建涉及高保真颜色再现的应用,例如图片和视频 编辑应用程序。

了解广色域模式

广色域配置文件 ICC 配置文件,例如 Adobe RGB Pro Photo RGBDCI-P3, 能够表示比 sRGB 更广的颜色范围。支持广色域配置文件的屏幕 可以显示具有更深主要颜色(红色、绿色和蓝色)以及更丰富的次要颜色的图片 颜色(例如洋红色、青色和黄色)。

在支持 Android 8.0(API 级别 26)或更高版本的 Android 设备上,您的应用可以 为 activity 启用广色域色彩模式,以便系统识别并 正确处理嵌入了广色域配置文件的位图图像。通过 ColorSpace.Named 类枚举常用技术的部分列表 颜色空间

注意:启用广色域模式后,activity 的 窗口使用更多内存和 GPU 处理来合成屏幕。启用广色域之前 模式,那么您应仔细考虑该活动是否真的能从中受益。例如, 全屏显示照片的 activity 非常适合使用广色域模式, 显示小缩略图的 activity 则不行。

启用广色域模式

使用 colorMode 属性请求显示 activity 在兼容设备上以广色域模式显示在广色域模式下,窗口可以渲染 显示更鲜艳的色彩。如果设备不支持广色域 色域呈现,此属性无效。如果您的应用需要确定 显示屏支持广色域, isWideColorGamut() 方法结合使用。您的应用还可以调用 isScreenWideColorGamut(),会返回 true 仅当显示屏支持广色域且设备支持广色域时 呈现方式

显示器可能支持广色域,但不能进行颜色管理,在这种情况下, 系统不会向应用授予广色域模式。不对显示屏进行颜色管理时 (与 8.0 之前的所有 Android 版本一样),系统会重新映射 根据显示屏色域绘制的颜色。

如需在 activity 中启用广色域,请设置 colorMode 属性设为 AndroidManifest.xml 文件中的 wideColorGamut。您 需要对每个您想启用广色域模式的 activity 执行此操作。

android:colorMode="wideColorGamut"

您也可以在 Activity 中以编程方式设置颜色模式,只需调用 setColorMode(int) 方法并传入 COLOR_MODE_WIDE_COLOR_GAMUT

呈现广色域内容

<ph type="x-smartling-placeholder">
</ph>
图 1.Display P3(橙色)与 sRGB(白色)颜色空间对比

要呈现广色域内容,您的应用必须加载广色域位图,即 包含宽度大于 sRGB 的颜色空间的色彩配置文件。常见的广色域配置文件包括 Adobe RGB、DCI-P3 和 Display P3。

您的应用可以通过调用 getColorSpace()。为了确定系统是否识别出 将特定颜色空间设为广色域,就可以调用 isWideGamut() 方法结合使用。

借助 Color 类,您可以使用四个组成部分表示颜色 打包成一个 64 位长值,而不是使用整数的最常见表示法 值。使用 long 值,您可以通过 精确率比整数值高。如果您需要将颜色创建或编码为 long 值,请使用 Color 类中的一个 pack() 方法。

您可以通过检查 getColorMode() 方法会返回 COLOR_MODE_WIDE_COLOR_GAMUT(此方法并不表示 但是,是否实际授予了广色域模式)。

在原生代码中使用广色域支持

本部分介绍如何使用 OpenGLVulkan API。

OpenGL

要在 OpenGL 中使用广色域模式,您的应用必须包含 EGL 1.4 库, 以下扩展程序之一:

如需启用此功能,您必须先通过 eglChooseConfig(支持的三个选项之一) 颜色缓冲区格式。适用于宽幅面板的颜色缓冲区格式 color [颜色] 必须是以下一组 RGBA 值:

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

然后,在创建 呈现目标,如以下代码段所示:

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

Vulkan 对广色域的支持通过 VK_EXT_swapchain_colorspace 个扩展程序。

在 Vulkan 代码中启用广色域支持之前,请先检查 扩展程序可通过 vkEnumerateInstanceExtensionProperties。 如果该扩展程序可用,您必须在安装期间启用 vkCreateInstance,然后再创建 请使用该扩展定义的其他颜色空间。

在创建交换链之前,您需要选择所需的颜色空间,然后循环遍历 可用的实体设备表面,并为此选择有效的颜色格式 颜色空间。

在 Android 设备上,Vulkan 支持具有以下颜色空间和 VkSurfaceFormatKHR 颜色格式:

  • Vulkan 广色域颜色空间: <ph type="x-smartling-placeholder">
      </ph>
    • VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT
    • VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT
  • 支持广色域的 Vulkan 颜色格式: <ph type="x-smartling-placeholder">
      </ph>
    • VK_FORMAT_R16G16B16A16_SFLOAT
    • VK_FORMAT_A2R10G10B10_UNORM_PACK32
    • VK_FORMAT_R8G8B8A8_UNORM

以下代码段展示了如何检查设备是否支持 Display P3 颜色空间:

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
}

以下代码段展示了如何使用 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;
}