إضافة تنسيقات بكسل جديدة إلى Android

يجب تضمين جميع تنسيقات البكسل الجديدة التي تمت إضافتها إلى Android في ملف لغة تعريف واجهة Android (AIDL) ومخازن الأجهزة في Android (AHB). تتطلب كل من AIDL وAHB متطلبات صارمة بشأن ثبات النظام وتوحيد معاييره، وتتطلّب إجراءات دقيقة عند توسيع نطاق الوظائف. يجب أن يتم طرح جميع تنسيقات البكسل الجديدة في AOSP ويجب أن يؤكّد خبراء AIDL وAHB كل التحديثات بشكلٍ فردي. تعد عملية التأكيد الدقيقة هذه عاملاً مهمًا في توحيد أي تنسيقات بكسل جديدة على نظام التشغيل.

توضِّح هذه الصفحة التغييرات اللازمة في رمز AOSP والعملية المطلوبة لإضافة تنسيقات بكسل جديدة على AOSP.

قبل إضافة تنسيق بكسل جديد، نزِّل المصدر وحمِّل الرموز البرمجية كما هو موضّح في مقالة إرسال الرموز البرمجية.

إضافة تنسيق بكسل جديد إلى تنسيق AIDL

تتطلّب إضافة دعم لتنسيق بكسل جديد إجراء تغييرات على كل من ملفَي PixelFormat.aidl ضمن AIDL. اطّلِع على hardware/interfaces/graphics/common/aidl/ للاطّلاع على رمز المصدر لـ 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. يُرجى الانتقال إلى frameworks/native/libs/nativewindow للاطّلاع على رمز المصدر AHB.

لإضافة تنسيق بكسل جديد إلى 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. يمكنك إضافة تنسيق البكسل الجديد إلى حزمة تطوير البرامج (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.

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

إضافة تنسيق بكسل جديد إلى دمج نظام Windows

لاستخدام تنسيق البكسل الجديد كتنسيق لإطار عرض في واجهة برمجة تطبيقات الرسومات، أضِفه إلى عملية دمج نظام النوافذ (WSI) المناسبة لواجهة برمجة تطبيقات الرسومات ذات الصلة. بالنسبة إلى عملية تطبيق أو نظام تستخدم واجهة برمجة التطبيقات Vulkan، عليك تعديل سلسلة التبديل Vulkan Swapchain. بالنسبة إلى عملية تطبيق أو نظام تستخدِم واجهة برمجة التطبيقات 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,
      ...
    };
    

إرسال التعديل

اتّبِع الخطوات التالية للمساهمين لإنشاء قوائم التغييرات ومشاركتها مع الفريق المناسب.