Ce service d'infrastructure simple permet aux processus des fournisseurs d'utiliser SurfaceFlinger/EGL dans les implémentations HAL, sans lier libgui. AOSP fournit l'implémentation par défaut de ce service, qui est entièrement fonctionnel. Cependant, le fournisseur doit également mettre en œuvre des API pour fournir ce service sur sa plateforme.
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); }
Pour utiliser ce service :
- Obtenez
IAutomotiveDisplayProxyService
.android::sp<IAutomotiveDisplayProxyService> windowProxyService = IAutomotiveDisplayProxyService::getService("default"); if (windowProxyService == nullptr) { LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting."; return 1; }
- Récupérez des informations d'affichage actives auprès du service pour déterminer la résolution.
// 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; });
- Récupérez un
IGraphicBufferProducer
matériel (ou HIDL GraphicBufferProducer (HGBP) à partir deIAutomotiveDisplayProxyService
:mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId); if (mGfxBufferProducer == nullptr) { LOG(ERROR) << "Failed to get IGraphicBufferProducer from " << "IAutomotiveDisplayProxyService."; return false; }
- Obtenez un
SurfaceHolder
à partir d'un HGBP récupéré, en utilisant l'APIlibbufferqueueconverter
:mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer); if (mSurfaceHolder == nullptr) { LOG(ERROR) << "Failed to get a Surface from HGBP."; return false; }
- Convertissez un
SurfaceHolder
en fenêtre native en utilisant l'APIlibbufferqueueconverter
:mWindow = getNativeWindow(mSurfaceHolder.get()); if (mWindow == nullptr) { LOG(ERROR) << "Failed to get a native window from Surface."; return false; }
- Créez une surface de fenêtre EGL avec une fenêtre native puis effectuez le rendu :
// 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; } ...
- Appelez
IAutomotiveDisplayProxyService::showWindow()
pour afficher la vue rendue à l'écran. Ce service a la priorité la plus élevée et prend donc toujours le contrôle de l'écran du propriétaire actuel :mAutomotiveDisplayProxyService->showWindow();
Voir service.cpp
et GlWrapper.cpp
dans $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/
pour plus de détails sur la mise en œuvre.
Une implémentation EVS HAL nécessite les bibliothèques supplémentaires affichées en gras ci-dessous.
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", ],
Prise en charge multi-affichage
Afficher l'énumération des appareils et récupérer les informations d'affichage
À l’instar de l’énumération des appareils photo, le framework EVS fournit une méthode pour énumérer les écrans disponibles. L' identifiant d'affichage statique code un identifiant de type long, les informations de port d'affichage dans l'octet inférieur et Extended Display IDentification Data
dans les bits supérieurs. IAutomotiveDisplayProxyService::getDisplayIdList()
renvoie une liste des ID d'affichage des écrans locaux physiques, qui sont disponibles pour le service EVS, et IEvsEnumerator::getDisplayIdList()
renvoie une liste des ports d'affichage auxquels les écrans détectés sont connectés. Le premier ID de la liste est toujours celui de l'affichage principal.
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); };
Périphérique d'affichage cible ouvert
L'application EVS appelle IEvsEnumerator::openDisplay_1_1() avec un numéro de port d'affichage cible :
android::sp<IEvsDisplay> pDisplay = pEvs->openDisplay_1_1(displayId); if (pDisplay.get() == nullptr) { LOG(ERROR) << "EVS Display unavailable. Exiting."; return 1; }
Remarque : Un seul affichage peut être utilisé à la fois, ce qui signifie que le client EVS actuel perd son affichage lorsqu'un autre client EVS demande à ouvrir l'affichage, même s'il ne s'agit pas des mêmes.