広色域コンテンツでグラフィックを強化する

Android 8.0(API レベル 26)では、追加のカラー マネージメント サポートが導入されました。 色スペース 対応ディスプレイを備えたデバイスでのグラフィックのレンダリングに使用する標準 RGB(sRGB)です。このサポートにより、PNG、JPEG、WebP ファイルから Java またはネイティブ コードを介して読み込まれた埋め込み広色域プロファイルを使って、アプリでビットマップをレンダリングできます。OpenGL または Vulkan を使用しているアプリは、広色域コンテンツを直接出力できます(Display P3scRGB を使用)。この機能は 画像や動画など、色を忠実に再現するアプリの作成に便利 アプリを編集しています。

広色域モードを理解する

広色域プロファイルは ICC プロファイル: Adobe RGB、 <ph type="x-smartling-placeholder"></ph> プロフォト RGB DCI-P3: sRGB よりも幅広い色を表現できます。ワイドカラー プロファイルをサポートする画面では、より深みのあるプライマリ カラー(赤、緑、青)と、より豊かなセカンダリ カラー(マゼンタ、シアン、黄色など)の画像を表示できます。

これをサポートする Android 8.0(API レベル 26)以降が実行されている Android デバイスでは、アプリがアクティビティに対して広色域モードを有効にできるため、埋め込み広色域プロファイルを使ってビットマップ画像が認識され、正しく処理されます。「 ColorSpace.Named クラスは、よく使用されるアプリケーションの部分リストを列挙 Android がサポートする色空間です。

注: 広色域モードが有効になっていると、より多くのメモリと GPU 処理がアクティビティ ウィンドウの画面構成に使用されます。広色域を有効にする前に アクティビティが本当にその恩恵を受けているかどうかを慎重に検討する必要があります。たとえば、写真を全画面表示するアクティビティは広色域モードに適していますが、小さなサムネイルを表示するアクティビティは適していません。

広色域モードを有効にする

colorMode 属性を使用して、アクティビティの表示をリクエストする 対応デバイスで広色域モードで表示できます広色域モードでは、sRGB 色域以外をウィンドウでレンダリングして、より鮮やかな色を表示できます。デバイスが広色域に対応していない場合 色域レンダリングを使用した場合、この属性は機能しません。特定のディスプレイが広色域に対応しているかどうかをアプリで判断する必要がある場合は、isWideColorGamut() メソッドを呼び出します。また、アプリで isScreenWideColorGamut() を呼び出すこともできます。これは、ディスプレイが広色域に対応していて、デバイスが広色域のカラー レンダリングをサポートしている場合にのみ true を返します。

ディスプレイが広色域対応でも、色管理されていない場合は、アプリに対して広色域モードが許可されることはありません。ディスプレイがカラー マネージメントでない場合 (Android 8.0 より前のすべてのバージョンの場合と同様)に、 アプリによってディスプレイの色域に描画された色。

アクティビティで広色域を有効にするには、AndroidManifest.xml ファイルで colorMode 属性を wideColorGamut に設定します。この操作は、広色域モードを有効にするアクティビティごとに行う必要があります。

android:colorMode="wideColorGamut"

アクティビティでプログラムによって色モードを設定することもできます。それには、setColorMode(int) メソッドを呼び出して COLOR_MODE_WIDE_COLOR_GAMUT を渡します。

広色域コンテンツをレンダリングする

図 1. ディスプレイの P3(オレンジ)と sRGB(白)の色空間

広色域コンテンツをレンダリングするには、広色域ビットマップ( sRGB よりも広い色空間を含むカラー プロファイル。一般的な広色域プロファイルには、 Adobe RGB、DCI-P3、Display P3。

ビットマップの色空間をクエリするには、 getColorSpace()。システムが 広色域でレンダリングしたい場合は isWideGamut() メソッドを使用します。

Color クラスを使用すると、整数値で色を表現する一般的な方法ではなく、4 つのコンポーネントで構成される 64 ビット長の値で色を表現できます。長い値を使用すると、 精度が高くなります色を long 値として作成またはエンコードする必要がある場合は、次のコマンドを使用します。 Color クラスの pack() メソッドのいずれか。

アプリが広色域モードを適切にリクエストしたかどうかを確認するには、getColorMode() メソッドが COLOR_MODE_WIDE_COLOR_GAMUT を返すことを確認します(ただし、このメソッドは、広色域モードが実際に許可されたかどうかを示すものではありません)。

ネイティブ コードで広色域サポートを使用する

ここでは、アプリでネイティブ コードが使用されている場合に、OpenGL API および Vulkan API で広色域モードを有効にする方法について説明します。

OpenGL

OpenGL で広色域モードを使用するには、EGL 1.4 ライブラリを 次のいずれかの拡張機能を使用できます。

この機能を有効にするには、まず eglChooseConfig を介して、サポートされている 3 つの広色域用カラーバッファ形式のいずれかを属性で使用して、GL コンテキストを作成する必要があります。ワイド広告のカラーバッファ形式 color は次のいずれかの RGBA 値にする必要があります。

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

P3 色空間拡張をリクエストして、 レンダリング ターゲットを、次のコード スニペットに示します。

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 広色域の色スペース:
    • 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

次のコード スニペットは、デバイスが 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
}

次のコード スニペットは、以下を含む Vulkan スワップチェーンをリクエストする方法を示しています。 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;
}