Добавьте новые форматы пикселей в Android

Все новые форматы пикселей, добавляемые в Android, должны быть включены в язык определения интерфейса Android (AIDL) и в аппаратный буфер Android (AHB) . AIDL и AHB предъявляют строгие требования к стабильности и стандартизации, что требует тщательного процесса расширения функциональности. Все новые форматы пикселей должны быть добавлены в AOSP, а все обновления должны быть индивидуально подтверждены экспертами AIDL и AHB. Этот процесс тщательного подтверждения является важным фактором стандартизации любых новых форматов пикселей на платформе.

На этой странице описаны необходимые изменения кода AOSP и процесс, необходимый для добавления новых форматов пикселей в AOSP.

Прежде чем добавлять новый формат пикселей, загрузите исходный код и загрузите исправления, как описано в разделе «Отправка исправлений» .

Добавьте новый формат пикселей в AIDL

Добавление поддержки нового формата пикселей требует внесения изменений в оба файла PixelFormat.aidl , расположенные в AIDL. Исходный код AIDL см. в разделе hardware/interfaces/graphics/common/aidl/ .

Чтобы добавить новый пиксель в AIDL, выполните следующие действия:

  1. Добавьте новый формат пикселей в качестве новой записи в конец перечисления PixelFormat в PixelFormat.aidl , следуя существующему соглашению о коде и установив шестнадцатеричное значение для вашей записи на единицу больше, чем предыдущая запись. Сопоставьте изменения кода с предыдущими записями. См. следующий пример записи формата пикселей 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,
    

    Следующее сообщение об ошибке отображается при сборке кода после внесения изменений в 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. Чтобы устранить эту ошибку, выполните следующую команду, как указано в сообщении об ошибке, чтобы изменить PixelFormat.aidl в каталоге aidl_api :

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

    Выполнение приведенной выше команды обновляет правильный файл, чтобы его можно было нормально построить.

Добавьте новый формат пикселей в AHB

Добавление поддержки нового формата пикселей требует изменений в hardware_buffer.h и AHardwareBuffer.cpp . Исходный код AHB см. в frameworks/native/libs/nativewindow .

Чтобы добавить новый формальный пиксель в AHB, выполните следующие действия:

  1. В hardware_buffer.h добавьте новый формат пикселей в качестве новой записи в конец перечисления AHardwareBuffer_Format . Следуйте существующим соглашениям кода.

    Используя пример формата пикселей RGBA_8888 , добавьте новую запись формата пикселей следующим образом:

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

    Обратите внимание, что новому формату пикселей присваивается имя в AHB, которое должно начинаться с AHARDWAREBUFFER_FORMAT_ , за которым следуют сокращения каналов и разрядность, и заканчивать кодировкой. Эта запись перечисления должна иметь то же шестнадцатеричное значение, что и в PixelFormat.aidl .

    Ожидается, что формат пикселей будет иметь один или оба связанных формата Vulkan или OpenGL ES . При необходимости укажите связанный формат. Если связанного формата не существует, укажите N/A .

  2. Добавьте формат пикселей в дополнительное тестирование в рамках CTS, если он связан с форматом OpenGL ES. Для этого добавьте новый формат GL в AHardwareBufferGLTest.cpp в AHBFormatAsString(int32_t format) с FORMAT_CASE(...) и GL_FORMAT_CASE(...) для нового формата, как показано ниже:

    const char* AHBFormatAsString(int32_t format) {
      switch (format) {
          ...
          FORMAT_CASE(R8G8B8A8_UNORM);
          ...
          GL_FORMAT_CASE(GL_RGB8);
      }
      return "";
    }
    
  3. Затем добавьте новый тест в AHardwareBufferGLTest.cpp , как показано ниже:

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

    Укажите хотя бы один набор значений AHardwareBuffer_Desc . При необходимости добавьте дополнительные значения.

  4. В AHardwareBuffer.cpp найдите конец статических утверждений, найденных внутри:

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

    Добавьте новый static_assert для нового формата пикселей, используя перечисление PixelFormat:: , а не константу HAL_PIXEL_FORMAT . Используя тот же пример для формата пикселей RGBA_8888 из раздела «Добавление нового формата пикселей в AIDL» , добавьте запись нового формата пикселей следующим образом:

    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. Добавьте новый формат пикселей в соответствующие тесты, добавив новый формат пикселей в конец PrintAhbFormat() в AHardwareBufferTest.cpp . Следуйте существующему соглашению о коде, как показано ниже:

    void PrintAhbFormat(std::ostream& os, uint64_t format) {
        switch (format) {
            ...
            FORMAT_CASE(R8G8B8A8_UNORM);
            default: os << "unknown"; break;
        }
    }
    
  6. Добавьте новый формат пикселей в HardwareBuffer SDK в HardwareBuffer.java : добавив новую запись в @IntDef . Например, запись для формата RGBA_8888 отображается следующим образом:

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

    Если значения компонентов не являются беззнаковыми, нормализованными, то укажите значение явно в имени переменной. Например, имя переменной для формата 16-битного красного канала без знака должно быть R_16UI , а тот же формат с дополнительным форматом 16-битного зеленого канала без знака должен быть RG_16UI16UI .

  7. Добавьте новый формат пикселей как static int в HardwareBuffer.java , добавив новую общедоступную переменную-член в конце @Format :

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

    Эта запись перечисления должна иметь то же шестнадцатеричное значение, что и в PixelFormat.aidl и hardware_buffer.h . Следуйте существующим соглашениям.

  8. Попытка сборки с этими изменениями кода приводит к ошибке сборки:

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

    Чтобы устранить эту ошибку, выполните следующую команду, указанную в сообщении об ошибке, чтобы изменить current.txt :

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

    Выполнение приведенной выше команды обновляет правильный файл, чтобы его можно было нормально построить.

  9. Добавьте новый формат пикселей в тесты Java, добавив новый формат пикселей в конец paramsForTestCreateOptionalFormats() в HardwareBufferTest.java , как показано ниже:

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

Добавьте новый формат пикселей в интеграцию с оконной системой.

Чтобы использовать новый формат пикселей в качестве формата кадрового буфера в графическом API, добавьте его в соответствующую интеграцию оконной системы (WSI) для соответствующего графического API. Для приложения или системного процесса, использующего Vulkan API, обновите Vulkan Swapchain. Для приложения или системного процесса, использующего API OpenGL ES, обновите API EGL .

Изменения Vulkan WSI для новых форматов пикселей

Обновите Vulkan WSI следующим образом:
  1. Добавьте новый регистр в функцию GetNativePixelFormat(VkFormat format) в 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. Запросите расширение Vulkan, если формат пикселей требует для работы расширения Vulkan. Для расширений на стороне экземпляра используйте instance_data , как показано ниже:
    bool colorspace_ext = instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
    

    Для расширений на стороне устройства используйте следующее:

    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 управляет инфраструктурой, необходимой для предоставления экземпляра или расширения устройства для swapchain.cpp . Первоначальный список изменений не требуется для правильной настройки расширений из загрузчика Vulkan.

  3. Затем перечислите пары формата и цветового пространства:
    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});
    }
    

    Вы должны знать совместимые пары форматов и цветовых пространств.

  4. Добавьте новый формат в dEQP-VK , расположенный по адресу external/deqp .
  5. Обновите тесты соответствия Vulkan в vktApiExternalMemoryTests.cpp и vktExternalMemoryUtil.cpp , выделив необходимые изменения из существующего источника или обратившись за информацией в службу поддержки Android.

Изменения EGL для новых форматов пикселей

Обновите EGL следующим образом:

  1. В функции getNativePixelFormat() измените дерево if-else , чтобы оно возвращало перечисление AIDL для нового формата пикселей. На примере формата пикселей RGBA_8888 :
    if (a == 0) {
      ...
    } else {
      if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
          if (colorDepth > 24) {
              ...
          } else {
              *format = PixelFormat::RGBA_8888;
          }
      } else {
        ...
      }
    }
    
  2. Чтобы добавить новый формат в dEQP, добавьте новую запись в перечисление androidFormats , как показано ниже:
    static const GLenum androidFormats[] =
    {
      ...
      GL_RGBA8,
      ...
    };
    

Отправьте свое обновление

Следуйте инструкциям для участников , чтобы составить списки изменений и поделиться ими с соответствующей командой.