reimplement wifi display hack with new external display SF framework
fix a few bugs with external displays - HWComposer doesn't really handle multiple displays yet so there is a lot of ugliness there - We also need to make sure that external displays are not blanked by default - due to some EGL limitations surfaces being swapped need to be current Change-Id: I82bff05b43bcebd8da863c7c76b4edbc3bc223a9
This commit is contained in:
parent
818b46058a
commit
5f20e2d446
|
@ -140,6 +140,9 @@ void DisplayDevice::init(EGLConfig config)
|
||||||
mFormat = format;
|
mFormat = format;
|
||||||
mPageFlipCount = 0;
|
mPageFlipCount = 0;
|
||||||
|
|
||||||
|
// external displays are always considered enabled
|
||||||
|
mScreenAcquired = mId >= DisplayDevice::DISPLAY_ID_COUNT;
|
||||||
|
|
||||||
// initialize the display orientation transform.
|
// initialize the display orientation transform.
|
||||||
DisplayDevice::setOrientation(DisplayState::eOrientationDefault);
|
DisplayDevice::setOrientation(DisplayState::eOrientationDefault);
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,7 +334,8 @@ void HWComposer::eventControl(int event, int enabled) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t HWComposer::createWorkList(int32_t id, size_t numLayers) { // FIXME: handle multiple displays
|
status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
|
||||||
|
// FIXME: handle multiple displays
|
||||||
if (uint32_t(id) >= MAX_DISPLAYS)
|
if (uint32_t(id) >= MAX_DISPLAYS)
|
||||||
return BAD_INDEX;
|
return BAD_INDEX;
|
||||||
|
|
||||||
|
@ -360,6 +361,15 @@ status_t HWComposer::prepare() const {
|
||||||
int err = hwcPrepare(mHwc, 1,
|
int err = hwcPrepare(mHwc, 1,
|
||||||
const_cast<hwc_display_contents_1_t**>(mLists));
|
const_cast<hwc_display_contents_1_t**>(mLists));
|
||||||
if (err == NO_ERROR) {
|
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 numOVLayers = 0;
|
size_t numOVLayers = 0;
|
||||||
size_t numFBLayers = 0;
|
size_t numFBLayers = 0;
|
||||||
size_t count = getNumLayers(0);
|
size_t count = getNumLayers(0);
|
||||||
|
@ -397,7 +407,15 @@ status_t HWComposer::prepare() const {
|
||||||
return (status_t)err;
|
return (status_t)err;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HWComposer::getLayerCount(int32_t id, int type) const { // FIXME: handle multiple displays
|
size_t HWComposer::getLayerCount(int32_t id, int type) const {
|
||||||
|
// FIXME: handle multiple displays
|
||||||
|
if (uint32_t(id) >= MAX_DISPLAYS) {
|
||||||
|
// FIXME: in practice this is only use to know
|
||||||
|
// if we have at least one layer of type.
|
||||||
|
return (type == HWC_FRAMEBUFFER) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case HWC_OVERLAY:
|
case HWC_OVERLAY:
|
||||||
return mNumOVLayers;
|
return mNumOVLayers;
|
||||||
|
@ -623,7 +641,11 @@ public:
|
||||||
/*
|
/*
|
||||||
* returns an iterator initialized at a given index in the layer list
|
* returns an iterator initialized at a given index in the layer list
|
||||||
*/
|
*/
|
||||||
HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) { // FIXME: handle multiple displays
|
HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) {
|
||||||
|
// FIXME: handle multiple displays
|
||||||
|
if (uint32_t(id) >= MAX_DISPLAYS)
|
||||||
|
return LayerListIterator();
|
||||||
|
|
||||||
if (!mHwc || index > hwcNumHwLayers(mHwc, mLists[0]))
|
if (!mHwc || index > hwcNumHwLayers(mHwc, mLists[0]))
|
||||||
return LayerListIterator();
|
return LayerListIterator();
|
||||||
if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
|
if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
|
||||||
|
@ -638,14 +660,14 @@ HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t in
|
||||||
/*
|
/*
|
||||||
* returns an iterator on the beginning of the layer list
|
* returns an iterator on the beginning of the layer list
|
||||||
*/
|
*/
|
||||||
HWComposer::LayerListIterator HWComposer::begin(int32_t id) { // FIXME: handle multiple displays
|
HWComposer::LayerListIterator HWComposer::begin(int32_t id) {
|
||||||
return getLayerIterator(id, 0);
|
return getLayerIterator(id, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns an iterator on the end of the layer list
|
* returns an iterator on the end of the layer list
|
||||||
*/
|
*/
|
||||||
HWComposer::LayerListIterator HWComposer::end(int32_t id) { // FIXME: handle multiple displays
|
HWComposer::LayerListIterator HWComposer::end(int32_t id) {
|
||||||
return getLayerIterator(id, getNumLayers(id));
|
return getLayerIterator(id, getNumLayers(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -426,10 +426,10 @@ void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
|
||||||
|
|
||||||
snprintf(buffer, SIZE,
|
snprintf(buffer, SIZE,
|
||||||
" "
|
" "
|
||||||
"z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
|
"layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
|
||||||
"isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
|
"isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
|
||||||
"alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
|
"alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
|
||||||
s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
|
s.z, s.layerStack, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
|
||||||
s.active.crop.left, s.active.crop.top,
|
s.active.crop.left, s.active.crop.top,
|
||||||
s.active.crop.right, s.active.crop.bottom,
|
s.active.crop.right, s.active.crop.bottom,
|
||||||
isOpaque(), needsDithering(), contentDirty,
|
isOpaque(), needsDithering(), contentDirty,
|
||||||
|
|
|
@ -95,8 +95,7 @@ SurfaceFlinger::SurfaceFlinger()
|
||||||
mLastSwapBufferTime(0),
|
mLastSwapBufferTime(0),
|
||||||
mDebugInTransaction(0),
|
mDebugInTransaction(0),
|
||||||
mLastTransactionTime(0),
|
mLastTransactionTime(0),
|
||||||
mBootFinished(false),
|
mBootFinished(false)
|
||||||
mExternalDisplaySurface(EGL_NO_SURFACE)
|
|
||||||
{
|
{
|
||||||
ALOGI("SurfaceFlinger is starting");
|
ALOGI("SurfaceFlinger is starting");
|
||||||
|
|
||||||
|
@ -555,40 +554,34 @@ sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
|
||||||
return mEventThread->createEventConnection();
|
return mEventThread->createEventConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfaceFlinger::connectDisplay(const sp<ISurfaceTexture> display) {
|
void SurfaceFlinger::connectDisplay(const sp<ISurfaceTexture> surface) {
|
||||||
EGLSurface result = EGL_NO_SURFACE;
|
|
||||||
EGLSurface old_surface = EGL_NO_SURFACE;
|
|
||||||
sp<SurfaceTextureClient> stc;
|
|
||||||
|
|
||||||
if (display != NULL) {
|
sp<IBinder> token;
|
||||||
stc = new SurfaceTextureClient(display);
|
{ // scope for the lock
|
||||||
result = eglCreateWindowSurface(mEGLDisplay,
|
Mutex::Autolock _l(mStateLock);
|
||||||
mEGLConfig, (EGLNativeWindowType)stc.get(), NULL);
|
token = mExtDisplayToken;
|
||||||
ALOGE_IF(result == EGL_NO_SURFACE,
|
}
|
||||||
"eglCreateWindowSurface failed (ISurfaceTexture=%p)",
|
|
||||||
display.get());
|
if (token == 0) {
|
||||||
|
token = createDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // scope for the lock
|
{ // scope for the lock
|
||||||
Mutex::Autolock _l(mStateLock);
|
Mutex::Autolock _l(mStateLock);
|
||||||
old_surface = mExternalDisplaySurface;
|
if (surface == 0) {
|
||||||
mExternalDisplayNativeWindow = stc;
|
// release our current display. we're guarantee to have
|
||||||
mExternalDisplaySurface = result;
|
// a reference to it (token), while we hold the lock
|
||||||
ALOGD("mExternalDisplaySurface = %p", result);
|
mExtDisplayToken = 0;
|
||||||
}
|
} else {
|
||||||
|
mExtDisplayToken = token;
|
||||||
|
}
|
||||||
|
|
||||||
if (old_surface != EGL_NO_SURFACE) {
|
DisplayDeviceState& info(mCurrentState.displays.editValueFor(token));
|
||||||
// Note: EGL allows to destroy an object while its current
|
info.surface = surface;
|
||||||
// it will fail to become current next time though.
|
setTransactionFlags(eDisplayTransactionNeeded);
|
||||||
eglDestroySurface(mEGLDisplay, old_surface);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLSurface SurfaceFlinger::getExternalDisplaySurface() const {
|
|
||||||
Mutex::Autolock _l(mStateLock);
|
|
||||||
return mExternalDisplaySurface;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
void SurfaceFlinger::waitForEvent() {
|
void SurfaceFlinger::waitForEvent() {
|
||||||
|
@ -757,49 +750,6 @@ void SurfaceFlinger::handleMessageRefresh() {
|
||||||
}
|
}
|
||||||
|
|
||||||
postFramebuffer();
|
postFramebuffer();
|
||||||
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
// render to the external display if we have one
|
|
||||||
EGLSurface externalDisplaySurface = getExternalDisplaySurface();
|
|
||||||
if (externalDisplaySurface != EGL_NO_SURFACE) {
|
|
||||||
EGLSurface cur = eglGetCurrentSurface(EGL_DRAW);
|
|
||||||
EGLBoolean success = eglMakeCurrent(eglGetCurrentDisplay(),
|
|
||||||
externalDisplaySurface, externalDisplaySurface,
|
|
||||||
eglGetCurrentContext());
|
|
||||||
|
|
||||||
ALOGE_IF(!success, "eglMakeCurrent -> external failed");
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
// redraw the screen entirely...
|
|
||||||
glDisable(GL_TEXTURE_EXTERNAL_OES);
|
|
||||||
glDisable(GL_TEXTURE_2D);
|
|
||||||
glClearColor(0,0,0,1);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glLoadIdentity();
|
|
||||||
|
|
||||||
const sp<DisplayDevice>& hw(getDisplayDevice(0));
|
|
||||||
const Vector< sp<LayerBase> >& layers( hw->getVisibleLayersSortedByZ() );
|
|
||||||
const size_t count = layers.size();
|
|
||||||
for (size_t i=0 ; i<count ; ++i) {
|
|
||||||
const sp<LayerBase>& layer(layers[i]);
|
|
||||||
layer->draw(hw);
|
|
||||||
}
|
|
||||||
|
|
||||||
success = eglSwapBuffers(eglGetCurrentDisplay(), externalDisplaySurface);
|
|
||||||
ALOGE_IF(!success, "external display eglSwapBuffers failed");
|
|
||||||
|
|
||||||
hw->compositionComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
success = eglMakeCurrent(eglGetCurrentDisplay(),
|
|
||||||
cur, cur, eglGetCurrentContext());
|
|
||||||
|
|
||||||
ALOGE_IF(!success, "eglMakeCurrent -> internal failed");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfaceFlinger::postFramebuffer()
|
void SurfaceFlinger::postFramebuffer()
|
||||||
|
@ -830,6 +780,10 @@ void SurfaceFlinger::postFramebuffer()
|
||||||
|
|
||||||
if (hwc.initCheck() == NO_ERROR) {
|
if (hwc.initCheck() == NO_ERROR) {
|
||||||
// FIXME: eventually commit() won't take arguments
|
// FIXME: eventually commit() won't take arguments
|
||||||
|
// FIXME: EGL spec says:
|
||||||
|
// "surface must be bound to the calling thread's current context,
|
||||||
|
// for the current rendering API."
|
||||||
|
DisplayDevice::makeCurrent(getDisplayDevice(DisplayDevice::DISPLAY_ID_MAIN), mEGLContext);
|
||||||
hwc.commit(mEGLDisplay, getDefaultDisplayDevice()->getEGLSurface());
|
hwc.commit(mEGLDisplay, getDefaultDisplayDevice()->getEGLSurface());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,14 +798,22 @@ void SurfaceFlinger::postFramebuffer()
|
||||||
for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
|
for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
|
||||||
currentLayers[i]->onLayerDisplayed(hw, &*cur);
|
currentLayers[i]->onLayerDisplayed(hw, &*cur);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
// FIXME: we need to call eglSwapBuffers() on displays that have
|
||||||
|
// GL composition and only on those.
|
||||||
|
// however, currently hwc.commit() already does that for the main
|
||||||
|
// display and never for the other ones
|
||||||
|
if (hw->getDisplayId() >= DisplayDevice::DISPLAY_ID_COUNT) {
|
||||||
|
// FIXME: EGL spec says:
|
||||||
|
// "surface must be bound to the calling thread's current context,
|
||||||
|
// for the current rendering API."
|
||||||
|
DisplayDevice::makeCurrent(hw, mEGLContext);
|
||||||
eglSwapBuffers(mEGLDisplay, hw->getEGLSurface());
|
eglSwapBuffers(mEGLDisplay, hw->getEGLSurface());
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
currentLayers[i]->onLayerDisplayed(hw, NULL);
|
currentLayers[i]->onLayerDisplayed(hw, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: we need to call eglSwapBuffers() on displays that have GL composition
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mLastSwapBufferTime = systemTime() - now;
|
mLastSwapBufferTime = systemTime() - now;
|
||||||
|
@ -967,7 +929,6 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
|
||||||
// (ie: in current state but not in drawing state)
|
// (ie: in current state but not in drawing state)
|
||||||
for (size_t i=0 ; i<cc ; i++) {
|
for (size_t i=0 ; i<cc ; i++) {
|
||||||
if (draw.indexOfKey(curr.keyAt(i)) < 0) {
|
if (draw.indexOfKey(curr.keyAt(i)) < 0) {
|
||||||
// FIXME: we need to pass the surface here
|
|
||||||
const DisplayDeviceState& state(curr[i]);
|
const DisplayDeviceState& state(curr[i]);
|
||||||
sp<SurfaceTextureClient> stc(
|
sp<SurfaceTextureClient> stc(
|
||||||
new SurfaceTextureClient(state.surface));
|
new SurfaceTextureClient(state.surface));
|
||||||
|
@ -1954,6 +1915,26 @@ void SurfaceFlinger::dumpAllLocked(
|
||||||
layer->shortDump(result, buffer, SIZE);
|
layer->shortDump(result, buffer, SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump Display state
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
|
||||||
|
const sp<const DisplayDevice>& hw(mDisplays[dpy]);
|
||||||
|
snprintf(buffer, SIZE,
|
||||||
|
"+ DisplayDevice[%u]\n"
|
||||||
|
" id=%x, layerStack=%u, (%4dx%4d), orient=%2d, tr=%08x, "
|
||||||
|
"flips=%u, secure=%d, numLayers=%u\n",
|
||||||
|
dpy,
|
||||||
|
hw->getDisplayId(), hw->getLayerStack(),
|
||||||
|
hw->getWidth(), hw->getHeight(),
|
||||||
|
hw->getOrientation(), hw->getTransform().getType(),
|
||||||
|
hw->getPageFlipCount(),
|
||||||
|
hw->getSecureLayerVisible(),
|
||||||
|
hw->getVisibleLayersSortedByZ().size());
|
||||||
|
result.append(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dump SurfaceFlinger global state
|
* Dump SurfaceFlinger global state
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -428,9 +428,7 @@ private:
|
||||||
* Feature prototyping
|
* Feature prototyping
|
||||||
*/
|
*/
|
||||||
|
|
||||||
EGLSurface getExternalDisplaySurface() const;
|
sp<IBinder> mExtDisplayToken;
|
||||||
sp<SurfaceTextureClient> mExternalDisplayNativeWindow;
|
|
||||||
EGLSurface mExternalDisplaySurface;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue