From ffe1f19ca9707f84cb9fdb06209bf36cd8c2ef0a Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Fri, 22 Mar 2013 15:13:48 -0700 Subject: [PATCH] Fix virtual displays for HWC<=1.1 If we're using a HWC that doesn't support virtual displays, or we have more virtual displays than HWC supports concurrently, the VirtualDisplaySurface should simply be a passthrough from source (GLES) to sink. This change also tries to distinguish between display types and HWC display IDs a little better, though there's more to do here. Probably needs a higher-level rethink; it's too error-prone now. Bug: 8446838 Change-Id: I708d2cf262ec30177042304f174ca5b8da701df1 --- services/surfaceflinger/DisplayDevice.cpp | 95 +++++++++---------- services/surfaceflinger/DisplayDevice.h | 3 +- .../DisplayHardware/VirtualDisplaySurface.cpp | 32 +++++-- .../DisplayHardware/VirtualDisplaySurface.h | 16 +++- services/surfaceflinger/SurfaceFlinger.cpp | 10 +- 5 files changed, 86 insertions(+), 70 deletions(-) diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index cdc16edb9..6936a7f86 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -70,12 +70,13 @@ void checkGLErrors() DisplayDevice::DisplayDevice( const sp& flinger, DisplayType type, + int32_t hwcId, bool isSecure, const wp& displayToken, const sp& displaySurface, EGLConfig config) : mFlinger(flinger), - mType(type), mHwcDisplayId(-1), + mType(type), mHwcDisplayId(hwcId), mDisplayToken(displayToken), mDisplaySurface(displaySurface), mDisplay(EGL_NO_DISPLAY), @@ -91,7 +92,48 @@ DisplayDevice::DisplayDevice( mOrientation() { mNativeWindow = new Surface(mDisplaySurface->getIGraphicBufferProducer()); - init(config); + ANativeWindow* const window = mNativeWindow.get(); + + int format; + window->query(window, NATIVE_WINDOW_FORMAT, &format); + + /* + * Create our display's surface + */ + + EGLSurface surface; + EGLint w, h; + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + surface = eglCreateWindowSurface(display, config, window, NULL); + eglQuerySurface(display, surface, EGL_WIDTH, &mDisplayWidth); + eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight); + + mDisplay = display; + mSurface = surface; + mFormat = format; + mPageFlipCount = 0; + mViewport.makeInvalid(); + mFrame.makeInvalid(); + + // virtual displays are always considered enabled + mScreenAcquired = (mType >= DisplayDevice::DISPLAY_VIRTUAL); + + // Name the display. The name will be replaced shortly if the display + // was created with createDisplay(). + switch (mType) { + case DISPLAY_PRIMARY: + mDisplayName = "Built-in Screen"; + break; + case DISPLAY_EXTERNAL: + mDisplayName = "HDMI Screen"; + break; + default: + mDisplayName = "Virtual Screen"; // e.g. Overlay #n + break; + } + + // initialize the display orientation transform. + setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); } DisplayDevice::~DisplayDevice() { @@ -121,55 +163,6 @@ EGLSurface DisplayDevice::getEGLSurface() const { return mSurface; } -void DisplayDevice::init(EGLConfig config) -{ - ANativeWindow* const window = mNativeWindow.get(); - - int format; - window->query(window, NATIVE_WINDOW_FORMAT, &format); - - /* - * Create our display's surface - */ - - EGLSurface surface; - EGLint w, h; - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - surface = eglCreateWindowSurface(display, config, window, NULL); - eglQuerySurface(display, surface, EGL_WIDTH, &mDisplayWidth); - eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight); - - mDisplay = display; - mSurface = surface; - mFormat = format; - mPageFlipCount = 0; - mViewport.makeInvalid(); - mFrame.makeInvalid(); - - // external displays are always considered enabled - mScreenAcquired = (mType >= DisplayDevice::NUM_DISPLAY_TYPES); - - // get an h/w composer ID - mHwcDisplayId = mFlinger->allocateHwcDisplayId(mType); - - // Name the display. The name will be replaced shortly if the display - // was created with createDisplay(). - switch (mType) { - case DISPLAY_PRIMARY: - mDisplayName = "Built-in Screen"; - break; - case DISPLAY_EXTERNAL: - mDisplayName = "HDMI Screen"; - break; - default: - mDisplayName = "Virtual Screen"; // e.g. Overlay #n - break; - } - - // initialize the display orientation transform. - setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); -} - void DisplayDevice::setDisplayName(const String8& displayName) { if (!displayName.isEmpty()) { // never override the name with an empty name diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index d8f55b457..d4a6daaeb 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -72,6 +72,7 @@ public: DisplayDevice( const sp& flinger, DisplayType type, + int32_t hwcId, // negative for non-HWC-composited displays bool isSecure, const wp& displayToken, const sp& displaySurface, @@ -152,8 +153,6 @@ public: void dump(String8& result, char* buffer, size_t SIZE) const; private: - void init(EGLConfig config); - /* * Constants, set during initialization */ diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index b28500e8f..d2b3edb58 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -21,24 +21,30 @@ namespace android { // --------------------------------------------------------------------------- -VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int disp, +VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, const sp& sink, const String8& name) : mHwc(hwc), - mDisplayId(disp), - mSource(new BufferQueueInterposer(sink, name)), + mDisplayId(dispId), mName(name) -{} +{ + if (mDisplayId >= 0) { + mInterposer = new BufferQueueInterposer(sink, name); + mSourceProducer = mInterposer; + } else { + mSourceProducer = sink; + } +} VirtualDisplaySurface::~VirtualDisplaySurface() { if (mAcquiredBuffer != NULL) { - status_t result = mSource->releaseBuffer(Fence::NO_FENCE); + status_t result = mInterposer->releaseBuffer(Fence::NO_FENCE); ALOGE_IF(result != NO_ERROR, "VirtualDisplaySurface \"%s\": " "failed to release buffer: %d", mName.string(), result); } } sp VirtualDisplaySurface::getIGraphicBufferProducer() const { - return mSource; + return mSourceProducer; } status_t VirtualDisplaySurface::compositionComplete() { @@ -46,6 +52,9 @@ status_t VirtualDisplaySurface::compositionComplete() { } status_t VirtualDisplaySurface::advanceFrame() { + if (mInterposer == NULL) + return NO_ERROR; + Mutex::Autolock lock(mMutex); status_t result = NO_ERROR; @@ -57,12 +66,12 @@ status_t VirtualDisplaySurface::advanceFrame() { } sp fence; - result = mSource->acquireBuffer(&mAcquiredBuffer, &fence); + result = mInterposer->acquireBuffer(&mAcquiredBuffer, &fence); if (result == BufferQueueInterposer::NO_BUFFER_AVAILABLE) { - result = mSource->pullEmptyBuffer(); + result = mInterposer->pullEmptyBuffer(); if (result != NO_ERROR) return result; - result = mSource->acquireBuffer(&mAcquiredBuffer, &fence); + result = mInterposer->acquireBuffer(&mAcquiredBuffer, &fence); } if (result != NO_ERROR) return result; @@ -71,6 +80,9 @@ status_t VirtualDisplaySurface::advanceFrame() { } void VirtualDisplaySurface::onFrameCommitted() { + if (mInterposer == NULL) + return; + Mutex::Autolock lock(mMutex); if (mAcquiredBuffer != NULL) { // fbFence signals when reads from the framebuffer are finished @@ -85,7 +97,7 @@ void VirtualDisplaySurface::onFrameCommitted() { String8::format("HWC done: %.21s", mName.string()), fbFence, outFence); - status_t result = mSource->releaseBuffer(fence); + status_t result = mInterposer->releaseBuffer(fence); ALOGE_IF(result != NO_ERROR, "VirtualDisplaySurface \"%s\": " "failed to release buffer: %d", mName.string(), result); mAcquiredBuffer.clear(); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 61bafedde..0706e7566 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -45,12 +45,18 @@ class HWComposer; * eglSwapBuffers doesn't immediately dequeue a buffer for the next frame, * since we can't rely on being able to dequeue more than one buffer at a time. * + * This class also has a passthrough mode, where it doesn't use a + * BufferQueueInterposer and never sends buffers to HWC. Instead, OpenGL ES + * output buffers are queued directly to the virtual display sink; this class + * is inactive after construction. This mode is used when the HWC doesn't + * support compositing for virtual displays. + * * TODO(jessehall): Add a libgui test that ensures that EGL/GLES do lazy * dequeBuffers; we've wanted to require that for other reasons anyway. */ class VirtualDisplaySurface : public DisplaySurface { public: - VirtualDisplaySurface(HWComposer& hwc, int disp, + VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, const sp& sink, const String8& name); @@ -66,10 +72,14 @@ private: // immutable after construction HWComposer& mHwc; - int mDisplayId; - sp mSource; + int32_t mDisplayId; String8 mName; + // with HWC support, both of these point to the same object. + // otherwise, mInterposer is NULL and mSourceProducer is the sink. + sp mInterposer; + sp mSourceProducer; + // mutable, must be synchronized with mMutex Mutex mMutex; sp mAcquiredBuffer; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2df279ac6..0a210f7ac 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -510,7 +510,8 @@ status_t SurfaceFlinger::readyToRun() wp token = mBuiltinDisplays[i]; sp hw = new DisplayDevice(this, - type, isSecure, token, new FramebufferSurface(*mHwc, i), + type, allocateHwcDisplayId(type), isSecure, token, + new FramebufferSurface(*mHwc, i), mEGLConfig); if (i > DisplayDevice::DISPLAY_PRIMARY) { // FIXME: currently we don't get blank/unblank requests @@ -1149,10 +1150,11 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) const DisplayDeviceState& state(curr[i]); sp dispSurface; + int32_t hwcDisplayId = allocateHwcDisplayId(state.type); if (state.isVirtualDisplay()) { if (state.surface != NULL) { dispSurface = new VirtualDisplaySurface( - *mHwc, state.type, state.surface, + *mHwc, hwcDisplayId, state.surface, state.displayName); } } else { @@ -1169,8 +1171,8 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) const wp& display(curr.keyAt(i)); if (dispSurface != NULL) { sp hw = new DisplayDevice(this, - state.type, state.isSecure, display, - dispSurface, mEGLConfig); + state.type, hwcDisplayId, state.isSecure, + display, dispSurface, mEGLConfig); hw->setLayerStack(state.layerStack); hw->setProjection(state.orientation, state.viewport, state.frame);