Android neue Pixelformate hinzufügen

Alle neuen Pixelformate, die Android hinzugefügt werden, müssen in der Android Interface-Definitionssprache (AIDL) und im Android Hardware Buffer (AHB)enthalten sein. Für AIDL und AHB gelten strenge 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 sorgfältige Bestätigungsprozess ist ein wichtiger Faktor bei der Standardisierung neuer Pixelformate auf der Plattform.

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

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

Neues Pixelformat zu AIDL hinzufügen

Zum Hinzufügen der Unterstützung für ein neues Pixelformat sind Änderungen an beiden PixelFormat.aidl-Dateien in AIDL erforderlich. Siehe hardware/interfaces/graphics/common/aidl/ für den AIDL-Quellcode.

So fügen Sie AIDL ein neues Pixelformat hinzu:

  1. Hängen Sie das neue Pixelformat als neuen Eintrag am Ende der PixelFormat Enum in PixelFormat.aidl an. Folgen Sie dabei der vorhandenen Codekonvention und legen Sie den Hexadezimalwert für Ihren Eintrag um eins höher als den des vorherigen Eintrags fest. Passen Sie Ihre Codeänderungen an die vorherigen Einträge an. Im folgenden Beispiel sehen Sie den Eintrag für das Pixelformat 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,
    

    Beim Erstellen des Codes nach Änderungen an PixelFormat.aidl wird die folgende Fehlermeldung angezeigt:

    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. Der Befehl ist in der Fehlermeldung angegeben:

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

    Durch Ausführen des oben genannten Befehls wird die richtige Datei aktualisiert, damit Sie sie normal erstellen können.

Neues Pixelformat zu AHB hinzufügen

Zum Hinzufügen der Unterstützung für ein neues Pixelformat sind Änderungen an hardware_buffer.h und AHardwareBuffer.cpperforderlich. 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 der AHardwareBuffer_Format-Enum an. Folgen Sie dabei den vorhandenen Codekonventionen.

    Fügen Sie den neuen Eintrag für das Pixelformat mit dem Beispiel für das Pixelformat RGBA_8888 wie folgt 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_ beginnen muss, gefolgt von den Kanalabkürzungen und Bittiefen und mit der Codierung enden muss. Dieser Enum-Eintrag muss denselben Hexadezimalwert wie in PixelFormat.aidl haben.

    Das Pixelformat muss ein oder beide der zugehörigen Vulkan oder OpenGL ES Formate 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 unter CTS zu optionalen Tests hinzu, wenn es ein zugehöriges OpenGL ES-Format hat. Fügen Sie dazu das neue GL-Format zu AHardwareBufferGLTest.cpp in AHBFormatAsString(int32_t format) mit FORMAT_CASE(...) und GL_FORMAT_CASE(...) für das neue Format hinzu, 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, wie unten gezeigt:

    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 das Ende der statischen Zusicherungen in:

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

    Hängen Sie eine neue static_assert für das neue Pixelformat an. Verwenden Sie dabei die PixelFormat::-Enum und nicht die Konstante HAL_PIXEL_FORMAT. Fügen Sie den neuen Eintrag für das Pixelformat mit demselben Beispiel für das RGBA_8888 Pixelformat aus Neues Pixelformat zu AIDL hinzufügen, 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 es am Ende von PrintAhbFormat() in AHardwareBufferTest.cpp anhängen. Folgen Sie dabei der vorhandenen 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 anhängen. Der Eintrag für das Format RGBA_8888 sieht beispielsweise so aus:

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

    Wenn die Komponentenwerte nicht als nicht signierte normalisierte Werte angegeben sind, geben Sie den Wert explizit im Variablennamen an. Der Variablenname für ein Format mit nur einem nicht signierten 16-Bit-Rotkanal muss beispielsweise R_16UI sein. Für dasselbe Format mit einem zusätzlichen nicht signierten 16-Bit-Grünkanal muss der Variablenname RG_16UI16UI lauten.

  7. Fügen Sie das neue Pixelformat als static int in HardwareBuffer.java, hinzu, indem Sie @Format eine neue öffentliche Membervariable 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 in PixelFormat.aidl und hardware_buffer.h haben. Folgen Sie dabei den vorhandenen Konventionen.

  8. Wenn Sie versuchen, mit diesen Codeänderungen 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. Der Befehl ist in der Fehlermeldung angegeben: ändern

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

    Durch Ausführen des oben genannten Befehls wird die richtige Datei aktualisiert, damit Sie sie normal erstellen können.

  9. Fügen Sie das neue Pixelformat den Java-Tests hinzu, indem Sie es am Ende von paramsForTestCreateOptionalFormats() in HardwareBufferTest.java, 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 Window System Integration (WSI) für die relevante Grafik-API hinzu. 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, der die OpenGL ES-API verwendet, die EGL API.

Änderungen an der Vulkan-WSI für neue Pixelformate

Aktualisieren Sie die Vulkan-WSI so:

  1. Fügen Sie der GetNativePixelFormat(VkFormat format) Funktion 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 das Pixelformat eine Vulkan-Erweiterung benötigt, um zu funktionieren. Verwenden Sie für Erweiterungen auf Instanzseite instance_data, wie unten gezeigt:
    bool colorspace_ext = instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
    

    Verwenden Sie für Erweiterungen auf Geräteseite 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 ursprüngliche Änderungsliste muss nicht die Erweiterungen enthalten, die vom Vulkan-Ladeprogramm korrekt eingerichtet wurden.

  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 die kompatiblen Format- und Farbraumpaare kennen.

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

Änderungen an EGL für neue Pixelformate

Aktualisieren Sie EGL so:

  1. Ändern Sie in der getNativePixelFormat() Funktion die if-else Struktur, um die 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 androidFormats Enum einen neuen Eintrag hinzu, um das neue Format zu dEQP hinzuzufügen, wie unten gezeigt:
    static const GLenum androidFormats[] =
    {
      ...
      GL_RGBA8,
      ...
    };
    

Update einreichen

Folgen Sie der Anleitung für Mitwirkende , um Ihre Änderungslisten hochzufahren und sie für das entsprechende Team freizugeben.