Ajouter de nouveaux formats de pixel à Android

Tous les nouveaux formats de pixels ajoutés à Android doivent être inclus dans le langage de définition d'interface Android (AIDL) et dans le tampon de matériel Android (AHB). L'AIDL et l'AHB sont soumis à des exigences strictes en matière de stabilité et de normalisation, ce qui nécessite un processus minutieux lors de l'extension des fonctionnalités. Tous les nouveaux formats de pixels doivent être intégrés à l'AOSP, et toutes les mises à jour doivent être confirmées individuellement par des experts AIDL et AHB. Ce processus de confirmation minutieux est un facteur important dans la normalisation de tous les nouveaux formats de pixels sur la plate-forme.

Cette page décrit les modifications de code AOSP nécessaires et le processus requis pour ajouter de nouveaux formats de pixels sur AOSP.

Avant d'ajouter un nouveau format de pixels, téléchargez la source et importez les correctifs comme indiqué dans Envoyer des correctifs.

Ajouter un nouveau format de pixels à l'AIDL

L'ajout de la prise en charge d'un nouveau format de pixels nécessite des modifications dans les deux fichiers PixelFormat.aidl situés dans l'AIDL. Consultez hardware/interfaces/graphics/common/aidl/ pour obtenir le code source de l'AIDL.

Pour ajouter un nouveau format de pixels à l'AIDL, procédez comme suit :

  1. Ajoutez le nouveau format de pixels en tant que nouvelle entrée à la fin de l'énumération PixelFormat dans PixelFormat.aidl en suivant la convention de code existante et en définissant la valeur hexadécimale de votre entrée sur une valeur supérieure à celle de l'entrée précédente. Faites correspondre les modifications de votre code aux entrées précédentes. Consultez l'exemple suivant pour l'entrée du format de pixels 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,
    

    Le message d'erreur suivant s'affiche lorsque vous compilez le code après avoir apporté des modifications à 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. Pour effacer cette erreur, exécutez la commande suivante, comme spécifié dans le message d'erreur, afin de modifier PixelFormat.aidl dans le répertoire aidl_api :

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

    L'exécution de la commande ci-dessus met à jour le fichier approprié pour permettre une compilation normale.

Ajouter un nouveau format de pixels à l'AHB

L'ajout de la prise en charge d'un nouveau format de pixels nécessite des modifications dans hardware_buffer.h et AHardwareBuffer.cpp. Consultez frameworks/native/libs/nativewindow pour obtenir le code source de l'AHB.

Pour ajouter un nouveau format de pixels à l'AHB, procédez comme suit :

  1. Dans hardware_buffer.h, ajoutez le nouveau format de pixels en tant que nouvelle entrée à la fin de l'énumération AHardwareBuffer_Format. Suivez les conventions de code existantes.

    En utilisant l'exemple du format de pixels RGBA_8888, ajoutez la nouvelle entrée de format de pixels comme suit :

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

    Notez que le nouveau format de pixels reçoit un nom dans l'AHB, qui doit commencer par AHARDWAREBUFFER_FORMAT_, suivi des abréviations de canal et des profondeurs de bits, et se terminer par l'encodage. Cette entrée d'énumération doit avoir la même valeur hexadécimale que celle de PixelFormat.aidl.

    Le format de pixels doit avoir un format Vulkan ou OpenGL ES associé, ou les deux. Spécifiez le format associé, le cas échéant. Si aucun format associé n'existe, spécifiez N/A.

  2. Ajoutez le format de pixels aux tests facultatifs sous CTS, s'il possède un format OpenGL ES associé. Pour ce faire, ajoutez le nouveau format GL à AHardwareBufferGLTest.cpp dans AHBFormatAsString(int32_t format) avec FORMAT_CASE(...) et GL_FORMAT_CASE(...) pour le nouveau format, comme indiqué ci-dessous :

    const char* AHBFormatAsString(int32_t format) {
      switch (format) {
          ...
          FORMAT_CASE(R8G8B8A8_UNORM);
          ...
          GL_FORMAT_CASE(GL_RGB8);
      }
      return "";
    }
    
  3. Ensuite, ajoutez un nouveau test à AHardwareBufferGLTest.cpp, comme indiqué ci-dessous :

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

    Spécifiez au moins un ensemble de valeurs AHardwareBuffer_Desc. Si nécessaire, ajoutez d'autres valeurs.

  4. Dans AHardwareBuffer.cpp, recherchez la fin des assertions statiques trouvées dans :

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

    Ajoutez une nouvelle static_assert pour le nouveau format de pixels, en utilisant l'énumération PixelFormat:: et non la constante HAL_PIXEL_FORMAT. En utilisant le même exemple pour le format de pixels RGBA_8888 que dans Ajouter un nouveau format de pixels à l'AIDL, ajoutez la nouvelle entrée de format de pixels comme suit :

    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. Ajoutez le nouveau format de pixels aux tests appropriés en l'ajoutant à la fin de PrintAhbFormat() dans AHardwareBufferTest.cpp. Suivez la convention de code existante, comme indiqué ci-dessous :

    void PrintAhbFormat(std::ostream& os, uint64_t format) {
        switch (format) {
            ...
            FORMAT_CASE(R8G8B8A8_UNORM);
            default: os << "unknown"; break;
        }
    }
    
  6. Ajoutez le nouveau format de pixels au HardwareBuffer SDK dans HardwareBuffer.java: en ajoutant une nouvelle entrée à @IntDef. Par exemple, l'entrée pour le format RGBA_8888 est présentée comme suit :

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

    Si les valeurs des composants ne sont pas normalisées sans signature, indiquez explicitement la valeur dans le nom de la variable. Par exemple, le nom de variable pour un format de canal rouge de 16 bits entier non signé uniquement doit être R_16UI, et le même format avec un format de canal vert de 16 bits entier non signé supplémentaire doit être RG_16UI16UI.

  7. Ajoutez le nouveau format de pixels en tant que static int dans HardwareBuffer.java, en ajoutant une nouvelle variable membre publique à la fin de @Format :

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

    Cette entrée d'énumération doit avoir la même valeur hexadécimale que celle de PixelFormat.aidl et hardware_buffer.h. Suivez les conventions existantes.

  8. Toute tentative de compilation avec ces modifications de code génère une erreur de compilation :

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

    Pour effacer cette erreur, exécutez la commande suivante, comme spécifié dans le message d'erreur, afin de modifier current.txt :

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

    L'exécution de la commande ci-dessus met à jour le fichier approprié pour permettre une compilation normale.

  9. Ajoutez le nouveau format de pixels aux tests Java en l'ajoutant à la fin de paramsForTestCreateOptionalFormats() dans HardwareBufferTest.java, comme indiqué ci-dessous :

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

Ajouter un nouveau format de pixels à l'intégration du système de fenêtres

Pour utiliser le nouveau format de pixels comme format pour un framebuffer dans une API graphique, ajoutez-le à l'intégration du système de fenêtres (WSI) appropriée pour l'API graphique concernée. Pour une application ou un processus système utilisant l'API Vulkan, mettez à jour la chaîne d'échange Vulkan. Pour une application ou un processus système utilisant l'API OpenGL ES, mettez à jour l' API EGL.

Modifications de la WSI Vulkan pour les nouveaux formats de pixels

Mettez à jour la WSI Vulkan comme suit :

  1. Ajoutez un nouveau cas à la GetNativePixelFormat(VkFormat format) fonction dans 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. Interrogez l'extension Vulkan si le format de pixels nécessite une extension Vulkan pour fonctionner. Pour les extensions côté instance, utilisez instance_data, comme indiqué ci-dessous :
    bool colorspace_ext = instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
    

    Pour les extensions côté appareil, utilisez les éléments suivants :

    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 gère l'infrastructure requise pour exposer une extension d'instance ou d'appareil à swapchain.cpp. La liste de modifications initiale n'a pas besoin que les extensions soient correctement configurées à partir du chargeur Vulkan.

  3. Ensuite, énumérez les paires de formats et d'espaces colorimétriques :
    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});
    }
    

    Vous devez connaître les paires de formats et d'espaces colorimétriques compatibles.

  4. Ajoutez le nouveau format à dEQP-VK situé à external/deqp.
  5. Mettez à jour les tests de conformité Vulkan dans vktApiExternalMemoryTests.cpp et vktExternalMemoryUtil.cpp en déduisant les modifications requises à partir de la source existante ou en contactant l'assistance Android pour obtenir des informations.

Modifications de l'EGL pour les nouveaux formats de pixels

Mettez à jour l'EGL comme suit :

  1. Dans la getNativePixelFormat() fonction, modifiez l'arborescence if-else pour renvoyer l'énumération AIDL pour le nouveau format de pixels.

    En utilisant l'exemple du format de pixels RGBA_8888 :

    if (a == 0) {
      ...
    } else {
      if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
          if (colorDepth > 24) {
              ...
          } else {
              *format = PixelFormat::RGBA_8888;
          }
      } else {
        ...
      }
    }
    
  2. Pour ajouter le nouveau format à dEQP, ajoutez une entrée à l' androidFormats énumération, comme indiqué ci-dessous :
    static const GLenum androidFormats[] =
    {
      ...
      GL_RGBA8,
      ...
    };
    

Envoyer votre mise à jour

Suivez les instructions pour les contributeurs afin de créer vos listes de modifications et de les partager avec l'équipe appropriée.