บริการพร็อกซีจอแสดงผลสำหรับยานยนต์

บริการเฟรมเวิร์กที่เรียบง่ายนี้ช่วยให้ผู้ให้บริการ กระบวนการใช้ 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);
}

หากต้องการใช้บริการนี้ ให้ทำดังนี้

  1. สมัคร IAutomotiveDisplayProxyService
    android::sp<IAutomotiveDisplayProxyService> windowProxyService =
       
    IAutomotiveDisplayProxyService::getService("default");
    if (windowProxyService == nullptr) {
        LOG
    (ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
       
    return 1;
    }
  2. ดึงข้อมูลจอแสดงผลที่ใช้งานอยู่จากบริการเพื่อกำหนดความละเอียด
    // 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;
    });
  3. ดึงข้อมูลฮาร์ดแวร์ IGraphicBufferProducer (หรือ HIDL GraphicBufferProducer (HGBP) จาก IAutomotiveDisplayProxyService:
    mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
    if (mGfxBufferProducer == nullptr) {
        LOG
    (ERROR) << "Failed to get IGraphicBufferProducer from "
                   
    << "IAutomotiveDisplayProxyService.";
       
    return false;
    }
  4. รับ SurfaceHolder จาก HGBP ที่ดึงข้อมูลโดยใช้ API libbufferqueueconverter:
    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
    if (mSurfaceHolder == nullptr) {
        LOG
    (ERROR) << "Failed to get a Surface from HGBP.";
       
    return false;
    }
  5. แปลง SurfaceHolder เป็นหน้าต่างเนทีฟโดยใช้ API libbufferqueueconverter:
    mWindow = getNativeWindow(mSurfaceHolder.get());
    if (mWindow == nullptr) {
        LOG
    (ERROR) << "Failed to get a native window from Surface.";
       
    return false;
    }
  6. สร้างพื้นผิวหน้าต่าง 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;
    }
    ...
  7. โทรหา 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;
}

หมายเหตุ: ใช้จอแสดงผลได้ครั้งละ 1 จอเท่านั้น ซึ่งหมายความว่าไคลเอ็นต์ EVS ที่ใช้อยู่จะแพ้จอแสดงผลเมื่อไคลเอ็นต์ EVS เครื่องอื่น คำขอเปิดจอแสดงผล แม้ว่าจะเป็นคำขอที่ต่างกันก็ตาม