Все новые форматы пикселей, добавленные в Android, должны быть включены в язык описания интерфейсов Android (AIDL) и в аппаратный буфер Android (AHB). К AIDL и AHB предъявляются строгие требования в отношении стабильности и стандартизации, поэтому расширение их функциональности требует тщательного подхода. Все новые форматы пикселей должны быть добавлены в AOSP, а все обновления должны быть подтверждены экспертами по AIDL и AHB. Этот процесс тщательной проверки является важным фактором стандартизации любых новых форматов пикселей на платформе.
На этой странице описаны необходимые изменения кода AOSP и процесс добавления новых форматов пикселей в AOSP.
Прежде чем добавлять новый формат пикселей, скачайте исходный код и загрузите исправления, как описано в разделе Отправка исправлений.
Добавьте новый формат пикселей в AIDL
Чтобы добавить поддержку нового формата пикселей, необходимо внести изменения в оба файла PixelFormat.aidl, расположенные в AIDL. Исходный код AIDL можно найти на странице hardware/interfaces/graphics/common/aidl/.
Чтобы добавить новый формат пикселей в AIDL, выполните следующие действия:
- Добавьте новый формат пикселей в конец перечисления
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-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.
-
Чтобы устранить эту ошибку, выполните следующую команду, как указано в сообщении об ошибке, чтобы изменить
PixelFormat.aidlв каталогеaidl_api:m android.hardware.graphics.common-update-api
После выполнения указанной выше команды нужный файл будет обновлен, и вы сможете продолжить сборку.
Как добавить новый формат пикселей в AHB
Чтобы добавить поддержку нового формата пикселей, необходимо внести изменения в hardware_buffer.h и AHardwareBuffer.cpp.
Исходный код AHB можно найти в frameworks/native/libs/nativewindow.
Чтобы добавить новый формат пикселей в AHB, выполните следующие действия:
- В файле
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. -
Добавьте формат пикселей в необязательное тестирование в 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 ""; } -
Затем добавьте в
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. При необходимости добавьте другие значения. -
В
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"); -
Добавьте новый формат пикселей в конец
PrintAhbFormat()вAHardwareBufferTest.cpp. Соблюдайте существующие правила написания кода, как показано ниже:void PrintAhbFormat(std::ostream& os, uint64_t format) { switch (format) { ... FORMAT_CASE(R8G8B8A8_UNORM); default: os << "unknown"; break; } } -
Добавьте новый формат пикселей в SDK
HardwareBufferв файле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. -
Добавьте новый формат пикселя как
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. Следуйте существующим соглашениям. -
При попытке сборки с этими изменениями кода возникает ошибка:
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. ****************************** ...Чтобы устранить эту ошибку, выполните указанную в сообщении об ошибке команду, чтобы изменить
current.txt:m api-stubs-docs-non-updatable-update-current-api
После выполнения этой команды файл будет обновлен и сборка пройдет успешно.
-
Добавьте новый формат пикселей в тесты Java, добавив его в конец
paramsForTestCreateOptionalFormats()вHardwareBufferTest.java, как показано ниже:private static Object[] paramsForTestCreateOptionalFormats() { return new Integer[]{ HardwareBuffer.RGBA_8888 };
Как добавить новый формат пикселей в интеграцию с системным окном
Чтобы использовать новый формат пикселей в качестве формата для буфера кадра в графическом API, добавьте его в подходящую интеграцию с оконной системой (WSI) для нужного графического API. Для приложения или системного процесса, использующего Vulkan API, обновите Vulkan Swapchain. Для приложения или системного процесса, использующего OpenGL ES API, обновите EGL API.
Изменения в Vulkan WSI для новых форматов пикселей
Обновите WSI Vulkan следующим образом:
-
Добавьте в функцию
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; } - Запросите расширение 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::vectorprops(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 исходный список изменений не требуется. - Затем перечислите пары форматов и цветовых пространств:
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}); }Вы должны знать, какие форматы и цветовые пространства совместимы.
- Добавьте новый формат в файл
dEQP-VK, который находится в каталогеexternal/deqp. - Обновите тесты на соответствие Vulkan в
vktApiExternalMemoryTests.cppиvktExternalMemoryUtil.cpp. Для этого определите необходимые изменения на основе существующего источника или обратитесь в службу поддержки Android.
Изменения EGL для новых форматов пикселей
Обновите EGL следующим образом:
- В функции
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 { ... } } - Чтобы добавить новый формат в dEQP, добавьте новую запись в перечисление
androidFormats, как показано ниже:static const GLenum androidFormats[] = { ... GL_RGBA8, ... };
Как отправить запрос на обновление
Следуйте инструкциям в разделе Для авторов, чтобы создать списки изменений и поделиться ими с нужной командой.