บริการเฟรมเวิร์กที่เรียบง่ายนี้ช่วยให้ผู้ให้บริการ กระบวนการใช้ 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;
} - รับ
SurfaceHolder
จาก HGBP ที่ดึงข้อมูลโดยใช้ APIlibbufferqueueconverter
:mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
if (mSurfaceHolder == nullptr) {
LOG(ERROR) << "Failed to get a Surface from HGBP.";
return false;
} - แปลง
SurfaceHolder
เป็นหน้าต่างเนทีฟโดยใช้ APIlibbufferqueueconverter
: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;
}
หมายเหตุ: ใช้จอแสดงผลได้ครั้งละ 1 จอเท่านั้น ซึ่งหมายความว่าไคลเอ็นต์ EVS ที่ใช้อยู่จะแพ้จอแสดงผลเมื่อไคลเอ็นต์ EVS เครื่องอื่น คำขอเปิดจอแสดงผล แม้ว่าจะเป็นคำขอที่ต่างกันก็ตาม