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. AIDL und AHB unterliegen strengen Stabilitäts- und Standardisierungsanforderungen, die bei der Erweiterung der Funktionalität einen sorgfältigen Prozess erfordern. Alle neuen Pixelformate müssen in AOSP aufgenommen werden und alle Updates müssen einzeln von AIDL- und AHB-Experten bestätigt werden. Dieser Prozess der sorgfältigen Bestätigung ist 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 Patches wie unter Patches einreichen beschrieben hoch.

Neues Pixelformat zu AIDL hinzufügen

Wenn Sie Unterstützung für ein neues Pixelformat hinzufügen möchten, müssen Sie beide PixelFormat.aidl-Dateien in AIDL ändern. Den AIDL-Quellcode finden Sie unter hardware/interfaces/graphics/common/aidl/.

So fügen Sie AIDL ein neues Pixelformat hinzu:

  1. Hängen Sie das neue Pixelformat als neuen Eintrag an das Ende des PixelFormat-Enum in PixelFormat.aidl an. Halten Sie sich dabei an die vorhandene Codekonvention und legen Sie den Hexadezimalwert für Ihren Eintrag auf eins mehr als den vorherigen Eintrag fest. Passen Sie die Codeänderungen an die vorherigen Einträge an. Hier ein Beispiel für den RGBA_8888-Eintrag für das Pixelformat:
    /**
     * 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 vorgenommen haben:

    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. Führen Sie den folgenden Befehl aus, um diesen Fehler zu beheben und PixelFormat.aidl im Verzeichnis aidl_api zu ändern, wie in der Fehlermeldung angegeben:

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

    Durch Ausführen des oben genannten Befehls wird die richtige Datei aktualisiert, sodass die Erstellung normal erfolgen kann.

Neues Pixelformat zu AHB hinzufügen

Wenn Sie Unterstützung für ein neues Pixelformat hinzufügen, 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 Pixel-Formal hinzu:

  1. Fügen Sie in hardware_buffer.h das neue Pixelformat als neuen Eintrag am Ende des AHardwareBuffer_Format-Enums hinzu. Halten Sie sich an die vorhandenen Codekonventionen.

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

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

    Das neue Pixelformat erhält in AHB einen Namen, der mit AHARDWAREBUFFER_FORMAT_ beginnt, gefolgt von den Kanalabkürzungen und Bittiefen und endend mit der Codierung. Dieser Enum-Eintrag muss denselben Hexadezimalwert wie in PixelFormat.aidl haben.

    Das Pixelformat muss ein zugehöriges Vulkan- oder OpenGL ES-Format haben. Geben Sie gegebenenfalls das zugehörige Format an. Wenn kein zugehöriges Format vorhanden ist, geben Sie N/A an.

  2. Fügen Sie das Pixelformat optionalen Tests unter CTS hinzu, wenn es ein zugehöriges OpenGL ES-Format hat. Fügen Sie dazu das neue GL-Format in AHardwareBufferGLTest.cpp in AHBFormatAsString(int32_t format) mit FORMAT_CASE(...) und GL_FORMAT_CASE(...) für das neue Format ein, wie unten gezeigt:

    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 einen neuen Test zu AHardwareBufferGLTest.cpp 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 Zusicherungen, die sich in Folgendem befinden:

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

    Hängen Sie ein neues static_assert für das neue Pixelformat an. Verwenden Sie dazu das PixelFormat::-Enum und nicht die HAL_PIXEL_FORMAT-Konstante. Fügen Sie den neuen Pixelformat-Eintrag mit demselben Beispiel für das Pixelformat RGBA_8888 aus AIDL ein neues Pixelformat hinzufügen so 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 es am Ende von PrintAhbFormat() in AHardwareBufferTest.cpp anhängen. Halten Sie sich an die vorhandene Codekonvention, wie unten gezeigt:

    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, indem Sie @IntDef einen neuen Eintrag hinzufügen. Der Eintrag für das RGBA_8888-Format sieht beispielsweise so aus:

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

    Wenn die Komponentenwerte nicht normalisiert sind, geben Sie den Wert explizit im Variablennamen an. Der Variablenname für einen 16-Bit-Rotkanal im Format „Unsigned Integer“ muss beispielsweise R_16UI lauten. Für dasselbe Format mit einem zusätzlichen 16-Bit-Grünkanal im Format „Unsigned Integer“ muss er RG_16UI16UI lauten.

  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 PixelFormat.aidl und hardware_buffer.h haben. Halten Sie sich an bestehende Konventionen.

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

    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.
    ******************************
    ...
    

    Führen Sie den folgenden Befehl aus, um diesen Fehler zu beheben und current.txt zu ändern:

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

    Durch Ausführen des oben genannten Befehls wird die richtige Datei aktualisiert, sodass die Erstellung normal erfolgen kann.

  9. Fügen Sie das neue Pixelformat den Java-Tests hinzu, indem Sie es am Ende von paramsForTestCreateOptionalFormats() in HardwareBufferTest.java anhängen, wie unten gezeigt:

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

Neues Pixelformat zur Window System-Integration hinzufügen

Wenn Sie das neue Pixelformat als Format für einen Framebuffer in einer Grafik-API verwenden möchten, fügen Sie es der entsprechenden WSI (Window System Integration) für die relevante Grafik-API hinzu. Aktualisieren Sie für eine App oder einen Systemprozess, der die Vulkan API verwendet, die Vulkan-Swapchain. Wenn eine App oder ein Systemprozess die OpenGL ES API verwendet, aktualisieren Sie die EGL API.

Vulkan WSI-Änderungen für neue Pixelformate

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

    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. Fragen Sie die Vulkan-Erweiterung ab, wenn für das Pixelformat eine Vulkan-Erweiterung erforderlich ist. Verwenden Sie für Seitenrand-Erweiterungen instance_data, wie unten 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 erforderlich ist, um eine Instanz- oder Geräteerweiterung für swapchain.cpp verfügbar zu machen. Die anfängliche Änderungsliste ist nicht erforderlich, damit die Erweiterungen korrekt über den Vulkan-Loader eingerichtet werden.

  3. Als Nächstes werden die Format- und Farbraum-Paare aufgelistet:
    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 die kompatiblen Format- und Farbraum-Paare kennen.

  4. Fügen Sie das neue Format der Datei 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 dem vorhandenen Quellcode ableiten oder sich an den Android-Support wenden, um Informationen zu erhalten.

EGL-Änderungen für neue Pixelformate

Aktualisieren Sie die EGL so:

  1. Ändern Sie in der Funktion getNativePixelFormat() den if-else-Baum, um das AIDL-Enum für das neue Pixelformat zurückzugeben. 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. Fügen Sie der dEQP-Datei einen neuen Eintrag für das neue Format hinzu, wie unten gezeigt:androidFormats
    static const GLenum androidFormats[] =
    {
      ...
      GL_RGBA8,
      ...
    };
    

Update einreichen

Für Mitwirkende