teach HWC about multiple displays
Change-Id: I5e72a83d419a729835cb0e1ec45557b4d3fb56b1
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index a44b1e1..b1f8328 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -70,7 +70,7 @@
EventHandler& handler,
framebuffer_device_t const* fbDev)
: mFlinger(flinger),
- mModule(0), mHwc(0), mNumDisplays(1), mCapacity(0),
+ mModule(0), mHwc(0), mNumDisplays(1),
mCBContext(new cb_context),
mEventHandler(handler),
mVSyncCount(0), mDebugForceFakeVSync(false)
@@ -108,41 +108,46 @@
mHwc->registerProcs(mHwc, &mCBContext->procs);
}
- // these IDs are always reserved
- mTokens.markBit(HWC_DISPLAY_PRIMARY);
- mTokens.markBit(HWC_DISPLAY_EXTERNAL);
-
// always turn vsync off when we start
needVSyncThread = false;
-
mHwc->eventControl(mHwc, 0, HWC_EVENT_VSYNC, 0);
int period;
if (mHwc->query(mHwc, HWC_VSYNC_PERIOD, &period) == NO_ERROR) {
- mDisplayData[0].refresh = nsecs_t(period);
+ mDisplayData[HWC_DISPLAY_PRIMARY].refresh = nsecs_t(period);
}
- if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
- mNumDisplays = HWC_NUM_DISPLAY_TYPES;
+ // these IDs are always reserved
+ for (size_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
+ mAllocatedDisplayIDs.markBit(i);
+ // TODO: we query xdpi / ydpi / refresh
+ }
- // create initial empty display contents for display 0
- createWorkList(HWC_DISPLAY_PRIMARY, 0);
+ // the number of displays we actually have depends on the
+ // hw composer version
+ if (mHwc->common.version == HWC_DEVICE_API_VERSION_1_1) {
+ // 1.1 adds support for multiple displays
+ mNumDisplays = HWC_NUM_DISPLAY_TYPES;
+ } else if (mHwc->common.version > HWC_DEVICE_API_VERSION_1_1) {
+ // 1.2 adds support for virtual displays
+ mNumDisplays = MAX_DISPLAYS;
+ }
}
}
-
if (fbDev) {
- if (mDisplayData[HWC_DISPLAY_PRIMARY].refresh == 0) {
- mDisplayData[HWC_DISPLAY_PRIMARY].refresh = nsecs_t(1e9 / fbDev->fps);
- ALOGW("getting VSYNC period from fb HAL: %lld", mDisplayData[0].refresh);
+ // if we're here it means we are on version 1.0
+ DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
+ disp.xdpi = fbDev->xdpi;
+ disp.ydpi = fbDev->ydpi;
+ if (disp.refresh == 0) {
+ disp.refresh = nsecs_t(1e9 / fbDev->fps);
+ ALOGW("getting VSYNC period from fb HAL: %lld", disp.refresh);
}
- mDisplayData[HWC_DISPLAY_PRIMARY].xdpi = fbDev->xdpi;
- mDisplayData[HWC_DISPLAY_PRIMARY].ydpi = fbDev->ydpi;
- }
-
- if (mDisplayData[HWC_DISPLAY_PRIMARY].refresh == 0) {
- mDisplayData[HWC_DISPLAY_PRIMARY].refresh = nsecs_t(1e9 / 60.0);
- ALOGW("getting VSYNC period thin air: %lld", mDisplayData[0].refresh);
+ if (disp.refresh == 0) {
+ disp.refresh = nsecs_t(1e9 / 60.0);
+ ALOGW("getting VSYNC period thin air: %lld", mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
+ }
}
if (needVSyncThread) {
@@ -153,9 +158,6 @@
HWComposer::~HWComposer() {
mHwc->eventControl(mHwc, 0, EVENT_VSYNC, 0);
- for (size_t i = 0; i < MAX_DISPLAYS; i++) {
- free(mLists[i]);
- }
if (mVSyncThread != NULL) {
mVSyncThread->requestExitAndWait();
}
@@ -194,31 +196,28 @@
}
int32_t HWComposer::allocateDisplayId() {
- if (mTokens.isFull()) {
+ if (mAllocatedDisplayIDs.count() >= mNumDisplays) {
return NO_MEMORY;
}
-
- // FIXME: for now we don't support h/w composition wifi displays
- return -1;
-
- int32_t id = mTokens.firstUnmarkedBit();
- mTokens.markBit(id);
+ int32_t id = mAllocatedDisplayIDs.firstUnmarkedBit();
+ mAllocatedDisplayIDs.markBit(id);
return id;
}
status_t HWComposer::freeDisplayId(int32_t id) {
- if (id < MAX_DISPLAYS) {
+ if (id < HWC_NUM_DISPLAY_TYPES) {
+ // cannot free the reserved IDs
return BAD_VALUE;
}
- if (!mTokens.hasBit(id)) {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
return BAD_INDEX;
}
- mTokens.clearBit(id);
+ mAllocatedDisplayIDs.clearBit(id);
return NO_ERROR;
}
nsecs_t HWComposer::getRefreshPeriod() const {
- return mDisplayData[0].refresh;
+ return mDisplayData[HWC_DISPLAY_PRIMARY].refresh;
}
nsecs_t HWComposer::getRefreshTimestamp() const {
@@ -227,7 +226,7 @@
// the refresh period and whatever closest timestamp we have.
Mutex::Autolock _l(mLock);
nsecs_t now = systemTime(CLOCK_MONOTONIC);
- return now - ((now - mLastHwVSync) % mDisplayData[0].refresh);
+ return now - ((now - mLastHwVSync) % mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
}
float HWComposer::getDpiX() const {
@@ -256,67 +255,70 @@
}
status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
- if (!mTokens.hasBit(id)) {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
return BAD_INDEX;
}
- // FIXME: handle multiple displays
if (mHwc) {
- // TODO: must handle multiple displays here
- // mLists[0] is NULL only when this is called from the constructor
- if (!mLists[0] || mCapacity < numLayers) {
- free(mLists[0]);
- size_t size = sizeof(hwc_display_contents_1_t) + numLayers * sizeof(hwc_layer_1_t);
- mLists[0] = (hwc_display_contents_1_t*)malloc(size);
- mCapacity = numLayers;
+ DisplayData& disp(mDisplayData[id]);
+ if (disp.capacity < numLayers) {
+ const size_t size = sizeof(hwc_display_contents_1_t)
+ + numLayers * sizeof(hwc_layer_1_t);
+ free(disp.list);
+ disp.list = (hwc_display_contents_1_t*)malloc(size);
+ disp.capacity = numLayers;
}
- mLists[0]->flags = HWC_GEOMETRY_CHANGED;
- mLists[0]->numHwLayers = numLayers;
- mLists[0]->flipFenceFd = -1;
+ disp.list->flags = HWC_GEOMETRY_CHANGED;
+ disp.list->numHwLayers = numLayers;
+ disp.list->flipFenceFd = -1;
}
return NO_ERROR;
}
status_t HWComposer::prepare() {
- int err = mHwc->prepare(mHwc, mNumDisplays,
- const_cast<hwc_display_contents_1_t**>(mLists));
-
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ mLists[i] = mDisplayData[i].list;
+ if (mLists[i]) {
+ mLists[i]->dpy = EGL_NO_DISPLAY;
+ mLists[i]->sur = EGL_NO_SURFACE;
+ }
+ }
+ int err = mHwc->prepare(mHwc, mNumDisplays, mLists);
if (err == NO_ERROR) {
-
// here we're just making sure that "skip" layers are set
// to HWC_FRAMEBUFFER and we're also counting how many layers
// we have of each type.
- // It would be nice if we could get rid of this entirely, which I
- // think is almost possible.
-
- // TODO: must handle multiple displays here
-
- size_t count = getNumLayers(0);
- struct hwc_display_contents_1* disp = mLists[0];
- mDisplayData[0].hasFbComp = false;
- mDisplayData[0].hasOvComp = false;
- for (size_t i=0 ; i<count ; i++) {
- hwc_layer_1_t* l = &disp->hwLayers[i];
- if (l->flags & HWC_SKIP_LAYER) {
- l->compositionType = HWC_FRAMEBUFFER;
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ DisplayData& disp(mDisplayData[i]);
+ disp.hasFbComp = false;
+ disp.hasOvComp = false;
+ if (disp.list) {
+ for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
+ hwc_layer_1_t& l = disp.list->hwLayers[i];
+ if (l.flags & HWC_SKIP_LAYER) {
+ l.compositionType = HWC_FRAMEBUFFER;
+ }
+ if (l.compositionType == HWC_FRAMEBUFFER) {
+ disp.hasFbComp = true;
+ }
+ if (l.compositionType == HWC_OVERLAY) {
+ disp.hasOvComp = true;
+ }
+ }
}
- if (l->compositionType == HWC_FRAMEBUFFER)
- mDisplayData[HWC_DISPLAY_PRIMARY].hasFbComp = true;
- if (l->compositionType == HWC_OVERLAY)
- mDisplayData[HWC_DISPLAY_PRIMARY].hasOvComp = true;
}
}
return (status_t)err;
}
bool HWComposer::hasHwcComposition(int32_t id) const {
- if (!mTokens.hasBit(id))
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
return false;
return mDisplayData[id].hasOvComp;
}
bool HWComposer::hasGlesComposition(int32_t id) const {
- if (!mTokens.hasBit(id))
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
return false;
return mDisplayData[id].hasFbComp;
}
@@ -324,21 +326,26 @@
status_t HWComposer::commit() {
int err = NO_ERROR;
if (mHwc) {
- if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
- mLists[0]->dpy = EGL_NO_DISPLAY;
- mLists[0]->sur = EGL_NO_SURFACE;
- } else {
+ if (mHwc->common.version == HWC_DEVICE_API_VERSION_1_0) {
// On version 1.0, the OpenGL ES target surface is communicated
- // by the (dpy, sur) fields
+ // by the (dpy, sur) fields and we are guaranteed to have only
+ // a single display.
mLists[0]->dpy = eglGetCurrentDisplay();
mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW);
}
+
err = mHwc->set(mHwc, mNumDisplays, mLists);
- if (mLists[0]->flipFenceFd != -1) {
- close(mLists[0]->flipFenceFd);
- mLists[0]->flipFenceFd = -1;
+
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ DisplayData& disp(mDisplayData[i]);
+ if (disp.list) {
+ if (disp.list->flipFenceFd != -1) {
+ close(disp.list->flipFenceFd);
+ disp.list->flipFenceFd = -1;
+ }
+ disp.list->flags &= ~HWC_GEOMETRY_CHANGED;
+ }
}
- mLists[0]->flags &= ~HWC_GEOMETRY_CHANGED;
}
return (status_t)err;
}
@@ -358,17 +365,12 @@
return NO_ERROR;
}
-status_t HWComposer::disable() {
- if (mHwc) {
- mLists[0]->numHwLayers = 0;
- int err = mHwc->prepare(mHwc, mNumDisplays, mLists);
- return (status_t)err;
+size_t HWComposer::getNumLayers(int32_t id) const {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
+ return 0;
}
- return NO_ERROR;
-}
-
-size_t HWComposer::getNumLayers(int32_t id) const { // FIXME: handle multiple displays
- return mHwc ? mLists[0]->numHwLayers : 0;
+ return (mHwc && mDisplayData[id].list) ?
+ mDisplayData[id].list->numHwLayers : 0;
}
/*
@@ -470,14 +472,14 @@
* returns an iterator initialized at a given index in the layer list
*/
HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) {
- if (!mTokens.hasBit(id))
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
return LayerListIterator();
-
- // FIXME: handle multiple displays
- if (!mHwc || index > mLists[0]->numHwLayers)
+ }
+ const DisplayData& disp(mDisplayData[id]);
+ if (!mHwc || !disp.list || index > disp.list->numHwLayers) {
return LayerListIterator();
-
- return LayerListIterator(new HWCLayerVersion1(mLists[0]->hwLayers), index);
+ }
+ return LayerListIterator(new HWCLayerVersion1(disp.list->hwLayers), index);
}
/*
@@ -498,32 +500,36 @@
const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const {
if (mHwc) {
result.append("Hardware Composer state:\n");
- result.appendFormat(" mDebugForceFakeVSync=%d\n",
- mDebugForceFakeVSync);
- result.appendFormat(" numHwLayers=%u, flags=%08x\n",
- mLists[0]->numHwLayers, mLists[0]->flags);
- result.append(
- " type | handle | hints | flags | tr | blend | format | source crop | frame name \n"
- "----------+----------+----------+----------+----+-------+----------+---------------------------+--------------------------------\n");
- // " ________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____]
- for (size_t i=0 ; i<mLists[0]->numHwLayers ; i++) {
- hwc_layer_1_t const* lp= &mLists[0]->hwLayers[i];
- const sp<LayerBase> layer(visibleLayersSortedByZ[i]);
- int32_t format = -1;
- if (layer->getLayer() != NULL) {
- const sp<GraphicBuffer>& buffer(layer->getLayer()->getActiveBuffer());
- if (buffer != NULL) {
- format = buffer->getPixelFormat();
+ result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync);
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ const DisplayData& disp(mDisplayData[i]);
+ if (disp.list) {
+ result.appendFormat(" id=%d, numHwLayers=%u, flags=%08x\n",
+ i, disp.list->numHwLayers, disp.list->flags);
+ result.append(
+ " type | handle | hints | flags | tr | blend | format | source crop | frame name \n"
+ "----------+----------+----------+----------+----+-------+----------+---------------------------+--------------------------------\n");
+ // " ________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____]
+ for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
+ const hwc_layer_1_t&l = disp.list->hwLayers[i];
+ const sp<LayerBase> layer(visibleLayersSortedByZ[i]);
+ int32_t format = -1;
+ if (layer->getLayer() != NULL) {
+ const sp<GraphicBuffer>& buffer(
+ layer->getLayer()->getActiveBuffer());
+ if (buffer != NULL) {
+ format = buffer->getPixelFormat();
+ }
+ }
+ result.appendFormat(
+ " %8s | %08x | %08x | %08x | %02x | %05x | %08x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n",
+ l.compositionType ? "OVERLAY" : "FB",
+ intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format,
+ l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
+ l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
+ layer->getName().string());
}
}
- const hwc_layer_1_t& l(*lp);
- result.appendFormat(
- " %8s | %08x | %08x | %08x | %02x | %05x | %08x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n",
- l.compositionType ? "OVERLAY" : "FB",
- intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format,
- l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
- l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
- layer->getName().string());
}
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 857b82c..7b92d2e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -86,9 +86,6 @@
// Asks the HAL what it can do
status_t prepare();
- // disable hwc until next createWorkList
- status_t disable();
-
// commits the list
status_t commit();
@@ -254,12 +251,18 @@
struct DisplayData {
DisplayData() : xdpi(0), ydpi(0), refresh(0),
- hasFbComp(false), hasOvComp(false) { }
+ hasFbComp(false), hasOvComp(false),
+ capacity(0), list(NULL) { }
+ ~DisplayData() {
+ free(list);
+ }
float xdpi;
float ydpi;
nsecs_t refresh;
bool hasFbComp;
bool hasOvComp;
+ size_t capacity;
+ hwc_display_contents_1* list;
};
sp<SurfaceFlinger> mFlinger;
@@ -271,13 +274,12 @@
DisplayData mDisplayData[MAX_DISPLAYS];
size_t mNumDisplays;
- size_t mCapacity;
cb_context* mCBContext;
EventHandler& mEventHandler;
size_t mVSyncCount;
sp<VSyncThread> mVSyncThread;
bool mDebugForceFakeVSync;
- BitSet32 mTokens;
+ BitSet32 mAllocatedDisplayIDs;
// protected by mLock
mutable Mutex mLock;