Android に追加される新しいピクセル形式はすべて、Android インターフェース定義言語(AIDL)と Android ハードウェア バッファ(AHB)に含まれている必要があります。AIDL と AHB には安定性と標準化に関する厳格な要件があるため、機能を拡張する際には慎重なプロセスが必要となります。新しいピクセル形式はすべて AOSP に対応している必要があり、すべてのアップデートは個々に AIDL および AHB エキスパートによって確認されている必要があります。この慎重な確認プロセスはプラットフォームでの新しいピクセル形式の標準化において重要な要素です。
このページでは必要となる AOSP でのコード変更と、AOSP での新しいピクセル形式の追加に必要なプロセスを説明します。
新しいピクセル形式を追加する前に、パッチの送信で説明のとおり、ソースをダウンロードして、パッチをアップロードします。新しいピクセル形式を AIDL に追加する
新しいピクセル形式のサポートを追加するには、AIDL 内にある両方の PixelFormat.aidl
ファイルへの変更が必要です。AIDL ソースコードについては hardware/interfaces/graphics/common/aidl/
をご参照ください。
新しいピクセル形式を AIDL に追加するには、次の手順に沿って行います。
- 新しいピクセル形式を新規エントリとして
PixelFormat.aidl
のPixelFormat
列挙型の最後に追加します。既存のコード規則に従い、エントリの 16 進数値をその前のエントリより 1 つ増やして設定します。コード変更をその前のエントリと一致させます。以下のRGBA_8888
ピクセル形式のエントリの例をご覧ください。/** * 32-bit format that has 8-bit R, G, B, and A components, in that order, * from the lowest memory address to the highest memory address. * * The component values are unsigned normalized to the range [0, 1], whose * interpretation is defined by the dataspace. */ RGBA_8888 = 0x1,
PixelFormat.aidl
に変更を加えた後にコードをビルドすると次のエラー メッセージが表示されます。android_developer:~/android/aosp-main: m ... ############################################################################### # ERROR: AIDL API change detected # ############################################################################### Above AIDL file(s) has changed. Run `m android.hardware.graphics.common-update-api` to reflect the changes to the current version so that it is reviewed by android-aidl-api-council@google.com And then you need to change dependency on android.hardware.graphics.common-V(n)-* to android.hardware.graphics.common-V(n+1)-* to use new APIs.
-
このエラーを消去するには、エラー メッセージで説明されているとおり、次のコマンドを実行して
aidl_api
ディレクトリのPixelFormat.aidl
を変更します。m android.hardware.graphics.common-update-api
このコマンドを実行すると、正しいファイルがアップデートされ、通常どおりにビルドできるようになります。
新しいピクセル形式を AHB に追加する
新しいピクセル形式のサポートを追加するには、hardware_buffer.h
と AHardwareBuffer.cpp
を変更する必要があります。AHB ソースコードについては frameworks/native/libs/nativewindow
をご覧ください。
新しいピクセル形式を AHB に追加するには、次の手順に沿って行います。
hardware_buffer.h
で新しいピクセル形式を新規エントリとしてAHardwareBuffer_Format
列挙型の最後に追加します。既存のコード規則に従います。RGBA_8888
ピクセル形式の例を使用して、新しいピクセル形式のエントリを次のように追加します。/** * Corresponding formats: * Vulkan: VK_FORMAT_R8G8B8A8_UNORM * OpenGL ES: GL_RGBA8 */ AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1,
新しいピクセル形式は AHB で名前が付与されます。名前は
AHARDWAREBUFFER_FORMAT_
で始まり、その後にチャネルの略称とビット深度が続き、エンコードで終わります。この列挙型エントリはPixelFormat.aidl
にあるものと同じ 16 進数値である必要があります。ピクセル形式は関連する Vulkan または OpenGL ES 形式のいずれかまたは両方を保持していることがあります。該当する場合は関連する形式を指定します。関連する形式が存在しない場合は、
N/A
と指定します。-
関連する OpenGL ES 形式がある場合には、ピクセル形式を CTS のオプション テストに追加します。そのためには、次のように新しい GL 形式を
AHBFormatAsString(int32_t format)
のAHardwareBufferGLTest.cpp
に新しい形式のFORMAT_CASE(...)
とGL_FORMAT_CASE(...)
を使って追加します。const char* AHBFormatAsString(int32_t format) { switch (format) { ... FORMAT_CASE(R8G8B8A8_UNORM); ... GL_FORMAT_CASE(GL_RGB8); } return ""; }
-
次に新しいテストを次のように
AHardwareBufferGLTest.cpp
に追加します。class RGBA8Test : public AHardwareBufferGLTest {}; // Verify that if we can allocate an RGBA8 AHB we can render to it. TEST_P(RGBA8Test, Write) { AHardwareBuffer_Desc desc = GetParam(); desc.usage = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER; if (!SetUpBuffer(desc)) { return; } ASSERT_NO_FATAL_FAILURE(SetUpFramebuffer(desc.width, desc.height, 0, kBufferAsRenderbuffer)); ASSERT_NO_FATAL_FAILURE( SetUpProgram(kVertexShader, kColorFragmentShader, kPyramidPositions, 0.5f)); glDrawArrays(GL_TRIANGLES, 0, kPyramidVertexCount); ASSERT_EQ(GLenum{GL_NO_ERROR}, glGetError()); } INSTANTIATE_TEST_CASE_P( SingleLayer, RGBA8Test, ::testing::Values( AHardwareBuffer_Desc{57, 33, 1, AHARDWAREBUFFER_FORMAT_R16G16_UINT, 0, 0, 0, 0}), &GetTestName);
AHardwareBuffer_Desc
値のセットを 1 つ以上指定します。必要に応じてさらに値を追加します。 -
AHardwareBuffer.cpp
内にある静的アサートの最後の部分を見つけます。// ---------------------------------------------------------------------------- // Validate hardware_buffer.h and PixelFormat.aidl agree // ----------------------------------------------------------------------------
新しいピクセル形式の新しい
static_assert
を追加します。PixelFormat::
列挙型を使用し、HAL_PIXEL_FORMAT
定数は使用しません。新しいピクセル形式を AIDL に追加するに記載のRGBA_8888
ピクセル形式の例を使って、次のように新しいピクセル形式のエントリを追加します。static_assert(static_cast
(aidl::android::hardware::graphics::common::PixelFormat::RGBA_8888) == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, "HAL and AHardwareBuffer pixel format don't match"); -
新しいピクセル形式を適切なテストに追加するために、新しいピクセル形式を
AHardwareBufferTest.cpp
のPrintAhbFormat()
の最後に追加します。以下のとおり既存のコード規則に従います。void PrintAhbFormat(std::ostream& os, uint64_t format) { switch (format) { ... FORMAT_CASE(R8G8B8A8_UNORM); default: os << "unknown"; break; } }
-
新しいピクセル形式を
HardwareBuffer.java
のHardwareBuffer
SDK に追加するために、新しいエントリを@IntDef
に追加します。たとえば、RGBA_8888
形式のエントリは次のようになります。@Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "RGB", "BLOB", "YCBCR_", "D_", "DS_", "S_" }, value = { ... RGBA_8888, })
コンポーネントの値が符号なし正規化整数でない場合は、変数名で明示的に値を示します。たとえば、16 ビットの符号なし整数の赤チャネルのみの形式の変数名は
R_16UI
とします。同じ形式で追加の 16 ビットの符号なし整数の緑チャネル形式を含む場合はRG_16UI16UI
とします。 -
新しいピクセル形式を
HardwareBuffer.java
にstatic int
として追加するために、@Format
の最後に新しいパブリック メンバー変数を追加します。@Format ... /** Format: 8 bits each red, green, blue, alpha */ public static final int RGBA_8888 = 0x1;
この列挙型エントリは
PixelFormat.aidl
とhardware_buffer.h
にあるものと同じ 16 進数値である必要があります。既存の規則に従います。 -
このコード変更でビルドしようとすると、ビルドエラーが生成されます。
android_developer:~/android/aosp-main: m ... ****************************** You have tried to change the API from what has been previously approved. To make these errors go away, you have two choices: 1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc) to the new methods, etc. shown in the above diff. 2. You can update current.txt and/or removed.txt by executing the following command: m api-stubs-docs-non-updatable-update-current-api To submit the revised current.txt to the main Android repository, you will need approval. ****************************** ...
このエラーを消去するには、エラー メッセージで説明されているとおり、次のコマンドを実行して
current.txt
を変更します。m api-stubs-docs-non-updatable-update-current-api
このコマンドを実行すると、正しいファイルがアップデートされ、通常どおりにビルドできるようになります。
-
新しいピクセル形式を Java テストに追加するために、次のように新しいピクセル形式を
HardwareBufferTest.java
のparamsForTestCreateOptionalFormats()
の最後に追加します。private static Object[] paramsForTestCreateOptionalFormats() { return new Integer[]{ HardwareBuffer.RGBA_8888 };
新しいピクセル形式をウィンドウ システム統合に追加する
新しいピクセル形式を Graphics API でフレームバッファの形式として使用するには、関連する Graphics API の適切なウィンドウ システム統合(WSI)に追加します。Vulkan API を使用したアプリまたはシステム プロセスの場合は、Vulkan スワップチェーンを更新します。OpenGL ES API を使用したアプリまたはシステム プロセスの場合は、EGL API を更新します。
新しいピクセル形式のための Vulkan WSI での変更
Vulkan WSI を次のように更新します。-
新しいケースを
swapchain.cpp
のGetNativePixelFormat(VkFormat format)
関数に追加します。android::PixelFormat GetNativePixelFormat(VkFormat format) { ... switch (format) { ... case VK_FORMAT_R8G8B8A8_UNORM: native_format = PixelFormat::RGBA_8888; break; ... default: ALOGV("unsupported swapchain format %d", format); break; } return native_format; }
- ピクセル形式で Vulkan 拡張機能が必要な場合は、Vulkan 拡張機能をクエリします。インスタンス側の拡張機能の場合は、以下のように
instance_data
を使用します。bool colorspace_ext = instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
デバイス側の拡張機能の場合は、以下を使用します。
bool rgba10x6_formats_ext = false; uint32_t exts_count; const auto& driver = GetData(pdev).driver; driver.EnumerateDeviceExtensionProperties(pdev, nullptr, &exts_count, nullptr); std::vector
props(exts_count); driver.EnumerateDeviceExtensionProperties(pdev, nullptr, &exts_count, props.data()); for (uint32_t i = 0; i < exts_count; i++) { VkExtensionProperties prop = props[i]; if (strcmp(prop.extensionName, VK_EXT_RGBA10X6_FORMATS_EXTENSION_NAME) == 0) { rgba10x6_formats_ext = true; } } Google がインスタンスまたはデバイス拡張機能を
swapchain.cpp
に公開するために必要なインフラストラクチャを管理します。初回の変更リストでは、拡張機能が Vulkan ローダーから正しくセットアップされている必要はありません。 - 次に形式と色空間ペアを列挙します。
desc.format = AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM; if (AHardwareBuffer_isSupported(&desc) && rgba10x6_formats_ext) { all_formats.emplace_back( VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}); if (colorspace_ext) { all_formats.emplace_back( VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, VK_COLOR_SPACE_PASS_THROUGH_EXT}); all_formats.emplace_back( VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}); }
互換性のある形式と色空間ペアについての知識が必要となります。
- 新しい形式を
external/deqp
にあるdEQP-VK
に追加します。 - 既存のソースから必要な変更を推測するか、Android サポートに問い合わせて情報を入手し、
vktApiExternalMemoryTests.cpp
とvktExternalMemoryUtil.cpp
の Vulkan 適合性テストを更新します。
新しいピクセル形式のための EGL での変更
EGL を次のように更新します。
getNativePixelFormat()
関数でif-else
ツリーを修正して、新しいピクセル形式の AIDL 形式を返すようにします。RGBA_8888
ピクセル形式の例を使用します。if (a == 0) { ... } else { if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { if (colorDepth > 24) { ... } else { *format = PixelFormat::RGBA_8888; } } else { ... } }
- 新しい形式を dEQP に追加するには、以下のように新しいエントリを
androidFormats
列挙型に追加します。static const GLenum androidFormats[] = { ... GL_RGBA8, ... };
アップデートを送信する
コントリビューターの手順に沿って、変更リストをスピンアップし、適切なチームと共有します。