diff options
-rw-r--r-- | include/surfaceflinger/ISurfaceComposer.h | 10 | ||||
-rw-r--r-- | include/surfaceflinger/SurfaceComposerClient.h | 2 | ||||
-rw-r--r-- | libs/gui/ISurfaceComposer.cpp | 6 | ||||
-rw-r--r-- | libs/gui/SurfaceComposerClient.cpp | 33 | ||||
-rw-r--r-- | services/surfaceflinger/Layer.cpp | 34 | ||||
-rw-r--r-- | services/surfaceflinger/Layer.h | 5 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 116 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 40 | ||||
-rw-r--r-- | services/surfaceflinger/tests/Android.mk | 41 | ||||
-rw-r--r-- | services/surfaceflinger/tests/Transaction_test.cpp | 236 |
10 files changed, 334 insertions, 189 deletions
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h index e7a33f1..5eb09c7 100644 --- a/include/surfaceflinger/ISurfaceComposer.h +++ b/include/surfaceflinger/ISurfaceComposer.h @@ -84,7 +84,11 @@ public: eOrientationUnchanged = 4, eOrientationSwapMask = 0x01 }; - + + enum { + eSynchronous = 0x01, + }; + enum { eElectronBeamAnimationOn = 0x01, eElectronBeamAnimationOff = 0x10 @@ -104,7 +108,7 @@ public: /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */ virtual void setTransactionState(const Vector<ComposerState>& state, - int orientation) = 0; + int orientation, uint32_t flags) = 0; /* signal that we're done booting. * Requires ACCESS_SURFACE_FLINGER permission @@ -143,8 +147,6 @@ public: GET_CBLK, SET_TRANSACTION_STATE, SET_ORIENTATION, - FREEZE_DISPLAY, - UNFREEZE_DISPLAY, CAPTURE_SCREEN, TURN_ELECTRON_BEAM_OFF, TURN_ELECTRON_BEAM_ON, diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h index 14e5b23..8226abe 100644 --- a/include/surfaceflinger/SurfaceComposerClient.h +++ b/include/surfaceflinger/SurfaceComposerClient.h @@ -112,7 +112,7 @@ public: static void openGlobalTransaction(); //! Close a composer transaction on all active SurfaceComposerClients. - static void closeGlobalTransaction(); + static void closeGlobalTransaction(bool synchronous = false); //! Freeze the specified display but not transactions. static status_t freezeDisplay(DisplayID dpy, uint32_t flags = 0); diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index eb90147..86bc62a 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -79,7 +79,7 @@ public: } virtual void setTransactionState(const Vector<ComposerState>& state, - int orientation) + int orientation, uint32_t flags) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -90,6 +90,7 @@ public: b->write(data); } data.writeInt32(orientation); + data.writeInt32(flags); remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } @@ -204,7 +205,8 @@ status_t BnSurfaceComposer::onTransact( state.add(s); } int orientation = data.readInt32(); - setTransactionState(state, orientation); + uint32_t flags = data.readInt32(); + setTransactionState(state, orientation, flags); } break; case BOOT_FINISHED: { CHECK_INTERFACE(ISurfaceComposer, data, reply); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 5f3d608..4ad6c22 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -92,11 +92,14 @@ class Composer : public Singleton<Composer> mutable Mutex mLock; SortedVector<ComposerState> mStates; int mOrientation; + uint32_t mForceSynchronous; Composer() : Singleton<Composer>(), - mOrientation(ISurfaceComposer::eOrientationUnchanged) { } + mOrientation(ISurfaceComposer::eOrientationUnchanged), + mForceSynchronous(0) + { } - void closeGlobalTransactionImpl(); + void closeGlobalTransactionImpl(bool synchronous); layer_state_t* getLayerStateLocked( const sp<SurfaceComposerClient>& client, SurfaceID id); @@ -123,8 +126,8 @@ public: uint32_t tint); status_t setOrientation(int orientation); - static void closeGlobalTransaction() { - Composer::getInstance().closeGlobalTransactionImpl(); + static void closeGlobalTransaction(bool synchronous) { + Composer::getInstance().closeGlobalTransactionImpl(synchronous); } }; @@ -132,11 +135,12 @@ ANDROID_SINGLETON_STATIC_INSTANCE(Composer); // --------------------------------------------------------------------------- -void Composer::closeGlobalTransactionImpl() { +void Composer::closeGlobalTransactionImpl(bool synchronous) { sp<ISurfaceComposer> sm(getComposerService()); Vector<ComposerState> transaction; int orientation; + uint32_t flags = 0; { // scope for the lock Mutex::Autolock _l(mLock); @@ -145,9 +149,14 @@ void Composer::closeGlobalTransactionImpl() { orientation = mOrientation; mOrientation = ISurfaceComposer::eOrientationUnchanged; + + if (synchronous || mForceSynchronous) { + flags |= ISurfaceComposer::eSynchronous; + } + mForceSynchronous = false; } - sm->setTransactionState(transaction, orientation); + sm->setTransactionState(transaction, orientation, flags); } layer_state_t* Composer::getLayerStateLocked( @@ -188,6 +197,10 @@ status_t Composer::setSize(const sp<SurfaceComposerClient>& client, s->what |= ISurfaceComposer::eSizeChanged; s->w = w; s->h = h; + + // Resizing a surface makes the transaction synchronous. + mForceSynchronous = true; + return NO_ERROR; } @@ -270,6 +283,10 @@ status_t Composer::setFreezeTint(const sp<SurfaceComposerClient>& client, status_t Composer::setOrientation(int orientation) { Mutex::Autolock _l(mLock); mOrientation = orientation; + + // Changing the orientation makes the transaction synchronous. + mForceSynchronous = true; + return NO_ERROR; } @@ -375,8 +392,8 @@ void SurfaceComposerClient::openGlobalTransaction() { // Currently a no-op } -void SurfaceComposerClient::closeGlobalTransaction() { - Composer::closeGlobalTransaction(); +void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) { + Composer::closeGlobalTransaction(synchronous); } // ---------------------------------------------------------------------------- diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 76a2caa..2b8d113 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -360,18 +360,6 @@ uint32_t Layer::doTransaction(uint32_t flags) mCurrentScalingMode); if (!isFixedSize()) { - // we're being resized and there is a freeze display request, - // acquire a freeze lock, so that the screen stays put - // until we've redrawn at the new size; this is to avoid - // glitches upon orientation changes. - if (mFlinger->hasFreezeRequest()) { - // if the surface is hidden, don't try to acquire the - // freeze lock, since hidden surfaces may never redraw - if (!(front.flags & ISurfaceComposer::eLayerHidden)) { - mFreezeLock = mFlinger->getFreezeLock(); - } - } - // this will make sure LayerBase::doTransaction doesn't update // the drawing state's size Layer::State& editDraw(mDrawingState); @@ -385,14 +373,6 @@ uint32_t Layer::doTransaction(uint32_t flags) temp.requested_h); } - if (temp.sequence != front.sequence) { - if (temp.flags & ISurfaceComposer::eLayerHidden || temp.alpha == 0) { - // this surface is now hidden, so it shouldn't hold a freeze lock - // (it may never redraw, which is fine if it is hidden) - mFreezeLock.clear(); - } - } - return LayerBase::doTransaction(flags); } @@ -466,7 +446,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) 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); - // update the layer size and release freeze-lock + // update the layer size if needed const Layer::State& front(drawingState()); // FIXME: mPostedDirtyRegion = dirty & bounds @@ -503,9 +483,6 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) // recompute visible region recomputeVisibleRegions = true; - - // we now have the correct size, unfreeze the screen - mFreezeLock.clear(); } LOGD_IF(DEBUG_RESIZE, @@ -538,11 +515,6 @@ void Layer::unlockPageFlip( dirtyRegion.andSelf(visibleRegionScreen); outDirtyRegion.orSelf(dirtyRegion); } - if (visibleRegionScreen.isEmpty()) { - // an invisible layer should not hold a freeze-lock - // (because it may never be updated and therefore never release it) - mFreezeLock.clear(); - } } void Layer::dump(String8& result, char* buffer, size_t SIZE) const @@ -560,9 +532,9 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const snprintf(buffer, SIZE, " " "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X]," - " freezeLock=%p, transform-hint=0x%02x, queued-frames=%d\n", + " transform-hint=0x%02x, queued-frames=%d\n", mFormat, w0, h0, s0,f0, - getFreezeLock().get(), getTransformHint(), mQueuedFrames); + getTransformHint(), mQueuedFrames); result.append(buffer); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 82e3521..2b9471b 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -39,7 +39,6 @@ namespace android { // --------------------------------------------------------------------------- -class FreezeLock; class Client; class GLExtensions; @@ -80,7 +79,6 @@ public: virtual wp<IBinder> getSurfaceTextureBinder() const; // only for debugging - inline const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; } inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; } protected: @@ -124,9 +122,6 @@ private: bool mProtectedByApp; // application requires protected path to external sink Region mPostedDirtyRegion; - // page-flip thread and transaction thread (currently main thread) - sp<FreezeLock> mFreezeLock; - // binder thread, transaction thread mutable Mutex mLock; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 3dccc11..eb10e8b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -80,15 +80,12 @@ const String16 sDump("android.permission.DUMP"); SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), Thread(false), mTransactionFlags(0), - mResizeTransationPending(false), + mTransationPending(false), mLayersRemoved(false), mBootTime(systemTime()), mVisibleRegionsDirty(false), mHwWorkListDirty(false), - mFreezeDisplay(false), mElectronBeamAnimationMode(0), - mFreezeCount(0), - mFreezeDisplayTime(0), mDebugRegion(0), mDebugBackground(0), mDebugDDMS(0), @@ -191,11 +188,6 @@ void SurfaceFlinger::binderDied(const wp<IBinder>& who) { // the window manager died on us. prepare its eulogy. - // unfreeze the screen in case it was... frozen - mFreezeDisplayTime = 0; - mFreezeCount = 0; - mFreezeDisplay = false; - // reset screen orientation setOrientation(0, eOrientationDefault, 0); @@ -323,33 +315,7 @@ void SurfaceFlinger::waitForEvent() { while (true) { nsecs_t timeout = -1; - const nsecs_t freezeDisplayTimeout = ms2ns(5000); - if (UNLIKELY(isFrozen())) { - // wait 5 seconds - const nsecs_t now = systemTime(); - if (mFreezeDisplayTime == 0) { - mFreezeDisplayTime = now; - } - nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime); - timeout = waitTime>0 ? waitTime : 0; - } - sp<MessageBase> msg = mEventQueue.waitMessage(timeout); - - // see if we timed out - if (isFrozen()) { - const nsecs_t now = systemTime(); - nsecs_t frozenTime = (now - mFreezeDisplayTime); - if (frozenTime >= freezeDisplayTimeout) { - // we timed out and are still frozen - LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d", - mFreezeDisplay, mFreezeCount); - mFreezeDisplayTime = 0; - mFreezeCount = 0; - mFreezeDisplay = false; - } - } - if (msg != 0) { switch (msg->what) { case MessageQueue::INVALIDATE: @@ -452,7 +418,7 @@ bool SurfaceFlinger::threadLoop() } const DisplayHardware& hw(graphicPlane(0).displayHardware()); - if (LIKELY(hw.canDraw() && !isFrozen())) { + if (LIKELY(hw.canDraw())) { // repaint the framebuffer (if needed) const int index = hw.getCurrentBufferIndex(); @@ -583,13 +549,6 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) mDirtyRegion.set(hw.bounds()); } - if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) { - // freezing or unfreezing the display -> trigger animation if needed - mFreezeDisplay = mCurrentState.freezeDisplay; - if (mFreezeDisplay) - mFreezeDisplayTime = 0; - } - if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) { // layers have been added mVisibleRegionsDirty = true; @@ -615,11 +574,6 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) commitTransaction(); } -sp<FreezeLock> SurfaceFlinger::getFreezeLock() const -{ - return new FreezeLock(const_cast<SurfaceFlinger *>(this)); -} - void SurfaceFlinger::computeVisibleRegions( const LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion) { @@ -749,7 +703,7 @@ void SurfaceFlinger::computeVisibleRegions( void SurfaceFlinger::commitTransaction() { mDrawingState = mCurrentState; - mResizeTransationPending = false; + mTransationPending = false; mTransactionCV.broadcast(); } @@ -1236,15 +1190,14 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state, - int orientation) { + int orientation, uint32_t flags) { Mutex::Autolock _l(mStateLock); - uint32_t flags = 0; + uint32_t transactionFlags = 0; if (mCurrentState.orientation != orientation) { if (uint32_t(orientation)<=eOrientation270 || orientation==42) { mCurrentState.orientation = orientation; - flags |= eTransactionNeeded; - mResizeTransationPending = true; + transactionFlags |= eTransactionNeeded; } else if (orientation != eOrientationUnchanged) { LOGW("setTransactionState: ignoring unrecognized orientation: %d", orientation); @@ -1255,56 +1208,29 @@ void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state, for (size_t i=0 ; i<count ; i++) { const ComposerState& s(state[i]); sp<Client> client( static_cast<Client *>(s.client.get()) ); - flags |= setClientStateLocked(client, s.state); + transactionFlags |= setClientStateLocked(client, s.state); } - if (flags) { - setTransactionFlags(flags); + if (transactionFlags) { + setTransactionFlags(transactionFlags); } - signalEvent(); - - // if there is a transaction with a resize, wait for it to - // take effect before returning. - while (mResizeTransationPending) { + // if this is a synchronous transaction, wait for it to take effect before + // returning. + if (flags & eSynchronous) { + mTransationPending = true; + } + while (mTransationPending) { status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); if (CC_UNLIKELY(err != NO_ERROR)) { // just in case something goes wrong in SF, return to the // called after a few seconds. LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!"); - mResizeTransationPending = false; + mTransationPending = false; break; } } } -status_t SurfaceFlinger::freezeDisplay(DisplayID dpy, uint32_t flags) -{ - if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) - return BAD_VALUE; - - Mutex::Autolock _l(mStateLock); - mCurrentState.freezeDisplay = 1; - setTransactionFlags(eTransactionNeeded); - - // flags is intended to communicate some sort of animation behavior - // (for instance fading) - return NO_ERROR; -} - -status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags) -{ - if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) - return BAD_VALUE; - - Mutex::Autolock _l(mStateLock); - mCurrentState.freezeDisplay = 0; - setTransactionFlags(eTransactionNeeded); - - // flags is intended to communicate some sort of animation behavior - // (for instance fading) - return NO_ERROR; -} - int SurfaceFlinger::setOrientation(DisplayID dpy, int orientation, uint32_t flags) { @@ -1505,7 +1431,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (what & eSizeChanged) { if (layer->setSize(s.w, s.h)) { flags |= eTraversalNeeded; - mResizeTransationPending = true; } } if (what & eAlphaChanged) { @@ -1625,8 +1550,7 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) mWormholeRegion.dump(result, "WormholeRegion"); const DisplayHardware& hw(graphicPlane(0).displayHardware()); snprintf(buffer, SIZE, - " display frozen: %s, freezeCount=%d, orientation=%d, canDraw=%d\n", - mFreezeDisplay?"yes":"no", mFreezeCount, + " orientation=%d, canDraw=%d\n", mCurrentState.orientation, hw.canDraw()); result.append(buffer); snprintf(buffer, SIZE, @@ -1679,8 +1603,6 @@ status_t SurfaceFlinger::onTransact( case CREATE_CONNECTION: case SET_TRANSACTION_STATE: case SET_ORIENTATION: - case FREEZE_DISPLAY: - case UNFREEZE_DISPLAY: case BOOT_FINISHED: case TURN_ELECTRON_BEAM_OFF: case TURN_ELECTRON_BEAM_ON: @@ -1752,10 +1674,6 @@ status_t SurfaceFlinger::onTransact( GraphicLog::getInstance().setEnabled(enabled); return NO_ERROR; } - case 1007: // set mFreezeCount - mFreezeCount = data.readInt32(); - mFreezeDisplayTime = 0; - return NO_ERROR; case 1008: // toggle use of hw composer n = data.readInt32(); mDebugDisableHWC = n ? 1 : 0; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 3c8f4e5..1490dec 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -46,7 +46,6 @@ namespace android { class Client; class DisplayHardware; -class FreezeLock; class Layer; class LayerDim; class LayerScreenshot; @@ -169,9 +168,7 @@ public: virtual sp<IMemoryHeap> getCblk() const; virtual void bootFinished(); virtual void setTransactionState(const Vector<ComposerState>& state, - int orientation); - virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags); - virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags); + int orientation, uint32_t flags); virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags); virtual bool authenticateSurfaceTexture(const sp<ISurfaceTexture>& surface) const; @@ -269,12 +266,10 @@ private: struct State { State() { orientation = ISurfaceComposer::eOrientationDefault; - freezeDisplay = 0; } LayerVector layersSortedByZ; uint8_t orientation; uint8_t orientationFlags; - uint8_t freezeDisplay; }; virtual bool threadLoop(); @@ -333,20 +328,6 @@ private: status_t renderScreenToTextureLocked(DisplayID dpy, GLuint* textureName, GLfloat* uOut, GLfloat* vOut); - friend class FreezeLock; - sp<FreezeLock> getFreezeLock() const; - inline void incFreezeCount() { - if (mFreezeCount == 0) - mFreezeDisplayTime = 0; - mFreezeCount++; - } - inline void decFreezeCount() { if (mFreezeCount > 0) mFreezeCount--; } - inline bool hasFreezeRequest() const { return mFreezeDisplay; } - inline bool isFrozen() const { - return (mFreezeDisplay || mFreezeCount>0) && mBootFinished; - } - - void debugFlashRegions(); void debugShowFPS() const; void drawWormhole() const; @@ -360,7 +341,7 @@ private: volatile int32_t mTransactionFlags; Condition mTransactionCV; SortedVector< sp<LayerBase> > mLayerPurgatory; - bool mResizeTransationPending; + bool mTransationPending; // protected by mStateLock (but we could use another lock) GraphicPlane mGraphicPlanes[1]; @@ -383,10 +364,7 @@ private: Region mWormholeRegion; bool mVisibleRegionsDirty; bool mHwWorkListDirty; - bool mFreezeDisplay; int32_t mElectronBeamAnimationMode; - int32_t mFreezeCount; - nsecs_t mFreezeDisplayTime; Vector< sp<LayerBase> > mVisibleLayersSortedByZ; @@ -422,20 +400,6 @@ private: }; // --------------------------------------------------------------------------- - -class FreezeLock : public LightRefBase<FreezeLock> { - SurfaceFlinger* mFlinger; -public: - FreezeLock(SurfaceFlinger* flinger) - : mFlinger(flinger) { - mFlinger->incFreezeCount(); - } - ~FreezeLock() { - mFlinger->decFreezeCount(); - } -}; - -// --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SURFACE_FLINGER_H diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk index 5053e7d..b655648 100644 --- a/services/surfaceflinger/tests/Android.mk +++ b/services/surfaceflinger/tests/Android.mk @@ -1 +1,40 @@ -include $(call all-subdir-makefiles) +# Build the unit tests, +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE := SurfaceFlinger_test + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := \ + Transaction_test.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libEGL \ + libGLESv2 \ + libandroid \ + libbinder \ + libcutils \ + libgui \ + libstlport \ + libui \ + libutils \ + +LOCAL_C_INCLUDES := \ + bionic \ + bionic/libstdc++/include \ + external/gtest/include \ + external/stlport/stlport \ + +# Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) +# to integrate with auto-test framework. +include $(BUILD_NATIVE_TEST) + +# Include subdirectory makefiles +# ============================================================ + +# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework +# team really wants is to build the stuff defined by this makefile. +ifeq (,$(ONE_SHOT_MAKEFILE)) +include $(call first-makefiles-under,$(LOCAL_PATH)) +endif diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp new file mode 100644 index 0000000..afafd8a --- /dev/null +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> + +#include <binder/IMemory.h> +#include <surfaceflinger/ISurfaceComposer.h> +#include <surfaceflinger/Surface.h> +#include <surfaceflinger/SurfaceComposerClient.h> +#include <utils/String8.h> + +namespace android { + +// Fill an RGBA_8888 formatted surface with a single color. +static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, + uint8_t r, uint8_t g, uint8_t b) { + Surface::SurfaceInfo info; + sp<Surface> s = sc->getSurface(); + ASSERT_TRUE(s != NULL); + ASSERT_EQ(NO_ERROR, s->lock(&info)); + uint8_t* img = reinterpret_cast<uint8_t*>(info.bits); + for (uint32_t y = 0; y < info.h; y++) { + for (uint32_t x = 0; x < info.w; x++) { + uint8_t* pixel = img + (4 * (y*info.s + x)); + pixel[0] = r; + pixel[1] = g; + pixel[2] = b; + pixel[3] = 255; + } + } + ASSERT_EQ(NO_ERROR, s->unlockAndPost()); +} + +// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check +// individual pixel values for testing purposes. +class ScreenCapture : public RefBase { +public: + static void captureScreen(sp<ScreenCapture>* sc) { + sp<IMemoryHeap> heap; + uint32_t w=0, h=0; + PixelFormat fmt=0; + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 0, 0, + 0, INT_MAX)); + ASSERT_TRUE(heap != NULL); + ASSERT_EQ(PIXEL_FORMAT_RGBA_8888, fmt); + *sc = new ScreenCapture(w, h, heap); + } + + void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) { + const uint8_t* img = reinterpret_cast<const uint8_t*>(mHeap->base()); + const uint8_t* pixel = img + (4 * (y*mWidth + x)); + if (r != pixel[0] || g != pixel[1] || b != pixel[2]) { + String8 err(String8::format("pixel @ (%3d, %3d): " + "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]", + x, y, r, g, b, pixel[0], pixel[1], pixel[2])); + EXPECT_EQ(String8(), err); + } + } + +private: + ScreenCapture(uint32_t w, uint32_t h, const sp<IMemoryHeap>& heap) : + mWidth(w), + mHeight(h), + mHeap(heap) + {} + + const uint32_t mWidth; + const uint32_t mHeight; + sp<IMemoryHeap> mHeap; +}; + +class LayerUpdateTest : public ::testing::Test { +protected: + virtual void SetUp() { + mComposerClient = new SurfaceComposerClient; + ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); + + ssize_t displayWidth = mComposerClient->getDisplayWidth(0); + ssize_t displayHeight = mComposerClient->getDisplayHeight(0); + + // Background surface + mBGSurfaceControl = mComposerClient->createSurface( + String8("BG Test Surface"), 0, displayWidth, displayHeight, + PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(mBGSurfaceControl != NULL); + ASSERT_TRUE(mBGSurfaceControl->isValid()); + fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195); + + // Foreground surface + mFGSurfaceControl = mComposerClient->createSurface( + String8("FG Test Surface"), 0, 64, 64, PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(mFGSurfaceControl != NULL); + ASSERT_TRUE(mFGSurfaceControl->isValid()); + + fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); + + // Synchronization surface + mSyncSurfaceControl = mComposerClient->createSurface( + String8("Sync Test Surface"), 0, 1, 1, PIXEL_FORMAT_RGBA_8888, 0); + ASSERT_TRUE(mSyncSurfaceControl != NULL); + ASSERT_TRUE(mSyncSurfaceControl->isValid()); + + fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + + SurfaceComposerClient::openGlobalTransaction(); + + ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT_MAX-2)); + ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show()); + + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX-1)); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64)); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show()); + + ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setLayer(INT_MAX-1)); + ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setPosition(displayWidth-2, + displayHeight-2)); + ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->show()); + + SurfaceComposerClient::closeGlobalTransaction(true); + } + + virtual void TearDown() { + mComposerClient->dispose(); + mBGSurfaceControl = 0; + mFGSurfaceControl = 0; + mSyncSurfaceControl = 0; + mComposerClient = 0; + } + + void waitForPostedBuffers() { + // Since the sync surface is in synchronous mode (i.e. double buffered) + // posting three buffers to it should ensure that at least two + // SurfaceFlinger::handlePageFlip calls have been made, which should + // guaranteed that a buffer posted to another Surface has been retired. + fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + } + + sp<SurfaceComposerClient> mComposerClient; + sp<SurfaceControl> mBGSurfaceControl; + sp<SurfaceControl> mFGSurfaceControl; + + // This surface is used to ensure that the buffers posted to + // mFGSurfaceControl have been picked up by SurfaceFlinger. + sp<SurfaceControl> mSyncSurfaceControl; +}; + +TEST_F(LayerUpdateTest, LayerMoveWorks) { + sp<ScreenCapture> sc; + { + SCOPED_TRACE("before move"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 0, 12, 63, 63, 195); + sc->checkPixel( 75, 75, 195, 63, 63); + sc->checkPixel(145, 145, 63, 63, 195); + } + + SurfaceComposerClient::openGlobalTransaction(); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128)); + SurfaceComposerClient::closeGlobalTransaction(true); + { + // This should reflect the new position, but not the new color. + SCOPED_TRACE("after move, before redraw"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 63, 63, 195); + sc->checkPixel(145, 145, 195, 63, 63); + } + + fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63); + waitForPostedBuffers(); + { + // This should reflect the new position and the new color. + SCOPED_TRACE("after redraw"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 63, 63, 195); + sc->checkPixel(145, 145, 63, 195, 63); + } +} + +TEST_F(LayerUpdateTest, LayerResizeWorks) { + sp<ScreenCapture> sc; + { + SCOPED_TRACE("before resize"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 0, 12, 63, 63, 195); + sc->checkPixel( 75, 75, 195, 63, 63); + sc->checkPixel(145, 145, 63, 63, 195); + } + + LOGD("resizing"); + SurfaceComposerClient::openGlobalTransaction(); + ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128)); + SurfaceComposerClient::closeGlobalTransaction(true); + LOGD("resized"); + { + // This should not reflect the new size or color because SurfaceFlinger + // has not yet received a buffer of the correct size. + SCOPED_TRACE("after resize, before redraw"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 0, 12, 63, 63, 195); + sc->checkPixel( 75, 75, 195, 63, 63); + sc->checkPixel(145, 145, 63, 63, 195); + } + + LOGD("drawing"); + fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63); + waitForPostedBuffers(); + LOGD("drawn"); + { + // This should reflect the new size and the new color. + SCOPED_TRACE("after redraw"); + ScreenCapture::captureScreen(&sc); + sc->checkPixel( 24, 24, 63, 63, 195); + sc->checkPixel( 75, 75, 63, 195, 63); + sc->checkPixel(145, 145, 63, 195, 63); + } +} + +} |