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