Aggiungere nuovi formati pixel ad Android

Tutti i nuovi formati pixel aggiunti ad Android devono essere inclusi in Android Interface Definition Language (AIDL) e in Android Hardware Buffer (AHB). AIDL e AHB hanno requisiti di stabilità e standardizzazione rigorosi che richiedono un processo attento quando si estendono le funzionalità. Tutti i nuovi formati pixel devono essere inclusi in AOSP e tutti gli aggiornamenti devono essere confermati singolarmente dagli esperti di AIDL e AHB. Questo processo di conferma attenta è un fattore importante per la standardizzazione di tutti i nuovi formati pixel sulla piattaforma.

Questa pagina descrive le modifiche al codice AOSP necessarie e la procedura richiesta per aggiungere nuovi formati pixel in AOSP.

Prima di aggiungere un nuovo formato pixel, scarica l'origine e carica le patch come descritto in Invio di patch.

Aggiungere un nuovo formato pixel ad AIDL

L'aggiunta del supporto per un nuovo formato pixel richiede modifiche a entrambi i file PixelFormat.aidl che si trovano all'interno di AIDL. Per il codice sorgente AIDL, consulta hardware/interfaces/graphics/common/aidl/.

Per aggiungere un nuovo formato pixel ad AIDL:

  1. Aggiungi il nuovo formato pixel come nuova voce alla fine dell'enumerazione PixelFormat in PixelFormat.aidl seguendo la convenzione di codice esistente e impostando il valore esadecimale della voce in modo che sia uno in più rispetto alla voce precedente. Abbina le modifiche al codice alle voci precedenti. Vedi l'esempio seguente per la voce del formato pixel 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,
    

    Quando crei il codice dopo aver apportato modifiche a PixelFormat.aidl, viene visualizzato il seguente messaggio di errore:

    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. Per eliminare questo errore, esegui il comando seguente, come specificato nel messaggio di errore, per modificare PixelFormat.aidl nella directory aidl_api:

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

    L'esecuzione del comando precedente aggiorna il file corretto per consentire la creazione normalmente.

Aggiungere un nuovo formato pixel ad AHB

L'aggiunta del supporto per un nuovo formato pixel richiede modifiche a hardware_buffer.h e AHardwareBuffer.cpp. Per il codice sorgente AHB, consulta frameworks/native/libs/nativewindow.

Per aggiungere un nuovo formato pixel ad AHB:

  1. In hardware_buffer.h, aggiungi il nuovo formato pixel come nuova voce alla fine dell'enumerazione AHardwareBuffer_Format. Segui le convenzioni di codice esistenti.

    Utilizzando l'esempio del formato pixel RGBA_8888, aggiungi la nuova voce del formato pixel come segue:

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

    Tieni presente che al nuovo formato pixel viene assegnato un nome in AHB, che deve iniziare con AHARDWAREBUFFER_FORMAT_, seguito dalle abbreviazioni dei canali e dalle profondità di bit e terminare con la codifica. Questa voce di enumerazione deve avere lo stesso valore esadecimale di quella in PixelFormat.aidl.

    È previsto che il formato pixel abbia uno o entrambi i formati Vulkan o OpenGL ES associati. Specifica il formato associato, se appropriato. Se non esiste un formato associato, specifica N/A.

  2. Aggiungi il formato pixel ai test facoltativi in CTS, se ha un formato OpenGL ES associato. Per farlo, aggiungi il nuovo formato GL a AHardwareBufferGLTest.cpp in AHBFormatAsString(int32_t format) con FORMAT_CASE(...) e GL_FORMAT_CASE(...) per il nuovo formato, come mostrato di seguito:

    const char* AHBFormatAsString(int32_t format) {
      switch (format) {
          ...
          FORMAT_CASE(R8G8B8A8_UNORM);
          ...
          GL_FORMAT_CASE(GL_RGB8);
      }
      return "";
    }
    
  3. Poi, aggiungi un nuovo test a AHardwareBufferGLTest.cpp, come mostrato di seguito:

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

    Specifica almeno un insieme di valori AHardwareBuffer_Desc. Se necessario, aggiungi altri valori.

  4. In AHardwareBuffer.cpp, trova la fine delle asserzioni statiche all'interno di:

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

    Aggiungi una nuova static_assert per il nuovo formato pixel, utilizzando l'enumerazione PixelFormat:: e non la costante HAL_PIXEL_FORMAT. Utilizzando lo stesso esempio per il formato pixel RGBA_8888 da Aggiungere un nuovo formato pixel ad AIDL, aggiungi la nuova voce del formato pixel come segue:

    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. Aggiungi il nuovo formato pixel ai test appropriati, aggiungendolo alla fine di PrintAhbFormat() in AHardwareBufferTest.cpp. Segui la convenzione di codice esistente, come mostrato di seguito:

    void PrintAhbFormat(std::ostream& os, uint64_t format) {
        switch (format) {
            ...
            FORMAT_CASE(R8G8B8A8_UNORM);
            default: os << "unknown"; break;
        }
    }
    
  6. Aggiungi il nuovo formato pixel all'HardwareBuffer SDK in HardwareBuffer.java: aggiungendo una nuova voce a @IntDef. Ad esempio, la voce per il formato RGBA_8888 è mostrata di seguito:

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

    Se i valori dei componenti non sono normalizzati senza segno, indica il valore in modo esplicito nel nome della variabile. Ad esempio, il nome della variabile per un formato solo canale rosso a 16 bit intero senza segno deve essere R_16UI e lo stesso formato con un formato canale verde a 16 bit intero senza segno aggiuntivo deve essere RG_16UI16UI.

  7. Aggiungi il nuovo formato pixel come static int in HardwareBuffer.java, aggiungendo una nuova variabile membro pubblica alla fine di @Format:

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

    Questa voce di enumerazione deve avere lo stesso valore esadecimale di quella in PixelFormat.aidl e hardware_buffer.h. Segui le convenzioni esistenti.

  8. Se tenti di creare con queste modifiche al codice, si genera un errore di compilazione:

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

    Per eliminare questo errore, esegui il comando seguente, come specificato nel messaggio di errore, per modificare current.txt:

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

    L'esecuzione del comando precedente aggiorna il file corretto per consentire la creazione normalmente.

  9. Aggiungi il nuovo formato pixel ai test Java aggiungendolo alla fine di paramsForTestCreateOptionalFormats() in HardwareBufferTest.java, come mostrato di seguito:

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

Aggiungere un nuovo formato pixel all'integrazione del sistema di finestre

Per utilizzare il nuovo formato pixel come formato per un framebuffer in un'API grafica, aggiungilo all'integrazione del sistema di finestre (WSI) appropriata per l'API grafica pertinente. Per un'app o un processo di sistema che utilizza l'API Vulkan, aggiorna la catena di scambio Vulkan. Per un'app o un processo di sistema che utilizza l'API OpenGL ES, aggiorna la EGL API.

Modifiche WSI Vulkan per i nuovi formati pixel

Aggiorna la WSI Vulkan come segue:

  1. Aggiungi un nuovo caso alla GetNativePixelFormat(VkFormat format) funzione 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. Esegui una query sull'estensione Vulkan se il formato pixel richiede un'estensione Vulkan per funzionare. Per le estensioni lato istanza, utilizza instance_data, come mostrato di seguito:
    bool colorspace_ext = instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
    

    Per le estensioni lato dispositivo, utilizza quanto segue:

    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 gestisce l'infrastruttura necessaria per esporre un'estensione di istanza o dispositivo a swapchain.cpp. L'elenco delle modifiche iniziale non richiede che le estensioni siano configurate correttamente dal caricatore Vulkan.

  3. Poi, enumera le coppie di formato e spazio colore:
    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});
    }
    

    Devi conoscere le coppie di formato compatibile e spazio colore.

  4. Aggiungi il nuovo formato a dEQP-VK che si trova in external/deqp.
  5. Aggiorna i test di conformità Vulkan in vktApiExternalMemoryTests.cpp e vktExternalMemoryUtil.cpp deducendo le modifiche richieste dall'origine esistente o contattando l'assistenza Android per informazioni.

Modifiche EGL per i nuovi formati pixel

Aggiorna EGL come segue:

  1. Nella getNativePixelFormat() funzione, modifica l'albero if-else per restituire l'enumerazione AIDL per il nuovo formato pixel.

    Utilizzando l'esempio per il formato pixel RGBA_8888:

    if (a == 0) {
      ...
    } else {
      if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
          if (colorDepth > 24) {
              ...
          } else {
              *format = PixelFormat::RGBA_8888;
          }
      } else {
        ...
      }
    }
    
  2. Per aggiungere il nuovo formato a dEQP, aggiungi una nuova voce all' androidFormats enumerazione, come mostrato di seguito:
    static const GLenum androidFormats[] =
    {
      ...
      GL_RGBA8,
      ...
    };
    

Inviare l'aggiornamento

Segui le istruzioni per i collaboratori per avviare gli elenchi delle modifiche e condividerli con il team appropriato.