使用廣色域內(nèi)容增強(qiáng)圖形效果
Android 8.0(API 級(jí)別 26)引入了顏色管理支持,以進(jìn)一步 顏色空間 用于在具有兼容顯示屏的設(shè)備上渲染圖形的標(biāo)準(zhǔn) RGB (sRGB)。借助這種支持,您的應(yīng)用可以通過 Java 或原生代碼,使用從 PNG、JPEG 和 WebP 文件加載的嵌入式廣色域配置文件呈現(xiàn)位圖。使用 OpenGL 或 Vulkan 的應(yīng)用可以直接輸出廣色域內(nèi)容(使用 Display P3 和 scRGB)。此功能 有助于創(chuàng)建涉及高保真顏色再現(xiàn)的應(yīng)用,例如圖片和視頻 編輯應(yīng)用程序。
了解廣色域模式
廣色域配置文件是指能夠表示比 sRGB 更廣的顏色范圍的 ICC 配置文件,例如 Adobe RGB、Pro Photo RGB 和 DCI-P3。支持廣色域配置文件的屏幕 可以顯示具有更深主要顏色(紅色、綠色和藍(lán)色)以及更豐富的次要顏色的圖片 顏色(例如洋紅色、青色和黃色)。
在支持 Android 8.0(API 級(jí)別 26)或更高版本的 Android 設(shè)備上,您的應(yīng)用可以
為 activity 啟用廣色域色彩模式,以便系統(tǒng)識(shí)別并
正確處理嵌入了廣色域配置文件的位圖圖像。ColorSpace.Named
類枚舉了 Android 支持的常用顏色空間的部分列表。
注意:?jiǎn)⒂脧V色域模式時(shí),activity 的窗口將更多內(nèi)存和 GPU 處理能力用于畫面構(gòu)成。啟用廣色域之前 模式,那么您應(yīng)仔細(xì)考慮該活動(dòng)是否真的能從中受益。例如, 全屏顯示照片的 activity 非常適合使用廣色域模式, 顯示小縮略圖的 activity 則不行。
啟用廣色域模式
使用 colorMode
屬性請(qǐng)求顯示 activity
在兼容設(shè)備上以廣色域模式顯示在廣色域模式下,窗口可以渲染
顯示更鮮艷的色彩。如果設(shè)備不支持廣色域
色域呈現(xiàn),此屬性無效。如果您的應(yīng)用需要確定某個(gè)特定顯示屏是否支持廣色域,請(qǐng)調(diào)用 isWideColorGamut()
方法。您的應(yīng)用還可以調(diào)用 isScreenWideColorGamut()
,該方法僅當(dāng)顯示屏支持廣色域且設(shè)備支持廣色域顏色呈現(xiàn)時(shí)才會(huì)返回 true
。
顯示屏可能支持廣色域,但不支持顏色管理,在這種情況下,系統(tǒng)不會(huì)向應(yīng)用授予廣色域模式。當(dāng)顯示屏不支持顏色管理時(shí),就像 8.0 以前的所有 Android 版本一樣,系統(tǒng)會(huì)將應(yīng)用繪制的顏色重新映射到顯示屏的色域。
如需在 activity 中啟用廣色域,請(qǐng)?jiān)O(shè)置 colorMode
屬性設(shè)為 AndroidManifest.xml
文件中的 wideColorGamut
。您需要對(duì)想要啟用廣色域模式的每個(gè) activity 執(zhí)行此操作。
android:colorMode="wideColorGamut"
您還可以通過調(diào)用 setColorMode(int)
方法并傳入 COLOR_MODE_WIDE_COLOR_GAMUT
,在您的 activity 中以編程方式設(shè)置顏色模式。
呈現(xiàn)廣色域內(nèi)容
如需呈現(xiàn)廣色域內(nèi)容,您的應(yīng)用必須加載廣色域位圖,該位圖的顏色配置文件包含比 sRGB 更廣的顏色空間。常見的廣色域配置文件包括 Adobe RGB、DCI-P3 和 Display P3。
您的應(yīng)用可以通過調(diào)用 getColorSpace()
查詢位圖的顏色空間。為了確定系統(tǒng)是否識(shí)別出
將特定顏色空間設(shè)為廣色域,您就可以調(diào)用
isWideGamut()
方法結(jié)合使用。
借助 Color
類,您可以使用四個(gè)組成部分表示顏色
打包成一個(gè) 64 位長值,而不是使用整數(shù)的最常見表示法
值。使用 long 值,您可以定義比整數(shù)值更精確的顏色。如果您需要將顏色創(chuàng)建或編碼為 long 值,請(qǐng)使用 Color
類中的某個(gè) pack()
方法。
您可以通過檢查 getColorMode()
方法是否返回 COLOR_MODE_WIDE_COLOR_GAMUT
來驗(yàn)證您的應(yīng)用是否正確請(qǐng)求了廣色域模式(但此方法并不指示是否實(shí)際授予了廣色域模式)。
在原生代碼中使用廣色域支持
本部分介紹當(dāng)您的應(yīng)用使用原生代碼時(shí),如何使用 OpenGL 和 Vulkan API 啟用廣色域模式。
OpenGL
要在 OpenGL 中使用廣色域模式,您的應(yīng)用必須包含 EGL 1.4 庫, 以下擴(kuò)展程序之一:
如需啟用此功能,您必須先通過
eglChooseConfig
(支持的三個(gè)選項(xiàng)之一)
顏色緩沖區(qū)格式。廣色域的顏色緩沖區(qū)格式必須是以下一組 RGBA 值:
- 8, 8, 8, 8
- 10, 10, 10, 2
- FP16, FP16, FP16, FP16
然后,在創(chuàng)建 呈現(xiàn)目標(biāo),如以下代碼段所示:
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 對(duì)廣色域的支持通過
VK_EXT_swapchain_colorspace
個(gè)擴(kuò)展程序。
在 Vulkan 代碼中啟用廣色域支持之前,請(qǐng)先檢查
擴(kuò)展程序可通過
vkEnumerateInstanceExtensionProperties
。
如果該擴(kuò)展程序可用,您必須在安裝期間啟用
vkCreateInstance
,然后再創(chuàng)建
請(qǐng)使用該擴(kuò)展定義的其他顏色空間。
在創(chuàng)建交換鏈之前,您需要選擇所需的顏色空間,然后循環(huán)遍歷 可用的實(shí)體設(shè)備表面,并為此選擇有效的顏色格式 顏色空間。
在 Android 設(shè)備上,Vulkan 支持具有以下顏色空間和
VkSurfaceFormatKHR
顏色格式:
- Vulkan 廣色域顏色空間:
VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT
VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT
- 支持廣色域的 Vulkan 顏色格式:
VK_FORMAT_R16G16B16A16_SFLOAT
VK_FORMAT_A2R10G10B10_UNORM_PACK32
VK_FORMAT_R8G8B8A8_UNORM
以下代碼段展示了如何檢查設(shè)備是否支持 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;
}