From 4fec873a98f7b4380720cd1ad006f74c8cdc73da Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 29 Jun 2012 14:12:52 -0700 Subject: [PATCH] one more step towards multiple display support - remove dependency on cached state in validateVisibility - get rid of mVertices and mTransformedBounds - get rid of validateVisibility - get rid of unlockPageFlip - handleTransaction now returns a dirty region - computevisibileregion now uses window-manager space --- include/utils/Vector.h | 8 +- services/surfaceflinger/Layer.cpp | 82 ++--- services/surfaceflinger/Layer.h | 9 +- services/surfaceflinger/LayerBase.cpp | 107 +++--- services/surfaceflinger/LayerBase.h | 60 ++-- services/surfaceflinger/LayerDim.cpp | 7 +- services/surfaceflinger/LayerScreenshot.cpp | 7 +- services/surfaceflinger/MessageQueue.cpp | 30 +- services/surfaceflinger/MessageQueue.h | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 356 ++++++++++---------- services/surfaceflinger/SurfaceFlinger.h | 19 +- 11 files changed, 355 insertions(+), 334 deletions(-) diff --git a/include/utils/Vector.h b/include/utils/Vector.h index e39a5b759..a89393ff2 100644 --- a/include/utils/Vector.h +++ b/include/utils/Vector.h @@ -72,11 +72,11 @@ public: //! returns number of items in the vector inline size_t size() const { return VectorImpl::size(); } - //! returns wether or not the vector is empty + //! returns whether or not the vector is empty inline bool isEmpty() const { return VectorImpl::isEmpty(); } //! returns how many items can be stored without reallocating the backing store inline size_t capacity() const { return VectorImpl::capacity(); } - //! setst the capacity. capacity can never be reduced less than size() + //! sets the capacity. capacity can never be reduced less than size() inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); } /*! @@ -102,12 +102,12 @@ public: const TYPE& mirrorItemAt(ssize_t index) const; /*! - * modifing the array + * modifying the array */ //! copy-on write support, grants write access to an item TYPE& editItemAt(size_t index); - //! grants right acces to the top of the stack (last element) + //! grants right access to the top of the stack (last element) TYPE& editTop(); /*! diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 0d1cb45bb..a09b5c7bf 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -145,14 +145,6 @@ void Layer::setName(const String8& name) { mSurfaceTexture->setName(name); } -void Layer::validateVisibility(const Transform& globalTransform, const DisplayHardware& hw) { - LayerBase::validateVisibility(globalTransform, hw); - - // This optimization allows the SurfaceTexture to bake in - // the rotation so hardware overlays can be used - mSurfaceTexture->setTransformHint(getTransformHint()); -} - sp Layer::createSurface() { class BSurface : public BnSurface, public LayerCleaner { @@ -225,7 +217,8 @@ Rect Layer::computeBufferCrop() const { } else if (mActiveBuffer != NULL){ crop = Rect(mActiveBuffer->getWidth(), mActiveBuffer->getHeight()); } else { - crop = Rect(mTransformedBounds.width(), mTransformedBounds.height()); + crop.makeInvalid(); + return crop; } // ... then reduce that in the same proportions as the window crop reduces @@ -258,9 +251,11 @@ Rect Layer::computeBufferCrop() const { return crop; } -void Layer::setGeometry(HWComposer::HWCLayerInterface& layer) +void Layer::setGeometry( + const DisplayHardware& hw, + HWComposer::HWCLayerInterface& layer) { - LayerBaseClient::setGeometry(layer); + LayerBaseClient::setGeometry(hw, layer); // enable this layer layer.setSkip(false); @@ -276,12 +271,11 @@ void Layer::setGeometry(HWComposer::HWCLayerInterface& layer) * 1) buffer orientation/flip/mirror * 2) state transformation (window manager) * 3) layer orientation (screen orientation) - * mTransform is already the composition of (2) and (3) * (NOTE: the matrices are multiplied in reverse order) */ const Transform bufferOrientation(mCurrentTransform); - const Transform tr(mTransform * bufferOrientation); + const Transform tr(hw.getTransform() * s.transform * bufferOrientation); // this gives us only the "orientation" component of the transform const uint32_t finalTransform = tr.getOrientation(); @@ -339,7 +333,7 @@ void Layer::onDraw(const DisplayHardware& hw, const Region& clip) const const sp& layer(drawingLayers[i]); if (layer.get() == static_cast(this)) break; - under.orSelf(layer->visibleRegionScreen); + under.orSelf( hw.getTransform().transform(layer->visibleRegion) ); } // if not everything below us is covered, we plug the holes! Region holes(clip.subtract(under)); @@ -527,10 +521,11 @@ bool Layer::onPreComposition() { return mQueuedFrames > 0; } -void Layer::lockPageFlip(bool& recomputeVisibleRegions) +Region Layer::latchBuffer(bool& recomputeVisibleRegions) { ATRACE_CALL(); + Region outDirtyRegion; if (mQueuedFrames > 0) { // if we've already called updateTexImage() without going through @@ -539,8 +534,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) // compositionComplete() call. // we'll trigger an update in onPreComposition(). if (mRefreshPending) { - mPostedDirtyRegion.clear(); - return; + return outDirtyRegion; } // Capture the old state of the layer for comparisons later @@ -637,17 +631,21 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) Reject r(mDrawingState, currentState(), recomputeVisibleRegions); + // XXX: not sure if setTransformHint belongs here + // it should only be needed when the main screen orientation changes + mSurfaceTexture->setTransformHint(getTransformHint()); + if (mSurfaceTexture->updateTexImage(&r) < NO_ERROR) { // something happened! recomputeVisibleRegions = true; - return; + return outDirtyRegion; } // update the active buffer mActiveBuffer = mSurfaceTexture->getCurrentBuffer(); if (mActiveBuffer == NULL) { // this can only happen if the very first buffer was rejected. - return; + return outDirtyRegion; } mRefreshPending = true; @@ -686,38 +684,17 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) recomputeVisibleRegions = true; } - // FIXME: mPostedDirtyRegion = dirty & bounds - const Layer::State& front(drawingState()); - mPostedDirtyRegion.set(front.active.w, front.active.h); - glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // FIXME: postedRegion should be dirty & bounds + const Layer::State& front(drawingState()); + Region dirtyRegion(Rect(front.active.w, front.active.h)); + + // transform the dirty region to window-manager space + outDirtyRegion = (front.transform.transform(dirtyRegion)); } -} - -void Layer::unlockPageFlip( - const Transform& planeTransform, Region& outDirtyRegion) -{ - ATRACE_CALL(); - - Region postedRegion(mPostedDirtyRegion); - if (!postedRegion.isEmpty()) { - mPostedDirtyRegion.clear(); - if (!visibleRegionScreen.isEmpty()) { - // The dirty region is given in the layer's coordinate space - // transform the dirty region by the surface's transformation - // and the global transformation. - const Layer::State& s(drawingState()); - const Transform tr(planeTransform * s.transform); - postedRegion = tr.transform(postedRegion); - - // At this point, the dirty region is in screen space. - // Make sure it's constrained by the visible region (which - // is in screen space as well). - postedRegion.andSelf(visibleRegionScreen); - outDirtyRegion.orSelf(postedRegion); - } - } + return outDirtyRegion; } void Layer::dump(String8& result, char* buffer, size_t SIZE) const @@ -786,7 +763,14 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const uint32_t Layer::getTransformHint() const { uint32_t orientation = 0; if (!mFlinger->mDebugDisableTransformHint) { - orientation = getPlaneOrientation(); + // The transform hint is used to improve performance on the main + // display -- we can only have a single transform hint, it cannot + // apply to all displays. + // This is why we use the default display here. This is not an + // oversight. + const DisplayHardware& hw(mFlinger->getDefaultDisplayHardware()); + const Transform& planeTransform(hw.getTransform()); + orientation = planeTransform.getOrientation(); if (orientation & Transform::ROT_INVALID) { orientation = 0; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index b6ae0ae80..239250de7 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -64,20 +64,20 @@ public: bool isFixedSize() const; // LayerBase interface - virtual void setGeometry(HWComposer::HWCLayerInterface& layer); + virtual void setGeometry(const DisplayHardware& hw, + HWComposer::HWCLayerInterface& layer); virtual void setPerFrameData(HWComposer::HWCLayerInterface& layer); virtual void setAcquireFence(HWComposer::HWCLayerInterface& layer); + virtual void onDraw(const DisplayHardware& hw, const Region& clip) const; virtual uint32_t doTransaction(uint32_t transactionFlags); - virtual void lockPageFlip(bool& recomputeVisibleRegions); - virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); + virtual Region latchBuffer(bool& recomputeVisibleRegions); virtual bool isOpaque() const; virtual bool isSecure() const { return mSecure; } virtual bool isProtected() const; virtual void onRemoved(); virtual sp getLayer() const { return const_cast(this); } virtual void setName(const String8& name); - virtual void validateVisibility(const Transform& globalTransform, const DisplayHardware& hw); // LayerBaseClient interface virtual wp getSurfaceTextureBinder() const; @@ -142,7 +142,6 @@ private: // page-flip thread (currently main thread) bool mSecure; // no screenshots bool mProtectedByApp; // application requires protected path to external sink - Region mPostedDirtyRegion; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index 8350d27ce..2070cb971 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -45,8 +45,6 @@ LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display) sequence(uint32_t(android_atomic_inc(&sSequence))), mFlinger(flinger), mFiltering(false), mNeedsFiltering(false), - mOrientation(0), - mPlaneOrientation(0), mTransactionFlags(0), mPremultipliedAlpha(true), mName("unnamed"), mDebug(false) { @@ -170,19 +168,14 @@ bool LayerBase::setCrop(const Rect& crop) { return true; } -Rect LayerBase::visibleBounds() const -{ - return mTransformedBounds; -} - void LayerBase::setVisibleRegion(const Region& visibleRegion) { // always called from main thread - visibleRegionScreen = visibleRegion; + this->visibleRegion = visibleRegion; } void LayerBase::setCoveredRegion(const Region& coveredRegion) { // always called from main thread - coveredRegionScreen = coveredRegion; + this->coveredRegion = coveredRegion; } uint32_t LayerBase::doTransaction(uint32_t flags) @@ -219,57 +212,45 @@ uint32_t LayerBase::doTransaction(uint32_t flags) return flags; } -void LayerBase::validateVisibility(const Transform& planeTransform, const DisplayHardware& hw) +void LayerBase::computeGeometry(const DisplayHardware& hw, LayerMesh* mesh) const { const Layer::State& s(drawingState()); - const Transform tr(planeTransform * s.transform); - const bool transformed = tr.transformed(); + const Transform tr(hw.getTransform() * s.transform); const uint32_t hw_h = hw.getHeight(); const Rect& crop(s.active.crop); - Rect win(s.active.w, s.active.h); if (!crop.isEmpty()) { win.intersect(crop, &win); } - - mNumVertices = 4; - tr.transform(mVertices[0], win.left, win.top); - tr.transform(mVertices[1], win.left, win.bottom); - tr.transform(mVertices[2], win.right, win.bottom); - tr.transform(mVertices[3], win.right, win.top); - for (size_t i=0 ; i<4 ; i++) - mVertices[i][1] = hw_h - mVertices[i][1]; - - if (CC_UNLIKELY(transformed)) { - // NOTE: here we could also punt if we have too many rectangles - // in the transparent region - if (tr.preserveRects()) { - // transform the transparent region - transparentRegionScreen = tr.transform(s.transparentRegion); - } else { - // transformation too complex, can't do the transparent region - // optimization. - transparentRegionScreen.clear(); + if (mesh) { + tr.transform(mesh->mVertices[0], win.left, win.top); + tr.transform(mesh->mVertices[1], win.left, win.bottom); + tr.transform(mesh->mVertices[2], win.right, win.bottom); + tr.transform(mesh->mVertices[3], win.right, win.top); + for (size_t i=0 ; i<4 ; i++) { + mesh->mVertices[i][1] = hw_h - mesh->mVertices[i][1]; } - } else { - transparentRegionScreen = s.transparentRegion; } - - // cache a few things... - mOrientation = tr.getOrientation(); - mPlaneOrientation = planeTransform.getOrientation(); - mTransform = tr; - mTransformedBounds = tr.transform(win); } -void LayerBase::lockPageFlip(bool& recomputeVisibleRegions) { +Rect LayerBase::computeBounds() const { + const Layer::State& s(drawingState()); + const Rect& crop(s.active.crop); + Rect win(s.active.w, s.active.h); + if (!crop.isEmpty()) { + win.intersect(crop, &win); + } + return s.transform.transform(win); } -void LayerBase::unlockPageFlip( - const Transform& planeTransform, Region& outDirtyRegion) { +Region LayerBase::latchBuffer(bool& recomputeVisibleRegions) { + Region result; + return result; } -void LayerBase::setGeometry(HWComposer::HWCLayerInterface& layer) +void LayerBase::setGeometry( + const DisplayHardware& hw, + HWComposer::HWCLayerInterface& layer) { layer.setDefaultState(); @@ -289,10 +270,14 @@ void LayerBase::setGeometry(HWComposer::HWCLayerInterface& layer) HWC_BLENDING_COVERAGE); } - // scaling is already applied in mTransformedBounds - layer.setFrame(mTransformedBounds); - layer.setVisibleRegionScreen(visibleRegionScreen); - layer.setCrop(mTransformedBounds.getBounds()); + const Transform& tr = hw.getTransform(); + Rect transformedBounds(computeBounds()); + transformedBounds = tr.transform(transformedBounds); + + // scaling is already applied in transformedBounds + layer.setFrame(transformedBounds); + layer.setCrop(transformedBounds.getBounds()); + layer.setVisibleRegionScreen(tr.transform(visibleRegion)); } void LayerBase::setPerFrameData(HWComposer::HWCLayerInterface& layer) { @@ -335,8 +320,11 @@ void LayerBase::clearWithOpenGL(const DisplayHardware& hw, const Region& clip, glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); - glVertexPointer(2, GL_FLOAT, 0, mVertices); - glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices); + LayerMesh mesh; + computeGeometry(hw, &mesh); + + glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); + glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); } void LayerBase::clearWithOpenGL(const DisplayHardware& hw, const Region& clip) const @@ -371,6 +359,12 @@ void LayerBase::drawWithOpenGL(const DisplayHardware& hw, const Region& clip) co } } + LayerMesh mesh; + computeGeometry(hw, &mesh); + + // TODO: we probably want to generate the texture coords with the mesh + // here we assume that we only have 4 vertices + struct TexCoords { GLfloat u; GLfloat v; @@ -380,9 +374,9 @@ void LayerBase::drawWithOpenGL(const DisplayHardware& hw, const Region& clip) co if (!s.active.crop.isEmpty()) { crop = s.active.crop; } - GLfloat left = GLfloat(crop.left) / GLfloat(s.active.w); - GLfloat top = GLfloat(crop.top) / GLfloat(s.active.h); - GLfloat right = GLfloat(crop.right) / GLfloat(s.active.w); + GLfloat left = GLfloat(crop.left) / GLfloat(s.active.w); + GLfloat top = GLfloat(crop.top) / GLfloat(s.active.h); + GLfloat right = GLfloat(crop.right) / GLfloat(s.active.w); GLfloat bottom = GLfloat(crop.bottom) / GLfloat(s.active.h); TexCoords texCoords[4]; @@ -399,9 +393,9 @@ void LayerBase::drawWithOpenGL(const DisplayHardware& hw, const Region& clip) co } glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, mVertices); glTexCoordPointer(2, GL_FLOAT, 0, texCoords); - glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices); + glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); + glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_BLEND); @@ -417,8 +411,7 @@ void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const result.append(buffer); s.transparentRegion.dump(result, "transparentRegion"); - transparentRegionScreen.dump(result, "transparentRegionScreen"); - visibleRegionScreen.dump(result, "visibleRegionScreen"); + visibleRegion.dump(result, "visibleRegion"); snprintf(buffer, SIZE, " " diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h index 83e871c11..d227b2d39 100644 --- a/services/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h @@ -57,9 +57,9 @@ public: DisplayID dpy; mutable bool contentDirty; - Region visibleRegionScreen; - Region transparentRegionScreen; - Region coveredRegionScreen; + // regions below are in window-manager space + Region visibleRegion; + Region coveredRegion; int32_t sequence; struct Geometry { @@ -86,6 +86,20 @@ public: Region transparentRegion; }; + class LayerMesh { + friend class LayerBase; + GLfloat mVertices[4][2]; + size_t mNumVertices; + public: + LayerMesh() : mNumVertices(4) { } + GLfloat const* getVertices() const { + return &mVertices[0][0]; + } + size_t getVertexCount() const { + return mNumVertices; + } + }; + virtual void setName(const String8& name); String8 getName() const; @@ -105,15 +119,18 @@ public: uint32_t getTransactionFlags(uint32_t flags); uint32_t setTransactionFlags(uint32_t flags); - - Rect visibleBounds() const; + + void computeGeometry(const DisplayHardware& hw, LayerMesh* mesh) const; + Rect computeBounds() const; + virtual sp getLayerBaseClient() const { return 0; } virtual sp getLayer() const { return 0; } virtual const char* getTypeId() const { return "LayerBase"; } - virtual void setGeometry(HWComposer::HWCLayerInterface& layer); + virtual void setGeometry(const DisplayHardware& hw, + HWComposer::HWCLayerInterface& layer); virtual void setPerFrameData(HWComposer::HWCLayerInterface& layer); virtual void setAcquireFence(HWComposer::HWCLayerInterface& layer); @@ -156,26 +173,13 @@ public: virtual void setCoveredRegion(const Region& coveredRegion); /** - * validateVisibility - cache a bunch of things - */ - virtual void validateVisibility(const Transform& globalTransform, const DisplayHardware& hw); - - /** - * lockPageFlip - called each time the screen is redrawn and returns whether + * latchBuffer - called each time the screen is redrawn and returns whether * the visible regions need to be recomputed (this is a fairly heavy * operation, so this should be set only if needed). Typically this is used * to figure out if the content or size of a surface has changed. */ - virtual void lockPageFlip(bool& recomputeVisibleRegions); - - /** - * unlockPageFlip - called each time the screen is redrawn. updates the - * final dirty region wrt the planeTransform. - * At this point, all visible regions, surface position and size, etc... are - * correct. - */ - virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); - + virtual Region latchBuffer(bool& recomputeVisibleRegions); + /** * isOpaque - true if this surface is opaque */ @@ -233,9 +237,6 @@ public: inline const State& currentState() const { return mCurrentState; } inline State& currentState() { return mCurrentState; } - int32_t getOrientation() const { return mOrientation; } - int32_t getPlaneOrientation() const { return mPlaneOrientation; } - void clearWithOpenGL(const DisplayHardware& hw, const Region& clip) const; protected: @@ -253,19 +254,10 @@ private: // Whether filtering is forced on or not bool mFiltering; - // cached during validateVisibility() // Whether filtering is needed b/c of the drawingstate bool mNeedsFiltering; protected: - // cached during validateVisibility() - int32_t mOrientation; - int32_t mPlaneOrientation; - Transform mTransform; - GLfloat mVertices[4][2]; - size_t mNumVertices; - Rect mTransformedBounds; - // these are protected by an external lock State mCurrentState; State mDrawingState; diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp index ceead455c..5c37d01e5 100644 --- a/services/surfaceflinger/LayerDim.cpp +++ b/services/surfaceflinger/LayerDim.cpp @@ -58,8 +58,11 @@ void LayerDim::onDraw(const DisplayHardware& hw, const Region& clip) const glColor4f(0, 0, 0, alpha); - glVertexPointer(2, GL_FLOAT, 0, mVertices); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + LayerMesh mesh; + computeGeometry(hw, &mesh); + + glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); + glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); glDisable(GL_BLEND); glDisableClientState(GL_TEXTURE_COORD_ARRAY); diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp index d04687963..f2bf19d29 100644 --- a/services/surfaceflinger/LayerScreenshot.cpp +++ b/services/surfaceflinger/LayerScreenshot.cpp @@ -120,6 +120,9 @@ void LayerScreenshot::onDraw(const DisplayHardware& hw, const Region& clip) cons glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } + LayerMesh mesh; + computeGeometry(hw, &mesh); + glColor4f(0, 0, 0, alpha); glDisable(GL_TEXTURE_EXTERNAL_OES); @@ -133,8 +136,8 @@ void LayerScreenshot::onDraw(const DisplayHardware& hw, const Region& clip) cons glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, 0, mTexCoords); - glVertexPointer(2, GL_FLOAT, 0, mVertices); - glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices); + glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices()); + glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount()); glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp index 290fff469..3f77f74c3 100644 --- a/services/surfaceflinger/MessageQueue.cpp +++ b/services/surfaceflinger/MessageQueue.cpp @@ -49,13 +49,13 @@ void MessageBase::handleMessage(const Message&) { // --------------------------------------------------------------------------- -void MessageQueue::Handler::signalRefresh() { +void MessageQueue::Handler::dispatchRefresh() { if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) { mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH)); } } -void MessageQueue::Handler::signalInvalidate() { +void MessageQueue::Handler::dispatchInvalidate() { if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) { mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE)); } @@ -132,13 +132,31 @@ status_t MessageQueue::postMessage( return NO_ERROR; } +/* when INVALIDATE_ON_VSYNC is set SF only processes + * buffer updates on VSYNC and performs a refresh immediately + * after. + * + * when INVALIDATE_ON_VSYNC is set to false, SF will instead + * perform the buffer updates immediately, but the refresh only + * at the next VSYNC. + * THIS MODE IS BUGGY ON GALAXY NEXUS AND WILL CAUSE HANGS + */ +#define INVALIDATE_ON_VSYNC 1 + void MessageQueue::invalidate() { -// mHandler->signalInvalidate(); +#if INVALIDATE_ON_VSYNC mEvents->requestNextVsync(); +#else + mHandler->dispatchInvalidate(); +#endif } void MessageQueue::refresh() { +#if INVALIDATE_ON_VSYNC + mHandler->dispatchRefresh(); +#else mEvents->requestNextVsync(); +#endif } int MessageQueue::cb_eventReceiver(int fd, int events, void* data) { @@ -152,7 +170,11 @@ int MessageQueue::eventReceiver(int fd, int events) { while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) { for (int i=0 ; isignalRefresh(); +#if INVALIDATE_ON_VSYNC + mHandler->dispatchInvalidate(); +#else + mHandler->dispatchRefresh(); +#endif break; } } diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h index ea29e7ef7..710b2c28e 100644 --- a/services/surfaceflinger/MessageQueue.h +++ b/services/surfaceflinger/MessageQueue.h @@ -70,8 +70,8 @@ class MessageQueue { public: Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { } virtual void handleMessage(const Message& message); - void signalRefresh(); - void signalInvalidate(); + void dispatchRefresh(); + void dispatchInvalidate(); }; friend class Handler; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 3b2bf00ed..6c900be99 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -425,100 +425,117 @@ status_t SurfaceFlinger::postMessageSync(const sp& msg, return res; } -bool SurfaceFlinger::threadLoop() -{ +bool SurfaceFlinger::threadLoop() { waitForEvent(); return true; } -void SurfaceFlinger::onMessageReceived(int32_t what) -{ +void SurfaceFlinger::onMessageReceived(int32_t what) { ATRACE_CALL(); switch (what) { - case MessageQueue::REFRESH: { -// case MessageQueue::INVALIDATE: { - // if we're in a global transaction, don't do anything. - const uint32_t mask = eTransactionNeeded | eTraversalNeeded; - uint32_t transactionFlags = peekTransactionFlags(mask); - if (CC_UNLIKELY(transactionFlags)) { - handleTransaction(transactionFlags); - } - - // post surfaces (if needed) - handlePageFlip(); - -// signalRefresh(); -// -// } break; -// -// case MessageQueue::REFRESH: { - - handleRefresh(); - - // TODO: iterate through all displays - const DisplayHardware& hw(getDisplayHardware(0)); - -// if (mDirtyRegion.isEmpty()) { -// return; -// } - - if (CC_UNLIKELY(mHwWorkListDirty)) { - // build the h/w work list - handleWorkList(hw); - } - - if (CC_LIKELY(hw.canDraw())) { - // repaint the framebuffer (if needed) - handleRepaint(hw); - // inform the h/w that we're done compositing - hw.compositionComplete(); - postFramebuffer(); - } else { - // pretend we did the post - hw.compositionComplete(); - } - - // 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 Vector< sp >& layers(mVisibleLayersSortedByZ); - const size_t count = layers.size(); - for (size_t i=0 ; i& layer(layers[i]); - layer->drawForSreenShot(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"); - } - - } break; + case MessageQueue::INVALIDATE: + handleMessageTransaction(); + handleMessageInvalidate(); + signalRefresh(); + break; + case MessageQueue::REFRESH: + handleMessageRefresh(); + break; } } +void SurfaceFlinger::handleMessageTransaction() { + const uint32_t mask = eTransactionNeeded | eTraversalNeeded; + uint32_t transactionFlags = peekTransactionFlags(mask); + if (transactionFlags) { + Region dirtyRegion; + dirtyRegion = handleTransaction(transactionFlags); + // XXX: dirtyRegion should be per screen + mDirtyRegion |= dirtyRegion; + } +} + +void SurfaceFlinger::handleMessageInvalidate() { + Region dirtyRegion; + dirtyRegion = handlePageFlip(); + // XXX: dirtyRegion should be per screen + mDirtyRegion |= dirtyRegion; +} + +void SurfaceFlinger::handleMessageRefresh() { + handleRefresh(); + + // XXX: dirtyRegion should be per screen, we should check all of them + if (mDirtyRegion.isEmpty()) { + return; + } + + // TODO: iterate through all displays + const DisplayHardware& hw(getDisplayHardware(0)); + + // XXX: dirtyRegion should be per screen + // transform the dirty region into this screen's coordinate space + const Transform& planeTransform(hw.getTransform()); + mDirtyRegion = planeTransform.transform(mDirtyRegion); + mDirtyRegion.orSelf(getAndClearInvalidateRegion()); + mDirtyRegion.andSelf(hw.bounds()); + + + if (CC_UNLIKELY(mHwWorkListDirty)) { + // build the h/w work list + handleWorkList(hw); + } + + if (CC_LIKELY(hw.canDraw())) { + // repaint the framebuffer (if needed) + handleRepaint(hw); + // inform the h/w that we're done compositing + hw.compositionComplete(); + postFramebuffer(); + } else { + // pretend we did the post + hw.compositionComplete(); + } + + // 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 Vector< sp >& layers(mVisibleLayersSortedByZ); + const size_t count = layers.size(); + for (size_t i=0 ; i& layer(layers[i]); + layer->drawForSreenShot(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"); + } + +} + void SurfaceFlinger::postFramebuffer() { ATRACE_CALL(); @@ -564,10 +581,12 @@ void SurfaceFlinger::postFramebuffer() mSwapRegion.clear(); } -void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) +Region SurfaceFlinger::handleTransaction(uint32_t transactionFlags) { ATRACE_CALL(); + Region dirtyRegion; + Mutex::Autolock _l(mStateLock); const nsecs_t now = systemTime(); mDebugInTransaction = now; @@ -580,16 +599,19 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) const uint32_t mask = eTransactionNeeded | eTraversalNeeded; transactionFlags = getTransactionFlags(mask); - handleTransactionLocked(transactionFlags); + dirtyRegion = handleTransactionLocked(transactionFlags); mLastTransactionTime = systemTime() - now; mDebugInTransaction = 0; invalidateHwcGeometry(); // here the transaction has been committed + + return dirtyRegion; } -void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) +Region SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { + Region dirtyRegion; const LayerVector& currentLayers(mCurrentState.layersSortedByZ); const size_t count = currentLayers.size(); @@ -652,13 +674,34 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) const sp& layer(previousLayers[i]); if (currentLayers.indexOf( layer ) < 0) { // this layer is not visible anymore - mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen); + // TODO: we could traverse the tree from front to back and compute the actual visible region + // TODO: we could cache the transformed region + Layer::State front(layer->drawingState()); + Region visibleReg = front.transform.transform( + Region(Rect(front.active.w, front.active.h))); + dirtyRegion.orSelf(visibleReg); } } } } commitTransaction(); + return dirtyRegion; +} + +void SurfaceFlinger::commitTransaction() +{ + if (!mLayersPendingRemoval.isEmpty()) { + // Notify removed layers now that they can't be drawn from + for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) { + mLayersPendingRemoval[i]->onRemoved(); + } + mLayersPendingRemoval.clear(); + } + + mDrawingState = mCurrentState; + mTransationPending = false; + mTransactionCV.broadcast(); } void SurfaceFlinger::computeVisibleRegions( @@ -666,10 +709,6 @@ void SurfaceFlinger::computeVisibleRegions( { ATRACE_CALL(); - const DisplayHardware& hw(getDefaultDisplayHardware()); // FIXME: we shouldn't rely on DisplayHardware here - const Transform& planeTransform(hw.getTransform()); - const Region screenRegion(hw.bounds()); - Region aboveOpaqueLayers; Region aboveCoveredLayers; Region dirty; @@ -679,7 +718,6 @@ void SurfaceFlinger::computeVisibleRegions( size_t i = currentLayers.size(); while (i--) { const sp& layer = currentLayers[i]; - layer->validateVisibility(planeTransform, hw); // start with the whole surface at its current location const Layer::State& s(layer->drawingState()); @@ -707,17 +745,30 @@ void SurfaceFlinger::computeVisibleRegions( // handle hidden surfaces by setting the visible region to empty if (CC_LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) { const bool translucent = !layer->isOpaque(); - const Rect bounds(layer->visibleBounds()); + Rect bounds(layer->computeBounds()); visibleRegion.set(bounds); - visibleRegion.andSelf(screenRegion); if (!visibleRegion.isEmpty()) { // Remove the transparent area from the visible region if (translucent) { - visibleRegion.subtractSelf(layer->transparentRegionScreen); + Region transparentRegionScreen; + const Transform tr(s.transform); + if (tr.transformed()) { + if (tr.preserveRects()) { + // transform the transparent region + transparentRegionScreen = tr.transform(s.transparentRegion); + } else { + // transformation too complex, can't do the + // transparent region optimization. + transparentRegionScreen.clear(); + } + } else { + transparentRegionScreen = s.transparentRegion; + } + visibleRegion.subtractSelf(transparentRegionScreen); } // compute the opaque region - const int32_t layerOrientation = layer->getOrientation(); + const int32_t layerOrientation = s.transform.getOrientation(); if (s.alpha==255 && !translucent && ((layerOrientation & Transform::ROT_INVALID) == false)) { // the opaque region is the layer's footprint @@ -740,7 +791,7 @@ void SurfaceFlinger::computeVisibleRegions( // we need to invalidate the whole region dirty = visibleRegion; // as well, as the old visible region - dirty.orSelf(layer->visibleRegionScreen); + dirty.orSelf(layer->visibleRegion); layer->contentDirty = false; } else { /* compute the exposed region: @@ -756,8 +807,8 @@ void SurfaceFlinger::computeVisibleRegions( * exposed because of a resize. */ const Region newExposed = visibleRegion - coveredRegion; - const Region oldVisibleRegion = layer->visibleRegionScreen; - const Region oldCoveredRegion = layer->coveredRegionScreen; + const Region oldVisibleRegion = layer->visibleRegion; + const Region oldCoveredRegion = layer->coveredRegion; const Region oldExposed = oldVisibleRegion - oldCoveredRegion; dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed); } @@ -779,63 +830,51 @@ void SurfaceFlinger::computeVisibleRegions( } } - // invalidate the areas where a layer was removed - dirtyRegion.orSelf(mDirtyRegionRemovedLayer); - mDirtyRegionRemovedLayer.clear(); - mSecureFrameBuffer = secureFrameBuffer; opaqueRegion = aboveOpaqueLayers; } - -void SurfaceFlinger::commitTransaction() -{ - if (!mLayersPendingRemoval.isEmpty()) { - // Notify removed layers now that they can't be drawn from - for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) { - mLayersPendingRemoval[i]->onRemoved(); - } - mLayersPendingRemoval.clear(); - } - - mDrawingState = mCurrentState; - mTransationPending = false; - mTransactionCV.broadcast(); -} - -void SurfaceFlinger::handlePageFlip() +Region SurfaceFlinger::handlePageFlip() { ATRACE_CALL(); - const DisplayHardware& hw(getDefaultDisplayHardware()); // FIXME: it's a problem we need DisplayHardware here - const Region screenRegion(hw.bounds()); + Region dirtyRegion; const LayerVector& currentLayers(mDrawingState.layersSortedByZ); - const bool visibleRegions = lockPageFlip(currentLayers); - if (visibleRegions || mVisibleRegionsDirty) { - Region opaqueRegion; - computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion); + bool visibleRegions = false; + const size_t count = currentLayers.size(); + sp const* layers = currentLayers.array(); + for (size_t i=0 ; i& layer(layers[i]); + dirtyRegion.orSelf( layer->latchBuffer(visibleRegions) ); + } - /* - * rebuild the visible layer list - */ - const size_t count = currentLayers.size(); - mVisibleLayersSortedByZ.clear(); - mVisibleLayersSortedByZ.setCapacity(count); - for (size_t i=0 ; ivisibleRegionScreen.isEmpty()) - mVisibleLayersSortedByZ.add(currentLayers[i]); - } + if (visibleRegions || mVisibleRegionsDirty) { + Region opaqueRegion; + computeVisibleRegions(currentLayers, dirtyRegion, opaqueRegion); - mWormholeRegion = screenRegion.subtract(opaqueRegion); - mVisibleRegionsDirty = false; - invalidateHwcGeometry(); + /* + * rebuild the visible layer list + */ + + // XXX: mVisibleLayersSortedByZ should be per-screen + const size_t count = currentLayers.size(); + mVisibleLayersSortedByZ.clear(); + mVisibleLayersSortedByZ.setCapacity(count); + for (size_t i=0 ; ivisibleRegion.isEmpty()) + mVisibleLayersSortedByZ.add(currentLayers[i]); } - unlockPageFlip(currentLayers); + // FIXME: mWormholeRegion needs to be calculated per screen + const DisplayHardware& hw(getDefaultDisplayHardware()); // XXX: we can't keep that here + mWormholeRegion = Region(hw.getBounds()).subtract( + hw.getTransform().transform(opaqueRegion) ); + mVisibleRegionsDirty = false; + invalidateHwcGeometry(); + } - mDirtyRegion.orSelf(getAndClearInvalidateRegion()); - mDirtyRegion.andSelf(screenRegion); + return dirtyRegion; } void SurfaceFlinger::invalidateHwcGeometry() @@ -843,30 +882,6 @@ void SurfaceFlinger::invalidateHwcGeometry() mHwWorkListDirty = true; } -bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers) -{ - bool recomputeVisibleRegions = false; - size_t count = currentLayers.size(); - sp const* layers = currentLayers.array(); - for (size_t i=0 ; i& layer(layers[i]); - layer->lockPageFlip(recomputeVisibleRegions); - } - return recomputeVisibleRegions; -} - -void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers) -{ - const DisplayHardware& hw(getDefaultDisplayHardware()); // FIXME: it's a problem we need DisplayHardware here - const Transform& planeTransform(hw.getTransform()); - const size_t count = currentLayers.size(); - sp const* layers = currentLayers.array(); - for (size_t i=0 ; i& layer(layers[i]); - layer->unlockPageFlip(planeTransform, mDirtyRegion); - } -} - void SurfaceFlinger::handleRefresh() { bool needInvalidate = false; @@ -896,7 +911,7 @@ void SurfaceFlinger::handleWorkList(const DisplayHardware& hw) HWComposer::LayerListIterator cur = hwc.begin(); const HWComposer::LayerListIterator end = hwc.end(); for (size_t i=0 ; cur!=end && isetGeometry(*cur); + currentLayers[i]->setGeometry(hw, *cur); if (mDebugDisableHWC || mDebugRegion) { cur->setSkip(true); } @@ -1012,9 +1027,10 @@ void SurfaceFlinger::composeSurfaces(const DisplayHardware& hw, const Region& di const Vector< sp >& layers(mVisibleLayersSortedByZ); const size_t count = layers.size(); + const Transform& tr = hw.getTransform(); for (size_t i=0 ; cur!=end && i& layer(layers[i]); - const Region clip(dirty.intersect(layer->visibleRegionScreen)); + const Region clip(dirty.intersect(tr.transform(layer->visibleRegion))); if (!clip.isEmpty()) { if (cur->getCompositionType() == HWC_OVERLAY) { if (i && (cur->getHints() & HWC_HINT_CLEAR_FB) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 3e2756453..91cc6a5eb 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -129,6 +129,9 @@ public: GLuint* textureName, GLfloat* uOut, GLfloat* vOut); void onMessageReceived(int32_t what); + void handleMessageTransaction(); + void handleMessageInvalidate(); + void handleMessageRefresh(); status_t postMessageAsync(const sp& msg, nsecs_t reltime=0, uint32_t flags = 0); @@ -237,17 +240,23 @@ public: // hack to work around gcc 4.0.3 bug private: void waitForEvent(); - void handleTransaction(uint32_t transactionFlags); - void handleTransactionLocked(uint32_t transactionFlags); + Region handleTransaction(uint32_t transactionFlags); + Region handleTransactionLocked(uint32_t transactionFlags); void computeVisibleRegions( const LayerVector& currentLayers, Region& dirtyRegion, Region& wormholeRegion); - void handlePageFlip(); - bool lockPageFlip(const LayerVector& currentLayers); - void unlockPageFlip(const LayerVector& currentLayers); + /* handlePageFilp: this is were we latch a new buffer + * if available and compute the dirty region. + * The return value is the dirty region expressed in the + * window manager's coordinate space (or the layer's state + * space, which is the same thing), in particular the dirty + * region is independent from a specific display's orientation. + */ + Region handlePageFlip(); + void handleRefresh(); void handleWorkList(const DisplayHardware& hw); void handleRepaint(const DisplayHardware& hw);