Add multi-display support
This change modifies and implements below methods to support
multi-display device implementations.
- getIGraphicBufferProducer() takes a target display identifier.
If a given identifier is not valid, this will return a null pointer.
- AutomotiveDisplayProxyService stores display tokens of each display.
- showWindow() is modified to set a layer stack properly for a target
display.
- getDisplayIdList() is newly implemented and returns stable IDs
of all available displays.
- getDisplayInfo() returns the description of a target display
that is identified by a given stable ID.
Bug: 141886260
Bug: 146567078
Test: VtsHalEvsV1_1TargetTest
Change-Id: Ia195a6c19416eb75bfe77da61d7a32030ec85967
Signed-off-by: Changyeon Jo <changyeon@google.com>
diff --git a/services/automotive/display/AutomotiveDisplayProxyService.cpp b/services/automotive/display/AutomotiveDisplayProxyService.cpp
index 3cd8e39..8f57dcd 100644
--- a/services/automotive/display/AutomotiveDisplayProxyService.cpp
+++ b/services/automotive/display/AutomotiveDisplayProxyService.cpp
@@ -27,97 +27,163 @@
namespace V1_0 {
namespace implementation {
-Return<sp<IGraphicBufferProducer>>
-AutomotiveDisplayProxyService::getIGraphicBufferProducer() {
- if (mSurface == nullptr) {
- status_t err;
- mSurfaceComposerClient = new SurfaceComposerClient();
- err = mSurfaceComposerClient->initCheck();
+Return<sp<IGraphicBufferProducer>>
+AutomotiveDisplayProxyService::getIGraphicBufferProducer(uint64_t id) {
+ auto it = mDisplays.find(id);
+ sp<IBinder> displayToken = nullptr;
+ sp<SurfaceControl> surfaceControl = nullptr;
+ if (it == mDisplays.end()) {
+ displayToken = SurfaceComposerClient::getPhysicalDisplayToken(id);
+ if (displayToken == nullptr) {
+ ALOGE("Given display id, 0x%lX, is invalid.", id);
+ return nullptr;
+ }
+
+ // Get the resolution from stored display state.
+ DisplayConfig displayConfig = {};
+ auto err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
+ if (err != NO_ERROR) {
+ ALOGE("Failed to get display configuration of %lX. "
+ "This display will be ignored.", id);
+ return nullptr;
+ }
+
+ ui::DisplayState displayState = {};
+ err = SurfaceComposerClient::getDisplayState(displayToken, &displayState);
+ if (err != NO_ERROR) {
+ ALOGE("Failed to get current display status of %lX. "
+ "This display will be ignored.", id);
+ return nullptr;
+ }
+
+ auto displayWidth = displayConfig.resolution.getWidth();
+ auto displayHeight = displayConfig.resolution.getHeight();
+ if ((displayState.orientation != ui::ROTATION_0) &&
+ (displayState.orientation != ui::ROTATION_180)) {
+ std::swap(displayWidth, displayHeight);
+ }
+
+ sp<android::SurfaceComposerClient> surfaceClient = new SurfaceComposerClient();
+ err = surfaceClient->initCheck();
if (err != NO_ERROR) {
ALOGE("SurfaceComposerClient::initCheck error: %#x", err);
- mSurfaceComposerClient = nullptr;
return nullptr;
}
- const auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
- if (displayToken == nullptr) {
- ALOGE("Failed to get internal display ");
- return nullptr;
- }
-
- err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &mDpyConfig);
- if (err != NO_ERROR) {
- ALOGE("Failed to get active display config");
- return nullptr;
- }
-
- err = SurfaceComposerClient::getDisplayState(displayToken, &mDpyState);
- if (err != NO_ERROR) {
- ALOGE("Failed to get display state");
- return nullptr;
- }
-
- const ui::Size& resolution = mDpyConfig.resolution;
- auto width = resolution.getWidth();
- auto height = resolution.getHeight();
-
- if (mDpyState.orientation == ui::ROTATION_90 ||
- mDpyState.orientation == ui::ROTATION_270) {
- std::swap(width, height);
- }
-
- mSurfaceControl = mSurfaceComposerClient->createSurface(
- String8("Automotive Display"), width, height,
+ // Create a SurfaceControl instance
+ surfaceControl = surfaceClient->createSurface(
+ String8::format("AutomotiveDisplay::%lX", id),
+ displayWidth, displayHeight,
PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque);
- if (mSurfaceControl == nullptr || !mSurfaceControl->isValid()) {
- ALOGE("Failed to create SurfaceControl");
- mSurfaceComposerClient = nullptr;
- mSurfaceControl = nullptr;
+ if (surfaceControl == nullptr || !surfaceControl->isValid()) {
+ ALOGE("Failed to create SurfaceControl.");
return nullptr;
}
- // SurfaceControl::getSurface is guaranteed to be not null.
- mSurface = mSurfaceControl->getSurface();
+ // Store
+ DisplayDesc descriptor = {displayToken, surfaceControl};
+ mDisplays.insert_or_assign(id, std::move(descriptor));
+ } else {
+ displayToken = it->second.token;
+ surfaceControl = it->second.surfaceControl;
}
+ // SurfaceControl::getSurface is guaranteed to be not null.
+ auto targetSurface = surfaceControl->getSurface();
return new ::android::hardware::graphics::bufferqueue::V2_0::utils::
- B2HGraphicBufferProducer(
- mSurface->getIGraphicBufferProducer());
+ B2HGraphicBufferProducer(targetSurface->getIGraphicBufferProducer());
}
-Return<bool> AutomotiveDisplayProxyService::showWindow() {
- status_t status = NO_ERROR;
- if (mSurfaceControl != nullptr) {
- status = SurfaceComposerClient::Transaction{}
- .setLayer(
- mSurfaceControl, 0x7FFFFFFF) // always on top
- .show(mSurfaceControl)
- .apply();
- } else {
- ALOGE("showWindow: Failed to get a valid SurfaceControl!");
+Return<bool> AutomotiveDisplayProxyService::showWindow(uint64_t id) {
+ auto it = mDisplays.find(id);
+ if (it == mDisplays.end()) {
+ ALOGE("Given display token is invalid or unknown.");
return false;
}
+ ui::DisplayState displayState;
+ auto err = SurfaceComposerClient::getDisplayState(it->second.token, &displayState);
+ if (err != NO_ERROR) {
+ ALOGE("Failed to get current state of the display 0x%lX", id);
+ return false;
+ }
+
+ SurfaceComposerClient::Transaction t;
+ t.setDisplayLayerStack(it->second.token, displayState.layerStack);
+ t.setLayerStack(it->second.surfaceControl, displayState.layerStack);
+
+ status_t status = t.setLayer(it->second.surfaceControl, 0x7FFFFFFF)
+ .show(it->second.surfaceControl)
+ .apply();
+
return status == NO_ERROR;
}
-Return<bool> AutomotiveDisplayProxyService::hideWindow() {
- status_t status = NO_ERROR;
- if (mSurfaceControl != nullptr) {
- status = SurfaceComposerClient::Transaction{}
- .hide(mSurfaceControl)
- .apply();
- } else {
- ALOGE("hideWindow: Failed to get a valid SurfaceControl!");
+Return<bool> AutomotiveDisplayProxyService::hideWindow(uint64_t id) {
+ auto it = mDisplays.find(id);
+ if (it == mDisplays.end()) {
+ ALOGE("Given display token is invalid or unknown.");
return false;
}
+ status_t status = SurfaceComposerClient::Transaction{}
+ .hide(it->second.surfaceControl)
+ .apply();
+
return status == NO_ERROR;
}
+
+Return<void> AutomotiveDisplayProxyService::getDisplayIdList(getDisplayIdList_cb _cb) {
+ hardware::hidl_vec<uint64_t> ids;
+
+ // Get stable IDs of all available displays and get their tokens and
+ // descriptors.
+ auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
+ ids.resize(displayIds.size());
+ for (auto i = 0; i < displayIds.size(); ++i) {
+ ids[i] = displayIds[i];
+ }
+
+ _cb(ids);
+ return hardware::Void();
+}
+
+
+Return<void> AutomotiveDisplayProxyService::getDisplayInfo(uint64_t id, getDisplayInfo_cb _cb) {
+ HwDisplayConfig activeConfig;
+ HwDisplayState activeState;
+
+ auto displayToken = SurfaceComposerClient::getPhysicalDisplayToken(id);
+ if (displayToken == nullptr) {
+ ALOGE("Given display id, 0x%lX, is invalid.", id);
+ } else {
+ DisplayConfig displayConfig = {};
+ auto err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
+ if (err != NO_ERROR) {
+ ALOGW("Failed to get display configuration of %lX. "
+ "This display will be ignored.", id);
+ }
+
+ ui::DisplayState displayState = {};
+ err = SurfaceComposerClient::getDisplayState(displayToken, &displayState);
+ if (err != NO_ERROR) {
+ ALOGW("Failed to get current display status of %lX. "
+ "This display will be ignored.", id);
+ }
+
+ activeConfig.setToExternal((uint8_t*)&displayConfig, sizeof(DisplayConfig));
+ activeState.setToExternal((uint8_t*)&displayState, sizeof(DisplayState));
+ }
+
+ _cb(activeConfig, activeState);
+ return hardware::Void();
+}
+
+
} // namespace implementation
} // namespace V1_0
} // namespace display