إطار عمل المزامنة

يصف إطار المزامنة بشكل صريح التبعيات بين العمليات غير المتزامنة المختلفة في نظام الرسومات في Android. يوفّر إطار العمل واجهة برمجة تطبيقات تتيح للمكوّنات الإشارة إلى وقت تحرير المخازن المؤقتة. يسمح إطار العمل أيضًا بنقل عناصر المزامنة الأساسية بين برامج التشغيل من النواة إلى مساحة المستخدمين وبين عمليات مساحة المستخدمين نفسها.

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

يتيح إطار المزامنة أيضًا للمنفّذين الاستفادة من موارد المزامنة في مكونات الأجهزة الخاصة بهم. أخيرًا، يوفّر إطار العمل إمكانية الاطّلاع على مسار عرض الرسومات للمساعدة في تصحيح الأخطاء.

المزامنة الصريحة

تتيح المزامنة الصريحة لمنتجي مخازن مؤقتة للرسومات ومستهلكيها الإشارة إلى وقت الانتهاء من استخدام مخزن مؤقت. يتم تنفيذ المزامنة الصريحة في مساحة النواة.

تشمل مزايا المزامنة الواضحة ما يلي:

  • تفاوت أقل في السلوك بين الأجهزة
  • تحسين إمكانات تصحيح الأخطاء
  • مقاييس الاختبار المحسّنة

يتضمّن إطار المزامنة ثلاثة أنواع من العناصر:

  • sync_timeline
  • sync_pt
  • sync_fence

sync_timeline

sync_timeline هو مخطط زمني يتزايد بشكلٍ منتظم يجب أن ينفّذه المورّدون لكل مثيل برنامج تشغيل، مثل سياق GL أو وحدة التحكّم في العرض أو أداة blitter ثنائية الأبعاد. تعرض sync_timeline عدد المهام التي تم إرسالها إلى النواة لجزء معيّن من الأجهزة. توفّر sync_timeline ضمانات بشأن ترتيب العمليات وتتيح عمليات تنفيذ خاصة بالأجهزة.

اتّبِع الإرشادات التالية عند تنفيذ sync_timeline:

  • قدِّم أسماء مفيدة لجميع برامج التشغيل والمخططات الزمنية والحدود لتسهيل عملية تصحيح الأخطاء.
  • استخدِم عاملَي التشغيل timeline_value_str وpt_value_str في المخططات الزمنية لجعل ناتج تصحيح الأخطاء أكثر قابلية للقراءة.
  • نفِّذ عملية التعبئة driver_data لمنح مكتبات مساحة المستخدم، مثل مكتبة GL، إمكانية الوصول إلى بيانات المخطط الزمني الخاص، إذا أردت ذلك. تسمح السمة data_driver للمورّدين بنقل معلومات حول السمتَين غير القابلتَين للتغيير sync_fence وsync_pts لإنشاء أسطر الأوامر استنادًا إليهما.
  • عدم السماح لمساحة المستخدم بإنشاء سياج أو الإشارة إليه بشكل صريح يؤدي إنشاء الإشارات/الحواجز بشكل صريح إلى هجوم حجب خدمة يؤدي إلى إيقاف وظائف خط الأنابيب.
  • لا تصل إلى عناصر sync_timeline أو sync_pt أو sync_fence بشكل صريح. توفّر واجهة برمجة التطبيقات جميع الوظائف المطلوبة.

sync_pt

sync_pt هي قيمة أو نقطة واحدة على sync_timeline. تحتوي النقطة على ثلاث حالات: نشطة، وتمت الإشارة إليها، وحدث خطأ. تبدأ النقاط في الحالة النشطة وتنتقل إلى الحالة التي تم إرسال إشارة إليها أو حالة الخطأ. على سبيل المثال، عندما لا يحتاج مستهلك الصور إلى المخزن المؤقت، يتم إرسال إشارة sync_pt ليعرف منتج الصور أنّه يمكنه الكتابة في المخزن المؤقت مرة أخرى.

sync_fence

sync_fence هي مجموعة من قيم sync_pt التي غالبًا ما يكون لها أصول sync_timeline مختلفة (مثل وحدة التحكّم في العرض ووحدة معالجة الرسومات). ‫sync_fence وsync_pt وsync_timeline هي العناصر الأساسية التي تستخدمها برامج التشغيل ومساحة المستخدم للتعبير عن التبعيات. عندما يتم الإشارة إلى اكتمال السياج، يُضمن اكتمال جميع الأوامر الصادرة قبل السياج لأنّ برنامج تشغيل النواة أو وحدة الأجهزة ينفّذ الأوامر بالترتيب.

يتيح إطار المزامنة لجهات الإنتاج أو الاستهلاك المتعددة الإشارة إلى انتهاء استخدامها لمخزن مؤقت، وذلك من خلال نقل معلومات التبعية باستخدام مَعلمة دالة واحدة. يتم الاحتفاظ بحدود الأمان باستخدام واصف ملف ويتم تمريرها من مساحة النواة إلى مساحة المستخدم. على سبيل المثال، يمكن أن يحتوي السياج على قيمتَين sync_pt تشيران إلى الوقت الذي ينتهي فيه مستهلكان منفصلان للصور من قراءة المخزن المؤقت. عندما يتم إرسال إشارة السياج، يعرف منتجو الصور أنّ المستهلكَين قد انتهيا من استهلاك الصور.

تبدأ السياجات، مثل قيم sync_pt، في الحالة النشطة وتتغير حالتها استنادًا إلى حالة نقاطها. إذا أصبحت جميع قيم sync_pt مُشارًا إليها، سيصبح sync_fence مُشارًا إليه. إذا حدث خطأ في أحد sync_pt، سيحدث خطأ في sync_fence بأكمله.

لا يمكن تغيير عضوية sync_fence بعد إنشاء السياج الجغرافي. للحصول على أكثر من نقطة واحدة في سياج جغرافي، يتم دمج النقاط من سياجين جغرافيين مختلفين وإضافتها إلى سياج جغرافي ثالث. إذا تم الإشارة إلى إحدى هاتين النقطتين في السياج الأصلي ولم يتم الإشارة إلى النقطة الأخرى، لن يكون السياج الثالث في حالة تم الإشارة إليها أيضًا.

لتنفيذ المزامنة الضمنية، قدِّم ما يلي:

  • نظام فرعي في مساحة النواة ينفّذ إطار عمل المزامنة لبرنامج تشغيل أجهزة معيّن. إنّ برامج التشغيل التي يجب أن تكون على دراية بالحواجز هي بشكل عام أي برامج تصل إلى Hardware Composer أو تتواصل معه. تشمل الملفات الرئيسية ما يلي:
    • التنفيذ الأساسي:
      • kernel/common/include/linux/sync.h
      • kernel/common/drivers/base/sync.c
    • المستندات في kernel/common/Documentation/sync.txt
    • مكتبة للتواصل مع مساحة النواة في platform/system/core/libsync
  • يجب أن يوفّر المورّد حواجز المزامنة المناسبة كمعلَمات للدالتَين validateDisplay() وpresentDisplay() في طبقة HAL.
  • إضافتان مرتبطتان بالحواجز في GL (EGL_ANDROID_native_fence_sync وEGL_ANDROID_wait_sync) وإتاحة الحواجز في برنامج تشغيل الرسومات

دراسة حالة: تنفيذ برنامج تشغيل شاشة عرض

لاستخدام واجهة برمجة التطبيقات التي تتيح وظيفة المزامنة، يجب تطوير برنامج تشغيل شاشة يتضمّن وظيفة ذاكرة تخزين مؤقت للشاشة. قبل توفّر إطار عمل المزامنة، كانت هذه الدالة تتلقّى عناصر dma-buf، وتضع المخازن المؤقتة على الشاشة، وتحظر أثناء ظهور المخزن المؤقت. على سبيل المثال:

/*
 * assumes buffer is ready to be displayed.  returns when buffer is no longer on
 * screen.
 */
void display_buffer(struct dma_buf *buffer);

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

لا يؤدي وضع العمل في قائمة الانتظار وبدء تنفيذه بعد إزالة السياج الجغرافي إلى حظر أي شيء. يجب إرجاع السياج الخاص بك على الفور، ما يضمن عدم عرض المخزن المؤقت على الشاشة. أثناء وضع المخازن المؤقتة في قائمة الانتظار، يسرد النواة التبعيات مع إطار المزامنة:

/*
 * displays buffer when fence is signaled.  returns immediately with a fence
 * that signals when buffer is no longer displayed.
 */
struct sync_fence* display_buffer(struct dma_buf *buffer, struct sync_fence
*fence);

دمج المزامنة

يوضّح هذا القسم كيفية دمج إطار عمل المزامنة في مساحة النواة مع أجزاء مساحة المستخدم في إطار عمل Android وبرامج التشغيل التي يجب أن تتواصل مع بعضها البعض. يتم تمثيل عناصر مساحة النواة كواصفات ملفات في مساحة المستخدم.

اتّفاقيات الدمج

اتّبِع اصطلاحات واجهة HAL لنظام التشغيل Android:

  • إذا كانت واجهة برمجة التطبيقات توفّر واصف ملف يشير إلى sync_pt، يجب أن يغلق برنامج التشغيل الخاص بالمورّد أو طبقة تجريد الأجهزة (HAL) التي تستخدم واجهة برمجة التطبيقات واصف الملف.
  • إذا مرَّر برنامج تشغيل المورّد أو طبقة HAL واصف ملف يحتوي على sync_pt إلى دالة في واجهة برمجة التطبيقات، يجب ألا يغلق برنامج تشغيل المورّد أو طبقة HAL واصف الملف.
  • لمواصلة استخدام واصف ملف السياج، يجب أن يكرّر برنامج التشغيل الخاص بالمورّد أو طبقة تجريد الأجهزة (HAL) الواصف.

تتم إعادة تسمية عنصر السياج في كل مرة يمر فيها عبر BufferQueue. يتيح دعم سياج النواة أن تتضمّن الأسياج سلاسل للأسماء، لذا يستخدم إطار عمل المزامنة اسم النافذة وفهرس المخزن المؤقت الذي يتم وضعه في قائمة الانتظار لتسمية السياج، مثل SurfaceView:0. ويفيد ذلك في تصحيح الأخطاء لتحديد مصدر التعطّل التام، لأنّ الأسماء تظهر في ناتج /d/sync وتقارير الأخطاء.

دمج ANativeWindow

‫ANativeWindow على دراية بالسياج. تحتوي dequeueBuffer وqueueBuffer وcancelBuffer على مَعلمات السياج الجغرافي.

تكامل OpenGL ES

يعتمد دمج المزامنة في OpenGL ES على إضافتَين من EGL:

  • توفّر السمة EGL_ANDROID_native_fence_sync طريقة لتضمين أو إنشاء واصفات ملفات سياج Android الأصلية في عناصر EGLSyncKHR.
  • تسمح EGL_ANDROID_wait_sync بتوقّف مؤقت على مستوى وحدة معالجة الرسومات بدلاً من التوقّف المؤقت على مستوى وحدة المعالجة المركزية، ما يجعل وحدة معالجة الرسومات تنتظر EGLSyncKHR. الإضافة EGL_ANDROID_wait_sync هي نفسها الإضافة EGL_KHR_wait_sync.

لاستخدام هذه الإضافات بشكل مستقل، عليك تنفيذ إضافة EGL_ANDROID_native_fence_sync مع توفير دعم النواة المرتبط بها. بعد ذلك، فعِّل EGL_ANDROID_wait_syncالإضافة في برنامج التشغيل. يتألف امتداد EGL_ANDROID_native_fence_sync من نوع كائن EGLSyncKHR مميز. نتيجةً لذلك، لا تنطبق الإضافات التي تنطبق على أنواع عناصر EGLSyncKHR الحالية بالضرورة على عناصر EGL_ANDROID_native_fence، ما يمنع حدوث تفاعلات غير مرغوب فيها.

يستخدم الامتداد EGL_ANDROID_native_fence_sync سمة واصف ملف سياج أصلي مقابلة لا يمكن ضبطها إلا في وقت الإنشاء ولا يمكن الاستعلام عنها مباشرةً من عنصر مزامنة حالي. يمكن ضبط هذه السمة على أحد الوضعَين التاليَين:

  • يغلّف واصف ملف سياج صالح واصف ملف سياج Android أصليًا حاليًا في عنصر EGLSyncKHR.
  • ينشئ -1 واصف ملف سياج Android أصليًا من عنصر EGLSyncKHR.

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

دمج Hardware Composer

يتعامل Hardware Composer مع ثلاثة أنواع من حواجز المزامنة:

  • يتم تمرير Acquire fences مع مخازن الإدخال المؤقتة إلى استدعاءات setLayerBuffer وsetClientTarget. تمثّل هذه العلامات عملية كتابة معلّقة في المخزن المؤقت، ويجب إرسال إشارة قبل أن تحاول SurfaceFlinger أو HWC القراءة من المخزن المؤقت المرتبط لتنفيذ عملية الدمج.
  • يتم استرداد حواجز الإصدار بعد الاتصال بـ presentDisplay باستخدام طلب getReleaseFences. تمثّل هذه القيم قراءة معلّقة من المخزن المؤقت السابق على الطبقة نفسها. يشير حاجز الإصدار إلى أنّ HWC لم يعُد يستخدم المخزن المؤقت السابق لأنّ المخزن المؤقت الحالي حلّ محل المخزن المؤقت السابق على الشاشة. يتم إرجاع حواجز الإصدار إلى التطبيق مع المخازن المؤقتة السابقة التي سيتم استبدالها أثناء عملية الإنشاء الحالية. يجب أن ينتظر التطبيق إلى أن يتم تلقّي إشارات سياج الإصدار قبل كتابة محتوى جديد في المخزن المؤقت الذي تم إرجاعه إليه.
  • يتم عرض أسوار العرض الحالية، واحد لكل إطار، كجزء من استدعاء presentDisplay. تمثّل الأسوار الحالية الوقت الذي اكتمل فيه تركيب هذه اللقطة، أو بدلاً من ذلك، الوقت الذي لم تعُد فيه هناك حاجة إلى نتيجة التركيب الخاصة باللقطة السابقة. بالنسبة إلى الشاشات الفعلية، تعرض الدالة presentDisplay الحواجز الحالية عندما يظهر الإطار الحالي على الشاشة. بعد عرض سياجات العرض الحالية، يمكن الكتابة في المخزن المؤقت المستهدف في SurfaceFlinger مرة أخرى، إذا كان ذلك منطبقًا. بالنسبة إلى الشاشات الافتراضية، يتم عرض سياجات العرض الحالية عندما يكون من الآمن القراءة من المخزن المؤقت للإخراج.