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

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

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

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

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

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

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

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

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

  • sync_timeline
  • sync_pt
  • sync_fence

همگام‌سازی_خط_زمان

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 به طور صریح دسترسی پیدا نکنید. API تمام توابع مورد نیاز را ارائه می‌دهد.

همگام‌سازی

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

همگام‌سازی

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

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

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

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

/*
 * 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);

ادغام همگام‌سازی

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

قراردادهای ادغام

از قراردادهای رابط کاربری HAL اندروید پیروی کنید:

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

یک شیء fence هر بار که از BufferQueue عبور می‌کند، تغییر نام می‌دهد. پشتیبانی از fence در هسته به fenceها اجازه می‌دهد تا رشته‌هایی برای نام‌ها داشته باشند، بنابراین چارچوب همگام‌سازی از نام پنجره و شاخص بافر که در صف قرار دارد برای نامگذاری fence استفاده می‌کند، مانند SurfaceView:0 . این امر در اشکال‌زدایی برای شناسایی منبع بن‌بست مفید است زیرا نام‌ها در خروجی /d/sync و گزارش‌های اشکال ظاهر می‌شوند.

ادغام ANativeWindow

ANativeWindow از حصار (fences) آگاه است. dequeueBuffer ، queueBuffer و cancelBuffer پارامترهای حصار (fences) دارند.

ادغام OpenGL ES

یکپارچه‌سازی همگام‌سازی OpenGL ES به دو افزونه EGL متکی است:

  • EGL_ANDROID_native_fence_sync راهی برای پوشش دادن یا ایجاد توصیف‌گرهای فایل حصار بومی اندروید در اشیاء EGLSyncKHR فراهم می‌کند.
  • EGL_ANDROID_wait_sync به جای CPU، اجازه می‌دهد که GPU از کار بیفتد و GPU را برای 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 از یک ویژگی توصیف‌گر فایل حصار بومی متناظر استفاده می‌کند که فقط در زمان ایجاد قابل تنظیم است و نمی‌توان مستقیماً از یک شیء همگام‌سازی موجود به بعد از آن پرس‌وجو کرد. این ویژگی را می‌توان روی یکی از دو حالت زیر تنظیم کرد:

  • یک توصیف‌گر فایل حصار معتبر، یک توصیف‌گر فایل حصار بومی اندروید موجود را در یک شیء EGLSyncKHR قرار می‌دهد.
  • -1 یک توصیفگر فایل حصار بومی اندروید از یک شیء EGLSyncKHR ایجاد می‌کند.

از فراخوانی تابع DupNativeFenceFD() برای استخراج شیء EGLSyncKHR از توصیفگر فایل حصار بومی اندروید استفاده کنید. این کار نتیجه‌ای مشابه پرس‌وجو از ویژگی set دارد، اما به این قرارداد پایبند است که گیرنده حصار را می‌بندد (از این رو عملیات تکراری انجام می‌شود). در نهایت، از بین بردن شیء EGLSyncKHR ، ویژگی حصار داخلی را می‌بندد.

ادغام آهنگساز سخت افزاری

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

  • حصارهای اکتسابی به همراه بافرهای ورودی به فراخوانی‌های setLayerBuffer و setClientTarget ارسال می‌شوند. این‌ها نشان‌دهنده‌ی یک نوشتن در حال انتظار در بافر هستند و باید قبل از اینکه SurfaceFlinger یا HWC تلاش کنند از بافر مربوطه بخوانند تا ترکیب را انجام دهند، سیگنال دهند.
  • حصارهای رهاسازی پس از فراخوانی presentDisplay با استفاده از فراخوانی getReleaseFences بازیابی می‌شوند. این حصارها نشان‌دهنده‌ی خواندن در حال انتظار از بافر قبلی در همان لایه هستند. حصار رهاسازی زمانی سیگنال می‌دهد که HWC دیگر از بافر قبلی استفاده نمی‌کند، زیرا بافر فعلی جایگزین بافر قبلی در صفحه نمایش شده است. حصارهای رهاسازی به همراه بافرهای قبلی که در طول ترکیب فعلی جایگزین خواهند شد، به برنامه بازگردانده می‌شوند. برنامه باید قبل از نوشتن محتوای جدید در بافری که به آنها بازگردانده شده است، منتظر سیگنال حصار رهاسازی بماند.
  • حصارهای فعلی ، به عنوان بخشی از فراخوانی presentDisplay ، به ازای هر فریم، یکی برگردانده می‌شوند. حصارهای فعلی نشان می‌دهند که ترکیب این فریم تکمیل شده است، یا به طور متناوب، زمانی که نتیجه ترکیب فریم قبلی دیگر مورد نیاز نیست. برای نمایشگرهای فیزیکی، presentDisplay حصارهای فعلی را زمانی برمی‌گرداند که فریم فعلی روی صفحه نمایش ظاهر شود. پس از برگرداندن حصارهای فعلی، در صورت لزوم، می‌توان دوباره در بافر هدف SurfaceFlinger نوشت. برای نمایشگرهای مجازی، حصارهای فعلی زمانی برگردانده می‌شوند که خواندن از بافر خروجی ایمن باشد.