Añade nuevos formatos de píxeles a Android

Todos los nuevos formatos de píxeles agregados a Android deben incluirse en el lenguaje de definición de interfaz de Android (AIDL) y en el búfer de hardware de Android (AHB) . La AIDL y la AHB tienen estrictos requisitos de estabilidad y estandarización que requieren un proceso cuidadoso al ampliar la funcionalidad. Todos los nuevos formatos de píxeles deben llegar a AOSP y todas las actualizaciones deben ser confirmadas individualmente por los expertos de AIDL y AHB. Este proceso de confirmación cuidadosa es un factor importante para estandarizar cualquier formato de píxel nuevo en la plataforma.

Esta página describe los cambios necesarios en el código AOSP y el proceso requerido para agregar nuevos formatos de píxeles en AOSP.

Antes de agregar un nuevo formato de píxel, descargue la fuente y cargue los parches como se describe en Envío de parches .

Agregue un nuevo formato de píxel a AIDL

Agregar soporte para un nuevo formato de píxeles requiere cambios en ambos archivos PixelFormat.aidl ubicados dentro de AIDL. Consulte hardware/interfaces/graphics/common/aidl/ para ver el código fuente de AIDL.

Para agregar un nuevo píxel formal a AIDL, siga estos pasos:

  1. Agregue el nuevo formato de píxel como una nueva entrada al final de la enumeración PixelFormat en PixelFormat.aidl siguiendo la convención de código existente y configurando el valor hexadecimal de su entrada para que sea uno más que la entrada anterior. Haga coincidir los cambios de su código con las entradas anteriores. Consulte el siguiente ejemplo para la entrada de formato de píxeles 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,
    

    El siguiente mensaje de error aparece cuando crea el código después de realizar cambios en PixelFormat.aidl :

    android_developer:~/android/aosp-main: 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. Para borrar este error, ejecute el siguiente comando, como se especifica en el mensaje de error, para cambiar PixelFormat.aidl en el directorio aidl_api :

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

    Al ejecutar el comando anterior se actualiza el archivo correcto para poder compilarlo normalmente.

Agregue un nuevo formato de píxel a AHB

Agregar soporte para un nuevo formato de píxeles requiere cambios en hardware_buffer.h y AHardwareBuffer.cpp . Consulte frameworks/native/libs/nativewindow para ver el código fuente de AHB.

Para agregar un nuevo píxel formal a AHB, siga estos pasos:

  1. En hardware_buffer.h , agregue el nuevo formato de píxel como una nueva entrada al final de la enumeración AHardwareBuffer_Format . Siga las convenciones de código existentes.

    Utilizando el ejemplo de formato de píxeles RGBA_8888 , agregue la nueva entrada de formato de píxeles de la siguiente manera:

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

    Tenga en cuenta que el nuevo formato de píxeles recibe un nombre en AHB, que debe comenzar con AHARDWAREBUFFER_FORMAT_ , seguido de las abreviaturas del canal y las profundidades de bits, y terminar con la codificación. Esta entrada de enumeración debe tener el mismo valor hexadecimal que el de PixelFormat.aidl .

    Se espera que el formato de píxel tenga uno o ambos formatos Vulkan u OpenGL ES asociados. Especifique el formato asociado cuando corresponda. Si no existe ningún formato asociado, especifique N/A .

  2. Agregue el formato de píxel a las pruebas opcionales en CTS, si tiene un formato OpenGL ES asociado. Para hacer esto, agregue el nuevo formato GL a AHardwareBufferGLTest.cpp en AHBFormatAsString(int32_t format) con FORMAT_CASE(...) y GL_FORMAT_CASE(...) para el nuevo formato, como se muestra a continuación:

    const char* AHBFormatAsString(int32_t format) {
      switch (format) {
          ...
          FORMAT_CASE(R8G8B8A8_UNORM);
          ...
          GL_FORMAT_CASE(GL_RGB8);
      }
      return "";
    }
    
  3. A continuación, agregue una nueva prueba a AHardwareBufferGLTest.cpp , como se muestra a continuación:

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

    Especifique al menos un conjunto de valores AHardwareBuffer_Desc . Agregue más valores si es necesario.

  4. En AHardwareBuffer.cpp , busque el final de las afirmaciones estáticas que se encuentran dentro de:

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

    Agregue un nuevo static_assert para el nuevo formato de píxel, usando la enumeración PixelFormat:: y no con la constante HAL_PIXEL_FORMAT . Usando el mismo ejemplo para el formato de píxel RGBA_8888 de Agregar un nuevo formato de píxel a AIDL , agregue la nueva entrada de formato de píxel de la siguiente manera:

    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. Agregue el nuevo formato de píxel a las pruebas apropiadas, agregando el nuevo formato de píxel al final de PrintAhbFormat() en AHardwareBufferTest.cpp . Siga la convención de código existente, como se muestra a continuación:

    void PrintAhbFormat(std::ostream& os, uint64_t format) {
        switch (format) {
            ...
            FORMAT_CASE(R8G8B8A8_UNORM);
            default: os << "unknown"; break;
        }
    }
    
  6. Agregue el nuevo formato de píxel al SDK HardwareBuffer en HardwareBuffer.java : agregando una nueva entrada a @IntDef . Por ejemplo, la entrada para el formato RGBA_8888 se muestra a continuación:

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

    Si los valores de los componentes no están normalizados sin signo, indique el valor explícitamente en el nombre de la variable. Por ejemplo, el nombre de la variable para un formato único de canal rojo de 16 bits entero sin signo debe ser R_16UI , y el mismo formato con un formato de canal verde de 16 bits entero sin signo adicional debe ser RG_16UI16UI .

  7. Agregue el nuevo formato de píxel como un static int en HardwareBuffer.java , agregando una nueva variable miembro pública al final de @Format :

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

    Esta entrada de enumeración debe tener el mismo valor hexadecimal que el de PixelFormat.aidl y hardware_buffer.h . Siga las convenciones existentes.

  8. Intentar compilar con estos cambios de código genera un error de compilación:

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

    Para borrar este error, ejecute el siguiente comando, como se especifica en el mensaje de error, para cambiar current.txt :

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

    Al ejecutar el comando anterior se actualiza el archivo correcto para poder compilarlo normalmente.

  9. Agregue el nuevo formato de píxel a las pruebas de Java, agregando el nuevo formato de píxel al final de paramsForTestCreateOptionalFormats() en HardwareBufferTest.java , como se muestra a continuación:

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

Agregue un nuevo formato de píxeles a la integración del sistema Windows

Para utilizar el nuevo formato de píxeles como formato para un framebuffer en una API de gráficos, agréguelo a la integración del sistema de ventanas (WSI) adecuada para la API de gráficos correspondiente. Para una aplicación o proceso del sistema que utiliza la API de Vulkan, actualice Vulkan Swapchain. Para una aplicación o proceso del sistema que utiliza la API OpenGL ES, actualice la API EGL .

Vulkan WSI cambia para nuevos formatos de píxeles

Actualice Vulkan WSI de la siguiente manera:
  1. Agregue un nuevo caso a la función GetNativePixelFormat(VkFormat format) en 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. Consulte la extensión Vulkan si el formato de píxel requiere una extensión Vulkan para funcionar. Por ejemplo, extensiones laterales, use instance_data , que se muestra a continuación:
    bool colorspace_ext = instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
    

    Para extensiones del lado del dispositivo, utilice lo siguiente:

    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 maneja la infraestructura necesaria para exponer una instancia o extensión de dispositivo a swapchain.cpp . No se requiere la lista de cambios inicial para tener las extensiones configuradas correctamente desde el cargador Vulkan.

  3. A continuación, enumere los pares de formato y espacio de color:
    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});
    }
    

    Debe tener conocimiento de los pares de formatos y espacios de color compatibles.

  4. Agregue el nuevo formato a dEQP-VK ubicado en external/deqp .
  5. Actualice las pruebas de conformidad de Vulkan en vktApiExternalMemoryTests.cpp y vktExternalMemoryUtil.cpp infiriendo los cambios requeridos de la fuente existente o comunicándose con su soporte de Android para obtener información.

Cambios de EGL para nuevos formatos de píxeles

Actualice el EGL de la siguiente manera:

  1. En la función getNativePixelFormat() , modifique el árbol if-else para devolver la enumeración AIDL para el nuevo formato de píxel. Usando el ejemplo para el formato de píxeles RGBA_8888 :
    if (a == 0) {
      ...
    } else {
      if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
          if (colorDepth > 24) {
              ...
          } else {
              *format = PixelFormat::RGBA_8888;
          }
      } else {
        ...
      }
    }
    
  2. Para agregar el nuevo formato a dEQP, agregue una nueva entrada a la enumeración androidFormats , que se muestra a continuación:
    static const GLenum androidFormats[] =
    {
      ...
      GL_RGBA8,
      ...
    };
    

Envía tu actualización

Siga Para que los contribuyentes activen sus listas de cambios y las compartan con el equipo adecuado.