چارچوب همگام‌سازی

چارچوب همگام‌سازی وابستگی‌های بین عملیات ناهم‌زمان مختلف در سیستم گرافیک Android را به‌طور صریح توصیف می‌کند. این چارچوب میانای برنامه‌سازی کاربردی‌ای ارائه می‌دهد که به مؤلفه‌ها امکان می‌دهد زمان آزاد شدن میان‌گیرها را نشان دهند. این چارچوب همچنین اجازه می‌دهد تا اصول همگام‌سازی بین درایورها از هسته به فضای کاربر و بین خود فرآیندهای فضای کاربر منتقل شوند.

برای مثال، یک برنامه ممکن است کار را در صف قرار دهد تا در GPU انجام شود. «واحد پردازش گرافیکی» شروع به طراحی آن تصویر می‌کند. اگرچه تصویر هنوز در حافظه رسم نشده است، اشاره‌گر بافر به‌همراه نرده‌ای که نشان می‌دهد کار GPU چه زمانی تمام می‌شود به ترکیب‌کننده پنجره منتقل می‌شود. ترکیب‌کننده پنجره پردازش را زودتر از موعد شروع می‌کند و کار را به کنترل‌کننده نمایشگر منتقل می‌کند. به‌همین ترتیب، کار CPU زودتر از موعد انجام می‌شود. وقتی GPU کارش را تمام می‌کند، کنترل‌کننده نمایشگر بلافاصله تصویر را نمایش می‌دهد.

چارچوب همگام‌سازی همچنین به پیاده‌سازان اجازه می‌دهد از منابع همگام‌سازی در عناصر سخت‌افزاری خودشان استفاده کنند. درنهایت، این چارچوب امکان مشاهده خط لوله گرافیک را برای کمک به اشکال‌زدایی فراهم می‌کند.

همگام‌سازی صریح

همگام‌سازی صریح به تولیدکنندگان و مصرف‌کنندگان بافرهای گرافیکی امکان می‌دهد وقتی استفاده از بافر تمام شد، علامت دهند. همگام‌سازی صریح در فضای هسته پیاده‌سازی می‌شود.

مزایای همگام‌سازی صریح عبارتند از:

  • تغییرات کمتر در رفتار بین دستگاه‌ها
  • پشتیبانی بهتر از اشکال‌زدایی
  • سنجه‌های بهبودیافته آزمایش

چارچوب همگام‌سازی سه نوع شیء دارد:

  • sync_timeline
  • sync_pt
  • sync_fence

sync_timeline

sync_timeline یک خط زمان یکنواخت افزایشی است که فروشندگان باید برای هر نمونه درایور، مانند بافت GL، کنترل‌کننده نمایشگر، یا blitter دو بعدی، پیاده‌سازی کنند. 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 متفاوتی دارند (مثلاً برای کنترل‌کننده نمایشگر و GPU). ‫sync_fence،‏ sync_pt، و sync_timeline عناصر اصلی هستند که درایورها و فضای کاربر برای اعلام وابستگی‌هایشان استفاده می‌کنند. وقتی حصاری علامت‌گذاری می‌شود، همه فرمان‌های صادرشده قبل‌از حصار کامل می‌شوند زیرا برنامه درایور هسته یا سخت‌افزار فرمان‌ها را به‌ترتیب اجرا می‌کند.

چارچوب همگام‌سازی به چندین مصرف‌کننده یا تولیدکننده اجازه می‌دهد وقتی استفاده از بافر را تمام کردند علامت دهند و اطلاعات وابستگی را با یک پارامتر تابع منتقل کنند. حصارها با توصیفگر فایل پشتیبانی می‌شوند و از فضای هسته به فضای کاربر منتقل می‌شوند. برای مثال، یک حصار می‌تواند شامل دو مقدار sync_pt باشد که نشان می‌دهد دو مصرف‌کننده تصویر جداگانه چه زمانی خواندن میان‌گیر را تمام کرده‌اند. وقتی حصار علامت داده می‌شود، تولیدکنندگان تصویر می‌دانند که هر دو مصرف‌کننده مصرف را تمام کرده‌اند.

حصارها، مانند مقادیر sync_pt، به‌صورت فعال شروع می‌شوند و وضعیتشان براساس وضعیت نقطه‌هایشان تغییر می‌کند. اگر همه مقادیر sync_pt علامت‌دار شوند، sync_fence علامت‌دار می‌شود. اگر یک sync_pt به حالت خطا برود، کل sync_fence حالت خطا خواهد داشت.

عضویت در sync_fence پس‌از ایجاد حصار تغییرناپذیر است. برای دریافت بیش از یک نقطه در حصار، ادغام انجام می‌شود که در آن نقاط دو حصار متمایز به حصار سوم اضافه می‌شود. اگر یکی از آن نقاط در حصار مبدأ علامت‌دهی شده باشد و دیگری نشده باشد، حصار سوم نیز در وضعیت علامت‌دهی‌شده نخواهد بود.

برای پیاده‌سازی همگام‌سازی صریح، موارد زیر را ارائه دهید:

  • زیرسیستم فضای هسته که چارچوب همگام‌سازی را برای یک درایور سخت‌افزار خاص پیاده‌سازی می‌کند. گرداننده‌هایی که باید از حصار آگاه باشند معمولاً هر چیزی است که به «آهنگ‌ساز سخت‌افزاری» (HWC) دسترسی دارد یا با آن ارتباط برقرار می‌کند. فایل‌های کلیدی شامل موارد زیر است:
    • پیاده‌سازی اصلی:
      • 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) و پشتیبانی از حصار در درایور گرافیک.

مطالعه موردی: پیاده‌سازی درایور نمایشگر

برای استفاده از API پشتیبان تابع همگام‌سازی، برنامه‌نویس درایور نمایشگری که تابع بافر نمایشگر دارد. قبل‌از اینکه چارچوب همگام‌سازی وجود داشته باشد، این تابع اشیاء 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 و درایورهایی که باید با یکدیگر ارتباط برقرار کنند، توضیح می‌دهد. اشیاء فضای هسته به‌عنوان توصیف‌گرهای فایل در فضای کاربر نشان داده می‌شوند.

قراردادهای یکپارچه‌سازی

قراردادهای میانای Android HAL را دنبال کنید:

  • اگر میانای برنامه کاربردی توصیف‌گر فایلی ارائه می‌دهد که به sync_pt اشاره می‌کند، برنامه‌نویس فروشنده یا HAL که از میانای برنامه کاربردی استفاده می‌کند باید توصیف‌گر فایل را ببندد.
  • اگر درایور فروشنده یا HAL توصیف‌گر فایلی را که حاوی sync_pt است به تابع API ارسال کند، درایور فروشنده یا 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 بومی استفاده کنید. این کار نتیجه‌ای مشابه با پُرسمان کردن مشخصه مجموعه دارد، اما از قراردادی پیروی می‌کند که گیرنده حصار را می‌بندد (ازاین‌رو عملیات تکراری انجام می‌شود). درنهایت، ازبین بردن شیء EGLSyncKHR باعث بسته شدن ویژگی حصار داخلی می‌شود.

یکپارچه‌سازی آهنگ‌ساز سخت‌افزاری

‫HWC سه نوع حصار همگام‌سازی را مدیریت می‌کند:

  • اکتساب نرده‌ها همراه با بافرهای ورودی به تماس‌های setLayerBuffer و setClientTarget منتقل می‌شوند. این‌ها نشان‌دهنده نوشتن معلقه در بافر هستند و باید قبل‌از اینکه SurfaceFlinger یا HWC تلاش کند از بافر مرتبط برای انجام ترکیب بخواند، علامت دهند.
  • حصار انتشار پس‌از تماس با presentDisplay بااستفاده از تماس getReleaseFences بازیابی می‌شود. این‌ها نشان‌دهنده خواندن معلقه از بافر قبلی در همان لایه است. A release fence signals when the HWC is no longer using the previous buffer because the current buffer has replaced the previous buffer on the display. نرده‌های انتشار به‌همراه بافرهای قبلی که درطول ترکیب فعلی جایگزین خواهند شد به برنامه برگردانده می‌شوند. برنامه باید تا زمانی که سیگنال نرده انتشار دریافت کند صبر کند و سپس محتوای جدید را در بافری که به آن برگردانده شده است بنویسد.
  • حصارکشی‌های فعلی، یکی در هر قاب، به‌عنوان بخشی از تماس با presentDisplay برگردانده می‌شوند. حصارکشی‌های فعلی نشان‌دهنده زمانی است که ترکیب‌بندی این قاب تکمیل شده است، یا به‌طور متناوب، زمانی که نتیجه ترکیب‌بندی قاب قبلی دیگر موردنیاز نیست. برای نمایشگرهای فیزیکی، presentDisplay وقتی قاب فعلی روی صفحه‌نمایش ظاهر می‌شود، حصارهای فعلی را برمی‌گرداند. پس‌از اینکه حصارهای فعلی برگردانده شدند، درصورت لزوم، نوشتن در بافر هدف SurfaceFlinger دوباره ایمن است. برای نمایشگرهای مجازی، حصارهای حاضر زمانی برگردانده می‌شوند که خواندن از بافر برونداد ایمن باشد.