پیاده سازی Hardware Composer HAL

HALِ سخت‌افزاریِ Composer (HWC) لایه‌های دریافتی از SurfaceFlinger را ترکیب می‌کند و میزان ترکیب OpenGL ES (GLES) و عملکرد GPU را کاهش می‌دهد.

HWC اشیاء، مانند پوشش‌ها و تاول‌های دوبعدی، را برای ترکیب سطوح، انتزاعی می‌کند و با سخت‌افزار تخصصی ترکیب پنجره برای ترکیب پنجره‌ها ارتباط برقرار می‌کند. به جای ترکیب SurfaceFlinger با GPU، از HWC برای ترکیب پنجره‌ها استفاده کنید. اکثر GPUها برای ترکیب بهینه نشده‌اند و وقتی GPU لایه‌ها را از SurfaceFlinger ترکیب می‌کند، برنامه‌ها نمی‌توانند از GPU برای رندر خود استفاده کنند.

پیاده‌سازی‌های HWC باید از موارد زیر پشتیبانی کنند:

  • حداقل چهار لایه:
    • نوار وضعیت
    • نوار سیستم
    • برنامه
    • تصویر زمینه/پس زمینه
  • لایه‌هایی که بزرگتر از صفحه نمایش هستند (مثلاً یک تصویر زمینه)
  • ترکیب آلفای از پیش ضرب شده همزمان در هر پیکسل و ترکیب آلفای در هر صفحه
  • مسیر سخت‌افزاری برای پخش ویدیوی محافظت‌شده
  • سفارش بسته‌بندی RGBA، فرمت‌های YUV، و ویژگی‌های کاشی‌کاری، شیب‌بندی و گام‌برداری

برای اجرای HWC:

  1. یک HWC غیرعملیاتی پیاده‌سازی کنید و تمام کارهای ترکیب‌بندی را به GLES ارسال کنید.
  2. الگوریتمی را پیاده‌سازی کنید که ترکیب‌بندی را به صورت تدریجی به HWC واگذار کند. به عنوان مثال، فقط سه یا چهار سطح اول را به سخت‌افزار روکش HWC واگذار کنید.
  3. بهینه‌سازی HWC. این ممکن است شامل موارد زیر باشد:
    • انتخاب سطوحی که بار برداشته شده از پردازنده گرافیکی (GPU) را به حداکثر می‌رسانند و ارسال آنها به HWC.
    • تشخیص اینکه آیا صفحه نمایش در حال به‌روزرسانی است یا خیر. اگر اینطور نیست، برای صرفه‌جویی در مصرف برق، ترکیب‌بندی را به جای HWC به GLES واگذار کنید. وقتی صفحه دوباره به‌روزرسانی شد، به انتقال ترکیب‌بندی به HWC ادامه دهید.
    • آماده‌سازی برای موارد استفاده رایج مانند:
      • صفحه اصلی، که شامل نوار وضعیت، نوار سیستم، پنجره برنامه و تصاویر پس زمینه زنده است
      • بازی‌های تمام صفحه در حالت عمودی و افقی
      • ویدیوی تمام صفحه با زیرنویس و کنترل پخش
      • پخش ویدیوی محافظت‌شده
      • چند پنجره‌ای با قابلیت تقسیم صفحه

HWC اولیه

HWC دو عنصر اولیه، لایه‌ها و نمایشگرها ، را برای نمایش کار ترکیب‌بندی و تعامل آن با سخت‌افزار نمایشگر فراهم می‌کند. HWC همچنین کنترل VSync و فراخوانی به SurfaceFlinger را برای اطلاع‌رسانی در هنگام وقوع رویداد VSync فراهم می‌کند.

رابط HIDL

اندروید ۸.۰ و بالاتر از یک رابط HIDL به نام Composer HAL برای IPC پیوندی بین HWC و SurfaceFlinger استفاده می‌کند. Composer HAL جایگزین رابط قدیمی hwcomposer2.h می‌شود. اگر فروشندگان پیاده‌سازی Composer HAL از HWC را ارائه دهند، Composer HAL مستقیماً فراخوانی‌های HIDL را از SurfaceFlinger می‌پذیرد. اگر فروشندگان پیاده‌سازی قدیمی HWC را ارائه دهند، Composer HAL اشاره‌گرهای تابع را از hwcomposer2.h بارگذاری می‌کند و فراخوانی‌های HIDL را به فراخوانی‌های اشاره‌گر تابع هدایت می‌کند.

HWC توابعی را برای تعیین ویژگی‌های یک نمایشگر مشخص، جابجایی بین پیکربندی‌های مختلف نمایشگر (مانند وضوح 4k یا 1080p) و حالت‌های رنگی (مانند رنگ اصلی یا sRGB واقعی) و روشن، خاموش کردن یا قرار دادن نمایشگر در حالت کم‌مصرف (در صورت پشتیبانی) ارائه می‌دهد.

اشاره‌گرهای تابع

اگر فروشندگان Composer HAL را مستقیماً پیاده‌سازی کنند، SurfaceFlinger توابع آن را از طریق HIDL IPC فراخوانی می‌کند. برای مثال، برای ایجاد یک لایه، SurfaceFlinger تابع createLayer() را روی Composer HAL فراخوانی می‌کند.

اگر فروشندگان رابط hwcomposer2.h پیاده‌سازی کنند، Composer HAL اشاره‌گرهای تابع hwcomposer2.h را فراخوانی می‌کند. در کامنت‌های hwcomposer2.h ، توابع رابط HWC با نام‌های lowerCamelCase که در رابط به عنوان فیلدهای نامگذاری شده وجود ندارند، ارجاع داده می‌شوند. تقریباً هر تابعی با درخواست یک اشاره‌گر تابع با استفاده از getFunction ارائه شده توسط hwc2_device_t بارگذاری می‌شود. به عنوان مثال، تابع createLayer یک اشاره‌گر تابع از نوع HWC2_PFN_CREATE_LAYER است که وقتی مقدار شمارش شده HWC2_FUNCTION_CREATE_LAYER به getFunction ارسال می‌شود، بازگردانده می‌شود.

برای مستندات دقیق در مورد توابع HAL کامپوزر و توابع عبوری تابع HWC، به composer مراجعه کنید. برای مستندات دقیق در مورد اشاره‌گرهای تابع HWC، به hwcomposer2.h مراجعه کنید.

دسته‌های لایه‌بندی و نمایش

لایه‌ها و نمایشگرها توسط دستگیره‌هایی که توسط HWC تولید می‌شوند، دستکاری می‌شوند. این دستگیره‌ها در برابر SurfaceFlinger مات هستند.

وقتی SurfaceFlinger یک لایه جدید ایجاد می‌کند، تابع createLayer را فراخوانی می‌کند که برای پیاده‌سازی‌های مستقیم نوع Layer و برای پیاده‌سازی‌های عبوری نوع hwc2_layer_t را برمی‌گرداند. وقتی SurfaceFlinger ویژگی آن لایه را تغییر می‌دهد، SurfaceFlinger مقدار hwc2_layer_t را به همراه سایر اطلاعات مورد نیاز برای انجام تغییر، به تابع اصلاح مناسب ارسال می‌کند. نوع hwc2_layer_t به اندازه کافی بزرگ است که بتواند یک اشاره‌گر یا یک اندیس را در خود جای دهد.

نمایشگرهای فیزیکی با اتصال داغ (hotplug) ایجاد می‌شوند. هنگامی که یک نمایشگر فیزیکی متصل داغ می‌شود، HWC یک دسته (handle) ایجاد می‌کند و آن دسته را از طریق فراخوانی hotplug به SurfaceFlinger ارسال می‌کند. نمایشگرهای مجازی با فراخوانی createVirtualDisplay() توسط SurfaceFlinger برای درخواست یک نمایشگر ایجاد می‌شوند. اگر HWC از ترکیب نمایشگر مجازی پشتیبانی کند، یک دسته (handle) را برمی‌گرداند. سپس، SurfaceFlinger ترکیب نمایشگرها را به HWC واگذار می‌کند. اگر HWC از ترکیب نمایشگر مجازی پشتیبانی نکند، SurfaceFlinger دسته را ایجاد کرده و نمایشگر را کامپوزیت می‌کند.

نمایش عملیات ترکیب‌بندی

پس از هر VSync، اگر SurfaceFlinger محتوای جدیدی برای ترکیب داشته باشد، بیدار می‌شود. این محتوای جدید می‌تواند بافرهای تصویر جدید از برنامه‌ها یا تغییر در ویژگی‌های یک یا چند لایه باشد. وقتی SurfaceFlinger آن را بیدار می‌کند:

  1. در صورت وجود، تراکنش‌ها را مدیریت می‌کند.
  2. در صورت وجود، بافرهای گرافیکی جدید را قفل می‌کند.
  3. اگر مرحله ۱ یا ۲ منجر به تغییر در محتوای نمایش شده باشد، یک ترکیب جدید انجام می‌دهد.

برای انجام یک ترکیب جدید، SurfaceFlinger لایه‌ها را ایجاد و از بین می‌برد یا حالت‌های لایه را، در صورت لزوم، تغییر می‌دهد. همچنین لایه‌ها را با محتوای فعلی‌شان، با استفاده از فراخوانی‌هایی مانند setLayerBuffer یا setLayerColor ، به‌روزرسانی می‌کند. پس از به‌روزرسانی همه لایه‌ها، SurfaceFlinger تابع validateDisplay فراخوانی می‌کند که به HWC می‌گوید وضعیت لایه‌ها را بررسی کند و نحوه ترکیب را تعیین کند. به طور پیش‌فرض، SurfaceFlinger سعی می‌کند هر لایه را طوری پیکربندی کند که لایه توسط HWC ترکیب شود. اگرچه در برخی شرایط، SurfaceFlinger لایه‌ها را از طریق GPU fallback ترکیب می‌کند.

پس از فراخوانی validateDisplay ، SurfaceFlinger تابع getChangedCompositionTypes فراخوانی می‌کند تا ببیند آیا HWC می‌خواهد قبل از انجام ترکیب، نوع ترکیب لایه‌ها تغییر کند یا خیر. برای پذیرش تغییرات، SurfaceFlinger تابع acceptDisplayChanges فراخوانی می‌کند.

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

در نهایت، SurfaceFlinger تابع presentDisplay فراخوانی می‌کند تا به HWC بگوید فرآیند ترکیب را تکمیل کرده و نتیجه نهایی را نمایش دهد.

نمایشگرهای چندگانه

اندروید ۱۰ از چندین نمایشگر فیزیکی پشتیبانی می‌کند. هنگام طراحی پیاده‌سازی HWC که برای استفاده در اندروید ۷.۰ و بالاتر در نظر گرفته شده است، محدودیت‌هایی وجود دارد که در تعریف HWC وجود ندارد:

  • فرض بر این است که دقیقاً یک نمایشگر داخلی وجود دارد. نمایشگر داخلی، نمایشگری است که هات‌پلاگ اولیه هنگام بوت شدن گزارش می‌دهد. پس از هات‌پلاگ شدن نمایشگر داخلی، نمی‌توان آن را جدا کرد.
  • علاوه بر نمایشگر داخلی، هر تعداد نمایشگر خارجی ممکن است در حین عملکرد عادی دستگاه دچار مشکل اتصال برق شوند. این چارچوب فرض می‌کند که تمام اتصال برق پس از اولین نمایشگر داخلی، نمایشگرهای خارجی هستند، بنابراین اگر نمایشگرهای داخلی بیشتری اضافه شوند، به اشتباه به عنوان Display.TYPE_HDMI به جای Display.TYPE_BUILT_IN طبقه‌بندی می‌شوند.

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

برای مثال، اگر نمایشگر خارجی به‌روزرسانی شود، توالی به صورت زیر است:

// In Android 9 and lower:

// Update state for internal display
// Update state for external display
validateDisplay(<internal display>)
validateDisplay(<external display>)
presentDisplay(<internal display>)
presentDisplay(<external display>)

// In Android 10 and higher:

// Update state for internal display
// Update state for external display
validateInternal(<internal display>)
presentInternal(<internal display>)
validateExternal(<external display>)
presentExternal(<external display>)

ترکیب نمایش مجازی

ترکیب نمایش مجازی مشابه ترکیب نمایش خارجی است. تفاوت بین ترکیب نمایش مجازی و ترکیب نمایش فیزیکی این است که نمایشگرهای مجازی خروجی را به جای صفحه نمایش، به یک بافر Gralloc ارسال می‌کنند. آهنگساز سخت‌افزاری (HWC) خروجی را در یک بافر می‌نویسد، حصار تکمیل را فراهم می‌کند و بافر را به یک مصرف‌کننده (مانند رمزگذار ویدیو، پردازنده گرافیکی، پردازنده مرکزی و غیره) ارسال می‌کند. نمایشگرهای مجازی می‌توانند در صورت نوشتن خط لوله نمایش در حافظه، از 2D/blitter یا overlays استفاده کنند.

حالت‌ها

هر فریم پس از فراخوانی متد validateDisplay() HWC توسط SurfaceFlinger، در یکی از سه حالت زیر قرار می‌گیرد:

  • GLES — پردازنده گرافیکی (GPU) تمام لایه‌ها را ترکیب می‌کند و مستقیماً در بافر خروجی می‌نویسد. HWC در ترکیب لایه‌ها نقشی ندارد.
  • مختلط — پردازنده گرافیکی (GPU) برخی از لایه‌ها را با فریم‌بافر ترکیب می‌کند و HWC فریم‌بافر و لایه‌های باقی‌مانده را ترکیب می‌کند و مستقیماً در بافر خروجی می‌نویسد.
  • HWC — HWC تمام لایه‌ها را ترکیب کرده و مستقیماً در بافر خروجی می‌نویسد.

فرمت خروجی

قالب‌های خروجی بافر نمایش مجازی به حالت آنها بستگی دارد:

  • حالت GLES — درایور EGL فرمت بافر خروجی را در dequeueBuffer() تنظیم می‌کند، که معمولاً RGBA_8888 است. مصرف‌کننده باید بتواند فرمت خروجی تنظیم‌شده توسط درایور را بپذیرد، در غیر این صورت بافر قابل خواندن نخواهد بود.
  • حالت‌های ترکیبی و HWC — اگر مصرف‌کننده به دسترسی به CPU نیاز داشته باشد، مصرف‌کننده فرمت را تنظیم می‌کند. در غیر این صورت، فرمت IMPLEMENTATION_DEFINED است و Gralloc بهترین فرمت را بر اساس پرچم‌های استفاده تنظیم می‌کند. به عنوان مثال، Gralloc فرمت YCbCr را تنظیم می‌کند اگر مصرف‌کننده رمزگذار ویدیو باشد و HWC بتواند فرمت را به طور موثر بنویسد.

نرده‌های هماهنگ‌سازی

حصارهای همگام‌سازی (Sync) جنبه‌ی حیاتی سیستم گرافیکی اندروید هستند. حصارها اجازه می‌دهند کار CPU مستقل از کار همزمان GPU پیش برود و تنها زمانی که وابستگی واقعی وجود دارد، مسدود می‌شوند.

برای مثال، وقتی یک برنامه بافری را که در GPU تولید می‌شود ارسال می‌کند، یک شیء حصار همگام‌سازی را نیز ارسال می‌کند. این حصار زمانی که GPU نوشتن در بافر را تمام کرد، سیگنال می‌دهد.

HWC مستلزم آن است که GPU نوشتن بافرها را قبل از نمایش بافرها به پایان برساند. حصارهای همگام‌سازی (Sync fences) به همراه بافرها از طریق خط لوله گرافیکی عبور داده می‌شوند و هنگام نوشتن بافرها سیگنال می‌دهند. قبل از نمایش بافر، HWC بررسی می‌کند که آیا حصار همگام‌سازی سیگنال داده است یا خیر، و در صورت ارسال، بافر را نمایش می‌دهد.

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