Merge changes I4e5ff00c,Id5e3ca1d,I97cbba61
* changes: SurfaceFlinger: Remove display freezing code SurfaceFlinger: add some layer update tests SurfaceFlinger: make sync transactions explicit
This commit is contained in:
commit
cb2de7182e
@ -83,7 +83,11 @@ public:
|
||||
eOrientationUnchanged = 4,
|
||||
eOrientationSwapMask = 0x01
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
eSynchronous = 0x01,
|
||||
};
|
||||
|
||||
enum {
|
||||
eElectronBeamAnimationOn = 0x01,
|
||||
eElectronBeamAnimationOff = 0x10
|
||||
@ -103,7 +107,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
|
||||
@ -142,8 +146,6 @@ public:
|
||||
GET_CBLK,
|
||||
SET_TRANSACTION_STATE,
|
||||
SET_ORIENTATION,
|
||||
FREEZE_DISPLAY,
|
||||
UNFREEZE_DISPLAY,
|
||||
CAPTURE_SCREEN,
|
||||
TURN_ELECTRON_BEAM_OFF,
|
||||
TURN_ELECTRON_BEAM_ON,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -368,18 +368,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);
|
||||
@ -393,14 +381,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);
|
||||
}
|
||||
|
||||
@ -474,7 +454,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
|
||||
@ -511,9 +491,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,
|
||||
@ -546,11 +523,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
|
||||
@ -568,9 +540,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);
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -79,15 +79,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),
|
||||
@ -190,11 +187,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);
|
||||
|
||||
@ -322,33 +314,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:
|
||||
@ -451,7 +417,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();
|
||||
@ -582,13 +548,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;
|
||||
@ -614,11 +573,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)
|
||||
{
|
||||
@ -748,7 +702,7 @@ void SurfaceFlinger::computeVisibleRegions(
|
||||
void SurfaceFlinger::commitTransaction()
|
||||
{
|
||||
mDrawingState = mCurrentState;
|
||||
mResizeTransationPending = false;
|
||||
mTransationPending = false;
|
||||
mTransactionCV.broadcast();
|
||||
}
|
||||
|
||||
@ -1235,15 +1189,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);
|
||||
@ -1254,56 +1207,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)
|
||||
{
|
||||
@ -1489,7 +1415,6 @@ uint32_t SurfaceFlinger::setClientStateLocked(
|
||||
if (what & eSizeChanged) {
|
||||
if (layer->setSize(s.w, s.h)) {
|
||||
flags |= eTraversalNeeded;
|
||||
mResizeTransationPending = true;
|
||||
}
|
||||
}
|
||||
if (what & eAlphaChanged) {
|
||||
@ -1609,8 +1534,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,
|
||||
@ -1663,8 +1587,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:
|
||||
@ -1736,10 +1658,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;
|
||||
|
@ -46,7 +46,6 @@ namespace android {
|
||||
|
||||
class Client;
|
||||
class DisplayHardware;
|
||||
class FreezeLock;
|
||||
class Layer;
|
||||
class LayerDim;
|
||||
struct surface_flinger_cblk_t;
|
||||
@ -168,9 +167,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;
|
||||
|
||||
@ -244,12 +241,10 @@ private:
|
||||
struct State {
|
||||
State() {
|
||||
orientation = ISurfaceComposer::eOrientationDefault;
|
||||
freezeDisplay = 0;
|
||||
}
|
||||
LayerVector layersSortedByZ;
|
||||
uint8_t orientation;
|
||||
uint8_t orientationFlags;
|
||||
uint8_t freezeDisplay;
|
||||
};
|
||||
|
||||
virtual bool threadLoop();
|
||||
@ -308,20 +303,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;
|
||||
@ -341,7 +322,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];
|
||||
@ -364,10 +345,7 @@ private:
|
||||
Region mWormholeRegion;
|
||||
bool mVisibleRegionsDirty;
|
||||
bool mHwWorkListDirty;
|
||||
bool mFreezeDisplay;
|
||||
int32_t mElectronBeamAnimationMode;
|
||||
int32_t mFreezeCount;
|
||||
nsecs_t mFreezeDisplayTime;
|
||||
Vector< sp<LayerBase> > mVisibleLayersSortedByZ;
|
||||
|
||||
|
||||
@ -402,20 +380,6 @@ private:
|
||||
volatile int32_t mSecureFrameBuffer;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class FreezeLock : public LightRefBase<FreezeLock> {
|
||||
SurfaceFlinger* mFlinger;
|
||||
public:
|
||||
FreezeLock(SurfaceFlinger* flinger)
|
||||
: mFlinger(flinger) {
|
||||
mFlinger->incFreezeCount();
|
||||
}
|
||||
~FreezeLock() {
|
||||
mFlinger->decFreezeCount();
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
}; // namespace android
|
||||
|
||||
|
@ -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
|
||||
|
236
services/surfaceflinger/tests/Transaction_test.cpp
Normal file
236
services/surfaceflinger/tests/Transaction_test.cpp
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user