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

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

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

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

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

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

تشمل مزايا المزامنة الصريحة ما يلي:

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

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

  • sync_timeline
  • sync_pt
  • sync_fence

sync_timeline

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

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

  • قدِّم أسماء مفيدة لجميع العوامل المشغِّلة والمخططات الزمنية والحدود لتبسيط تصحيح الأخطاء.
  • استخدِم عاملَي التشغيل timeline_value_str وpt_value_str في المخططات الزمنية لجعل نتائج تصحيح الأخطاء أكثر سهولة في القراءة.
  • نفِّذ العنصر fill 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 بعد إنشاء السياج. للحصول على أكثر من نقطة واحدة في سياج، يتم إجراء دمج حيث تتم إضافة نقاط من سياجَين مختلفَين إلى سياج ثالث. إذا تم إرسال إشارة إلى إحدى هاتين النقطتَين في السياج الأصلي ولم يتم إرسال إشارة إلى الأخرى، لن يكون السياج الثالث أيضًا في حالة تم إرسال إشارة إليه.

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

  • نظام فرعي في مساحة النواة ينفذ إطار عمل المزامنة لبرنامج تشغيل جهاز معيّن إنّ برامج التشغيل التي يجب أن تكون على دراية بالحدود هي عمومًا أيّ برنامج يصل إلى "أداة إنشاء الأجهزة" أو يتواصل معها. تشمل الملفات الرئيسية ما يلي:
    • التنفيذ الأساسي:
      • 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 أكثر تعقيدًا. أثناء عرض المخزن المؤقت، يتم ربطه بحدود تشير إلى وقت استعداد المخزن المؤقت. يمكنك إضافة المحتوى إلى "قائمة المحتوى التالي" وبدء العمل بعد انتهاء فترة الحظر.

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

/*
 * 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 وبرامج التشغيل التي يجب أن تتواصل مع بعضها. يتم تمثيل عناصر مساحة النواة كأوصاف ملفات في مساحة المستخدم.

اصطلاحات الدمج

اتّبِع اصطلاحات واجهة Android HAL:

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

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

دمج ANativeWindow

يراعي ANativeWindow السياج. تحتوي dequeueBuffer وqueueBuffer وcancelBuffer على مَعلمات حدود.

دمج OpenGL ES

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

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

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

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

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

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

دمج Hardware Composer

يعالج "أداة إنشاء الأجهزة" ثلاثة أنواع من حدود المزامنة:

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