Android neue Pixelformate hinzufügen

Alle neuen Pixelformate, die Android hinzugefügt werden, müssen in der Android Interface Definition Language (AIDL) und im Android Hardware Buffer (AHB) enthalten sein. Die AIDL und das AHB haben strenge Stabilitäts- und Standardisierungsanforderungen, die eine beim Erweitern der Funktionalität sorgfältig vorgehen. Alle neuen Pixelformate müssen in AOSP landen und alle Updates müssen einzeln von AIDL- und AHB-Experten bestätigt werden. Dieser Prozess der sorgfältigen Bestätigung ein wichtiger Faktor bei der Standardisierung neuer Pixelformate auf der Plattform.

Auf dieser Seite werden die erforderlichen AOSP-Codeänderungen und der Prozess zum Hinzufügen neuer Pixelformate in AOSP beschrieben.

Bevor Sie ein neues Pixelformat hinzufügen, laden Sie die Quelle herunter und laden Sie die Patches wie unter Patches einreichen beschrieben hoch.

AIDL ein neues Pixelformat hinzufügen

Um ein neues Pixelformat zu unterstützen, müssen PixelFormat.aidl-Dateien in AIDL. Weitere Informationen finden Sie unter hardware/interfaces/graphics/common/aidl/ für den AIDL-Quellcode.

Führen Sie die folgenden Schritte aus, um AIDL ein neues Pixelformal hinzuzufügen:

  1. Fügen Sie das neue Pixelformat als neuen Eintrag an das Ende der PixelFormat-Enumeration in PixelFormat.aidl an. Folgen Sie dabei der bestehenden Codekonvention und legen Sie den Hexadezimalwert für Ihren Eintrag um eins höher als den des vorherigen Eintrags fest. Gleichen Sie Ihre Codeänderungen mit den vorherigen Einträgen ab. Im folgenden Beispiel wird der Eintrag für das Pixelformat RGBA_8888 gezeigt:
    /**
     * 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,
    

    Die folgende Fehlermeldung wird angezeigt, wenn Sie den Code erstellen, nachdem Sie Änderungen an PixelFormat.aidl:

    android_developer:~/android/aosp-android-latest-release: 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.
    
  2. Um diesen Fehler zu beheben, führen Sie den folgenden Befehl aus, wie in der Fehlermeldung angegeben, PixelFormat.aidl im Verzeichnis aidl_api:

    m android.hardware.graphics.common-update-api
    

    Durch Ausführen des Befehls oben wird die richtige Datei aktualisiert, damit der Build normal ausgeführt werden kann.

Neues Pixelformat zu AHB hinzufügen

Wenn Sie die Unterstützung für ein neues Pixelformat hinzufügen möchten, müssen Sie hardware_buffer.h und AHardwareBuffer.cpp ändern. Den AHB-Quellcode finden Sie unter frameworks/native/libs/nativewindow.

So fügen Sie AHB ein neues Pixelformat hinzu:

  1. Hängen Sie in hardware_buffer.h das neue Pixelformat als neuen Eintrag am Ende des die Enum AHardwareBuffer_Format. Halten Sie sich an die bestehenden Codekonventionen.

    Fügen Sie anhand des Beispiels für das Pixelformat RGBA_8888 den neuen Eintrag für das Pixelformat so hinzu:

    /**
     * Corresponding formats:
     *   Vulkan: VK_FORMAT_R8G8B8A8_UNORM
     *   OpenGL ES: GL_RGBA8
     */
    AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1,
    

    Das neue Pixelformat erhält einen Namen in AHB, der mit AHARDWAREBUFFER_FORMAT_, gefolgt von den Kanalabkürzungen und dem Bit und endet mit der Codierung. Dieser enum-Eintrag muss die denselben Hexadezimalwert wie in PixelFormat.aidl.

    Das Pixelformat muss mit einem oder beiden der Formate Vulkan oder OpenGL ES verknüpft sein. Geben Sie gegebenenfalls das zugehörige Format an. Wenn kein zugehöriges Format vorhanden ist, geben Sie N/A

  2. Füge das Pixelformat zu optionalen Tests unter CTS hinzu, wenn es mit einem OpenGL ES-Format verknüpft ist. Fügen Sie dazu das neue GL-Format AHardwareBufferGLTest.cpp in AHBFormatAsString(int32_t format) mit FORMAT_CASE(...) und GL_FORMAT_CASE(...) für das neue Format:

    const char* AHBFormatAsString(int32_t format) {
      switch (format) {
          ...
          FORMAT_CASE(R8G8B8A8_UNORM);
          ...
          GL_FORMAT_CASE(GL_RGB8);
      }
      return "";
    }
    
  3. Fügen Sie als Nächstes AHardwareBufferGLTest.cpp einen neuen Test hinzu:

    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);
    

    Geben Sie mindestens einen Satz von AHardwareBuffer_Desc-Werten an. Fügen Sie bei Bedarf weitere Werte hinzu.

  4. Suchen Sie in AHardwareBuffer.cpp nach dem Ende der statischen Assertions:

    // ----------------------------------------------------------------------------
    // Validate hardware_buffer.h and PixelFormat.aidl agree
    // ----------------------------------------------------------------------------
    

    Fügen Sie eine neue static_assert für das neue Pixelformat an, wobei Sie das PixelFormat::-Enum und nicht die Konstante HAL_PIXEL_FORMAT verwenden. Unter Verwendung desselben Beispiels für das Pixelformat RGBA_8888 aus Fügen Sie ein neues Pixelformat zu AIDL hinzu. fügen Sie den neuen Pixelformateintrag wie folgt hinzu:

    static_assert(static_cast(aidl::android::hardware::graphics::common::PixelFormat::RGBA_8888) ==
      AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
    "HAL and AHardwareBuffer pixel format don't match");
    
  5. Fügen Sie das neue Pixelformat den entsprechenden Tests hinzu, indem Sie das neue Pixelformat am Ende anhängen. von PrintAhbFormat() Zoll AHardwareBufferTest.cpp Halten Sie sich an die bestehende Codekonvention (siehe unten):

    void PrintAhbFormat(std::ostream& os, uint64_t format) {
        switch (format) {
            ...
            FORMAT_CASE(R8G8B8A8_UNORM);
            default: os << "unknown"; break;
        }
    }
    
  6. Fügen Sie das neue Pixelformat dem HardwareBuffer SDK in HardwareBuffer.java hinzu: Fügen Sie @IntDef einen neuen Eintrag hinzu. Beispiel: Der Eintrag für die Das RGBA_8888-Format sieht so aus:

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = { "RGB", "BLOB", "YCBCR_", "D_", "DS_", "S_" }, value = {
      ...
      RGBA_8888,
    })
    

    Wenn die Komponentenwerte nicht signaturlos normalisiert sind, geben Sie den Wert explizit im Variablennamen an. Beispiel: Der Variablenname für ein Format mit nur einem 16‑Bit-Rotkanal mit einer ungeprüften Ganzzahl muss R_16UI sein. Das gleiche Format mit einem zusätzlichen 16‑Bit-Grünkanal mit einer ungeprüften Ganzzahl muss RG_16UI16UI sein.

  7. Fügen Sie das neue Pixelformat als static int in HardwareBuffer.java hinzu, indem Sie am Ende von @Format eine neue öffentliche Mitgliedsvariable anhängen:

    @Format
    ...
    /** Format: 8 bits each red, green, blue, alpha */
    public static final int RGBA_8888 = 0x1;
    

    Dieser Enum-Eintrag muss denselben Hexadezimalwert wie der von PixelFormat.aidl haben und hardware_buffer.h. Beachten Sie die bestehenden Konventionen.

  8. Wenn Sie versuchen, einen Build mit diesen Codeänderungen zu erstellen, wird ein Build-Fehler ausgegeben:

    android_developer:~/android/aosp-android-latest-release: 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.
    ******************************
    ...
    

    Um diesen Fehler zu beheben, führen Sie den folgenden Befehl aus, wie in der Fehlermeldung angegeben: zum Ändern current.txt:

    m api-stubs-docs-non-updatable-update-current-api
    

    Durch Ausführen des Befehls oben wird die richtige Datei aktualisiert, damit der Build normal ausgeführt werden kann.

  9. Fügen Sie das neue Pixelformat den Java-Tests hinzu, indem Sie es in HardwareBufferTest.java am Ende von paramsForTestCreateOptionalFormats() anhängen. Das sieht dann so aus:

    private static Object[] paramsForTestCreateOptionalFormats() {
      return new Integer[]{
          HardwareBuffer.RGBA_8888
      };
    

Fenstersystem-Integration ein neues Pixelformat hinzufügen

Um das neue Pixelformat als Format für einen Framebuffer in einem Grafik-API hinzufügen, fügen Sie sie der entsprechenden Window System Integration (WSI) für die jeweilige Grafik-API. Aktualisieren Sie für eine App oder einen Systemprozess, der die Vulkan API verwendet, die Vulkan-Swapchain. Aktualisieren Sie für eine App oder einen Systemprozess, die die OpenGL ES API verwendet, die EGL API

Änderungen bei Vulkan WSI für neue Pixelformate

Aktualisieren Sie die Vulkan-WSI so:
  1. Fügen Sie der Funktion GetNativePixelFormat(VkFormat format) einen neuen Fall hinzu in swapchain.cpp:

    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;
    }
    
  2. Rufe die Vulkan-Erweiterung ab, wenn für das Pixelformat eine Vulkan-Erweiterung erforderlich ist. Verwenden Sie beispielsweise instance_data für seitliche Erweiterungen, wie hier dargestellt:
    bool colorspace_ext = instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
    

    Verwenden Sie für geräteseitige Erweiterungen Folgendes:

    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 kümmert sich um die Infrastruktur, die zum Freigeben einer Instanz oder Geräteerweiterung erforderlich ist an swapchain.cpp. Die anfängliche Änderungsliste ist nicht erforderlich, um die Erweiterungen im Vulkan-Ladeprogramm korrekt einrichten.

  3. Listen Sie als Nächstes die Format- und Farbraumpaare auf:
    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});
    }
    

    Sie müssen über kompatible Format- und Farbraumpaare verfügen.

  4. Fügen Sie das neue Format dEQP-VK unter external/deqp hinzu.
  5. Aktualisieren Sie die Vulkan-Konformitätstests in vktApiExternalMemoryTests.cpp und vktExternalMemoryUtil.cpp, indem Sie die erforderlichen Änderungen aus der vorhandenen Quelle ableiten oder sich an den Android-Support wenden.

EGL-Änderungen für neue Pixelformate

Aktualisieren Sie die EGL so:

  1. Im getNativePixelFormat() ändern Sie den if-else-Baum so, dass die AIDL enum für das neue Pixelformat zurückgegeben wird. Beispiel für das Pixelformat RGBA_8888:
    if (a == 0) {
      ...
    } else {
      if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
          if (colorDepth > 24) {
              ...
          } else {
              *format = PixelFormat::RGBA_8888;
          }
      } else {
        ...
      }
    }
    
  2. Um das neue Format zu dEQP hinzuzufügen, fügen Sie dem androidFormats enum, wie hier gezeigt:
    static const GLenum androidFormats[] =
    {
      ...
      GL_RGBA8,
      ...
    };
    

Aktualisierung senden

Folgen Sie der Anleitung unter Für Mitwirkende, um Änderungslisten zu erstellen und mit dem entsprechenden Team zu teilen.