این سرویس فریمورک ساده به فرآیندهای فروشنده اجازه میدهد از SurfaceFlinger/EGL در پیادهسازی HAL، بدون پیوند libgui استفاده کنند. AOSP اجرای پیش فرض این سرویس را ارائه می دهد که کاملاً کاربردی است. با این حال، فروشنده باید API ها را نیز برای ارائه این سرویس بر روی پلت فرم خود پیاده سازی کند.
package android.frameworks.automotive.display@1.0; import android.hardware.graphics.bufferqueue@2.0::IGraphicBufferProducer; interface IAutomotiveDisplayProxyService { /** * Gets an IGraphicBufferProducer instance from the service. * * @param id Target's stable display identifier * * @return igbp Returns an IGraphicBufferProducer object, that can be * converted to an ANativeWindow object. */ getIGraphicBufferProducer(uint64_t id) generates (IGraphicBufferProducer igbp); /** * Sets the ANativeWindow, which is associated with the * IGraphicBufferProducer, to be visible and to take over the display. * * @param id Target display ID * * @return success Returns true on success. */ showWindow(uint64_t id) generates (bool success); /** * Sets the ANativeWindow, which is associated with the * IGraphicBufferProducer, to be invisible and to release the control * over display. * * @param id Target display ID * * @return success Returns true on success. */ hideWindow(uint64_t id) generates (bool success); /** * Returns the stable identifiers of all available displays. * * @return ids A list of stable display identifiers. */ getDisplayIdList() generates (vec<uint64_t> ids); /** * Returns the descriptor of the target display. * * @param id Stable ID of a target display. * @return cfg DisplayConfig of the active display. * @return state Current state of the active display. */ getDisplayInfo(uint64_t id) generates (HwDisplayConfig cfg, HwDisplayState state); }
برای استفاده از این سرویس:
-
IAutomotiveDisplayProxyService
را دریافت کنید.android::sp<IAutomotiveDisplayProxyService> windowProxyService = IAutomotiveDisplayProxyService::getService("default"); if (windowProxyService == nullptr) { LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting."; return 1; }
- برای تعیین وضوح، اطلاعات نمایشگر فعال را از سرویس بازیابی کنید.
// We use the first display in the list as the primary. pWindowProxy->getDisplayInfo(displayId, [this](auto dpyConfig, auto dpyState) { DisplayConfig *pConfig = (DisplayConfig*)dpyConfig.data(); mWidth = pConfig->resolution.getWidth(); mHeight = pConfig->resolution.getHeight(); ui::DisplayState* pState = (ui::DisplayState*)dpyState.data(); if (pState->orientation != ui::ROTATION_0 && pState->orientation != ui::ROTATION_180) { // rotate std::swap(mWidth, mHeight); } LOG(DEBUG) << "Display resolution is " << mWidth << " x " << mHeight; });
- بازیابی سخت افزار
IGraphicBufferProducer
(یا HIDL GraphicBufferProducer (HGBP) ازIAutomotiveDisplayProxyService
:mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId); if (mGfxBufferProducer == nullptr) { LOG(ERROR) << "Failed to get IGraphicBufferProducer from " << "IAutomotiveDisplayProxyService."; return false; }
- با استفاده از API
libbufferqueueconverter
یکSurfaceHolder
از HGBP بازیابی شده دریافت کنید:mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer); if (mSurfaceHolder == nullptr) { LOG(ERROR) << "Failed to get a Surface from HGBP."; return false; }
- با استفاده از API
libbufferqueueconverter
یکSurfaceHolder
به یک پنجره بومی تبدیل کنید:mWindow = getNativeWindow(mSurfaceHolder.get()); if (mWindow == nullptr) { LOG(ERROR) << "Failed to get a native window from Surface."; return false; }
- یک سطح پنجره EGL با یک پنجره بومی ایجاد کنید و سپس رندر کنید:
// Set up our OpenGL ES context associated with the default display mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (mDisplay == EGL_NO_DISPLAY) { LOG(ERROR) << "Failed to get egl display"; return false; } ... // Create the EGL render target surface mSurface = eglCreateWindowSurface(mDisplay, egl_config, mWindow, nullptr); if (mSurface == EGL_NO_SURFACE) { LOG(ERROR) << "eglCreateWindowSurface failed."; return false; } ...
- برای نمایش نمای رندر شده روی صفحه، با
IAutomotiveDisplayProxyService::showWindow()
تماس بگیرید. این سرویس بالاترین اولویت را دارد و بنابراین همیشه کنترل صفحه را از مالک فعلی می گیرد:mAutomotiveDisplayProxyService->showWindow();
برای جزئیات بیشتر، به service.cpp
و GlWrapper.cpp
در $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/
مراجعه کنید.
اجرای EVS HAL به کتابخانه های اضافی نیاز دارد که به صورت پررنگ در زیر نمایش داده شده اند.
cc_binary { name: "android.hardware.automotive.evs@1.1-sample", vendor: true, srcs: [ ... ], shared_libs: [ ... "libbufferqueueconverter", "android.hidl.token@1.0-utils", "android.frameworks.automotive.display@1.0", "android.hardware.graphics.bufferqueue@1.0", "android.hardware.graphics.bufferqueue@2.0", ],
پشتیبانی از چند نمایشگر
نمایش شمارش دستگاه و بازیابی اطلاعات نمایشگر
مانند شمارش دستگاه های دوربین، چارچوب EVS روشی را برای شمارش نمایشگرهای موجود ارائه می دهد. شناسه نمایشگر استاتیک یک شناسه نوع طولانی، اطلاعات پورت نمایش در بایت پایین و Extended Display IDentification Data
در بیت های بالایی رمزگذاری می کند. IAutomotiveDisplayProxyService::getDisplayIdList()
لیستی از شناسه های نمایشگر نمایشگرهای محلی فیزیکی را که برای سرویس EVS در دسترس هستند، برمی گرداند و IEvsEnumerator::getDisplayIdList()
لیستی از پورت های نمایشی را برمی گرداند که نمایشگرهای شناسایی شده به آنها متصل هستند. اولین شناسه در لیست همیشه نمایشگر اصلی است.
interface IEvsEnumerator extends @1.0::IEvsEnumerator { ... /** * Returns a list of all EVS displays available to the system * * @return displayIds Identifiers of available displays. */ getDisplayIdList() generates (vec<uint8_t> displayIds); };
دستگاه نمایش هدف را باز کنید
برنامه EVS IEvsEnumerator::openDisplay_1_1() را با شماره پورت نمایش هدف تماس می گیرد:
android::sp<IEvsDisplay> pDisplay = pEvs->openDisplay_1_1(displayId); if (pDisplay.get() == nullptr) { LOG(ERROR) << "EVS Display unavailable. Exiting."; return 1; }
توجه: فقط یک نمایشگر میتواند در یک زمان مورد استفاده قرار گیرد، به این معنی که وقتی مشتری EVS دیگری درخواست باز کردن صفحه نمایش را میدهد، مشتری فعلی EVS نمایش خود را از دست میدهد، حتی زمانی که آنها یکسان نیستند.