diff options
29 files changed, 1278 insertions, 1275 deletions
diff --git a/include/private/ui/LayerState.h b/include/private/ui/LayerState.h index b6fcd80..f1a2618 100644 --- a/include/private/ui/LayerState.h +++ b/include/private/ui/LayerState.h @@ -25,8 +25,6 @@ #include <ui/ISurfaceFlingerClient.h> #include <ui/Region.h> -#include <private/ui/SharedState.h> - namespace android { class Parcel; diff --git a/include/private/ui/SharedBufferStack.h b/include/private/ui/SharedBufferStack.h new file mode 100644 index 0000000..2bd5344 --- /dev/null +++ b/include/private/ui/SharedBufferStack.h @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2007 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. + */ + +#ifndef ANDROID_UI_SHARED_BUFFER_STACK_H +#define ANDROID_UI_SHARED_BUFFER_STACK_H + +#include <stdint.h> +#include <sys/types.h> + +#include <cutils/compiler.h> + +#include <utils/Debug.h> +#include <utils/threads.h> +#include <utils/String8.h> + +#include <ui/Rect.h> + +namespace android { +// --------------------------------------------------------------------------- + +/* + * These classes manage a stack of buffers in shared memory. + * + * SharedClient: represents a client with several stacks + * SharedBufferStack: represents a stack of buffers + * SharedBufferClient: manipulates the SharedBufferStack from the client side + * SharedBufferServer: manipulates the SharedBufferStack from the server side + * + * Buffers can be dequeued until there are none available, they can be locked + * unless they are in use by the server, which is only the case for the last + * dequeue-able buffer. When these various conditions are not met, the caller + * waits until the condition is met. + * + * + * CAVEATS: + * + * In the current implementation there are several limitations: + * - buffers must be locked in the same order they've been dequeued + * - buffers must be enqueued in the same order they've been locked + * - dequeue() is not reentrant + * - no error checks are done on the condition above + * + */ + +// When changing these values, the COMPILE_TIME_ASSERT at the end of this +// file need to be updated. +const unsigned int NUM_LAYERS_MAX = 31; +const unsigned int NUM_BUFFER_MAX = 4; +const unsigned int NUM_DISPLAY_MAX = 4; + +// ---------------------------------------------------------------------------- + +class Region; +class SharedBufferStack; +class SharedClient; + +// ---------------------------------------------------------------------------- + +struct FlatRegion { // 12 bytes + static const unsigned int NUM_RECT_MAX = 1; + uint32_t count; + uint16_t rects[4*NUM_RECT_MAX]; +}; + +// should be 128 bytes (32 longs) +class SharedBufferStack +{ + friend class SharedClient; + friend class SharedBufferBase; + friend class SharedBufferClient; + friend class SharedBufferServer; + +public: + SharedBufferStack(); + status_t setDirtyRegion(int buffer, const Region& reg); + Region getDirtyRegion(int buffer) const; + + // these attributes are part of the conditions/updates + volatile int32_t head; // server's current front buffer + volatile int32_t available; // number of dequeue-able buffers + volatile int32_t queued; // number of buffers waiting for post + volatile int32_t inUse; // buffer currently in use by SF + + // not part of the conditions + volatile int32_t reallocMask; + + int32_t identity; // surface's identity (const) + status_t status; // surface's status code + int32_t reserved32[13]; + FlatRegion dirtyRegion[NUM_BUFFER_MAX]; // 12*4=48 bytes +}; + +// ---------------------------------------------------------------------------- + +// 4 KB max +class SharedClient +{ +public: + SharedClient(); + ~SharedClient(); + + status_t validate(size_t token) const; + uint32_t getIdentity(size_t token) const; + status_t setIdentity(size_t token, uint32_t identity); + +private: + friend class SharedBufferBase; + friend class SharedBufferClient; + friend class SharedBufferServer; + + // FIXME: this should be replaced by a lock-less primitive + Mutex lock; + Condition cv; + SharedBufferStack surfaces[ NUM_LAYERS_MAX ]; +}; + +// ============================================================================ + +class SharedBufferBase +{ +public: + SharedBufferBase(SharedClient* sharedClient, int surface, int num); + ~SharedBufferBase(); + uint32_t getIdentity(); + size_t getFrontBuffer() const; + String8 dump(char const* prefix) const; + +protected: + SharedClient* const mSharedClient; + SharedBufferStack* const mSharedStack; + const int mNumBuffers; + + friend struct Update; + friend struct QueueUpdate; + + struct ConditionBase { + SharedBufferStack& stack; + inline ConditionBase(SharedBufferBase* sbc) + : stack(*sbc->mSharedStack) { } + }; + + struct UpdateBase { + SharedBufferStack& stack; + inline UpdateBase(SharedBufferBase* sbb) + : stack(*sbb->mSharedStack) { } + }; + + template <typename T> + status_t waitForCondition(T condition); + + template <typename T> + status_t updateCondition(T update); +}; + +template <typename T> +status_t SharedBufferBase::waitForCondition(T condition) +{ + SharedClient& client( *mSharedClient ); + const nsecs_t TIMEOUT = s2ns(1); + Mutex::Autolock _l(client.lock); + while (!condition()) { + status_t err = client.cv.waitRelative(client.lock, TIMEOUT); + + // handle errors and timeouts + if (CC_UNLIKELY(err != NO_ERROR)) { + if (err == TIMED_OUT) { + if (condition()) { + LOGE("waitForCondition(%s) timed out (identity=%d), " + "but condition is true! We recovered but it " + "shouldn't happen." , + T::name(), mSharedStack->identity); + break; + } else { + LOGW("waitForCondition(%s) timed out (identity=%d). " + "CPU may be pegged. trying again.", + T::name(), mSharedStack->identity); + } + } else { + LOGE("waitForCondition(%s) error (%s) ", + T::name(), strerror(-err)); + return err; + } + } + } + return NO_ERROR; +} + + +template <typename T> +status_t SharedBufferBase::updateCondition(T update) { + SharedClient& client( *mSharedClient ); + Mutex::Autolock _l(client.lock); + ssize_t result = update(); + client.cv.broadcast(); + return result; +} + +// ---------------------------------------------------------------------------- + +class SharedBufferClient : public SharedBufferBase +{ +public: + SharedBufferClient(SharedClient* sharedClient, int surface, int num); + + ssize_t dequeue(); + status_t undoDequeue(int buf); + + status_t lock(int buf); + status_t queue(int buf); + bool needNewBuffer(int buffer) const; + status_t setDirtyRegion(int buffer, const Region& reg); + +private: + friend struct Condition; + friend struct DequeueCondition; + friend struct LockCondition; + + struct QueueUpdate : public UpdateBase { + inline QueueUpdate(SharedBufferBase* sbb); + inline ssize_t operator()(); + }; + + struct UndoDequeueUpdate : public UpdateBase { + inline UndoDequeueUpdate(SharedBufferBase* sbb); + inline ssize_t operator()(); + }; + + // -- + + struct DequeueCondition : public ConditionBase { + inline DequeueCondition(SharedBufferClient* sbc); + inline bool operator()(); + static inline const char* name() { return "DequeueCondition"; } + }; + + struct LockCondition : public ConditionBase { + int buf; + inline LockCondition(SharedBufferClient* sbc, int buf); + inline bool operator()(); + static inline const char* name() { return "LockCondition"; } + }; + + int32_t tail; +}; + +// ---------------------------------------------------------------------------- + +class SharedBufferServer : public SharedBufferBase +{ +public: + SharedBufferServer(SharedClient* sharedClient, int surface, int num); + + ssize_t retireAndLock(); + status_t unlock(int buffer); + status_t reallocate(); + status_t assertReallocate(int buffer); + + Region getDirtyRegion(int buffer) const; + +private: + struct UnlockUpdate : public UpdateBase { + const int lockedBuffer; + inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer); + inline ssize_t operator()(); + }; + + struct RetireUpdate : public UpdateBase { + const int numBuffers; + inline RetireUpdate(SharedBufferBase* sbb, int numBuffers); + inline ssize_t operator()(); + }; + + struct ReallocateCondition : public ConditionBase { + int buf; + inline ReallocateCondition(SharedBufferBase* sbb, int buf); + inline bool operator()(); + static inline const char* name() { return "ReallocateCondition"; } + }; +}; + +// =========================================================================== + +struct display_cblk_t +{ + uint16_t w; + uint16_t h; + uint8_t format; + uint8_t orientation; + uint8_t reserved[2]; + float fps; + float density; + float xdpi; + float ydpi; + uint32_t pad[2]; +}; + +struct surface_flinger_cblk_t // 4KB max +{ + uint8_t connected; + uint8_t reserved[3]; + uint32_t pad[7]; + display_cblk_t displays[NUM_DISPLAY_MAX]; +}; + +// --------------------------------------------------------------------------- + +COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 4096) +COMPILE_TIME_ASSERT(sizeof(SharedBufferStack) == 128) +COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096) + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif /* ANDROID_UI_SHARED_BUFFER_STACK_H */ diff --git a/include/private/ui/SharedState.h b/include/private/ui/SharedState.h deleted file mode 100644 index c9f6b5e..0000000 --- a/include/private/ui/SharedState.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#ifndef ANDROID_UI_SHARED_STATE_H -#define ANDROID_UI_SHARED_STATE_H - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Debug.h> -#include <utils/threads.h> - -namespace android { - -/* - * These structures are shared between the composer process and its clients - */ - -// --------------------------------------------------------------------------- - -struct surface_info_t { // 4 longs, 16 bytes - enum { - eBufferDirty = 0x01, - eNeedNewBuffer = 0x02 - }; - uint8_t reserved[11]; - uint8_t flags; - status_t status; -}; - -// --------------------------------------------------------------------------- - -const uint32_t NUM_LAYERS_MAX = 31; - -enum { // layer_cblk_t swapState - eIndex = 0x00000001, - eFlipRequested = 0x00000002, - - eResizeBuffer0 = 0x00000004, - eResizeBuffer1 = 0x00000008, - eResizeRequested = eResizeBuffer0 | eResizeBuffer1, - - eBusy = 0x00000010, - eLocked = 0x00000020, - eNextFlipPending = 0x00000040, - eInvalidSurface = 0x00000080 -}; - -enum { // layer_cblk_t flags - eLayerNotPosted = 0x00000001, - eNoCopyBack = 0x00000002, - eReserved = 0x0000007C, - eBufferIndexShift = 7, - eBufferIndex = 1<<eBufferIndexShift, -}; - -struct flat_region_t // 40 bytes -{ - int32_t count; - int16_t l; - int16_t t; - int16_t r; - int16_t b; - uint16_t runs[14]; -}; - -struct layer_cblk_t // (128 bytes) -{ - volatile int32_t swapState; // 4 - volatile int32_t flags; // 4 - volatile int32_t identity; // 4 - int32_t reserved; // 4 - surface_info_t surface[2]; // 32 - flat_region_t region[2]; // 80 - - static inline int backBuffer(uint32_t state) { - return ((state & eIndex) ^ ((state & eFlipRequested)>>1)); - } - static inline int frontBuffer(uint32_t state) { - return 1 - backBuffer(state); - } -}; - -// --------------------------------------------------------------------------- - -struct per_client_cblk_t // 4KB max -{ - per_client_cblk_t() : lock(Mutex::SHARED) { } - - Mutex lock; - Condition cv; - layer_cblk_t layers[NUM_LAYERS_MAX] __attribute__((aligned(32))); - - enum { - BLOCKING = 0x00000001, - INSPECT = 0x00000002 - }; - - // these functions are used by the clients - status_t validate(size_t i) const; - int32_t lock_layer(size_t i, uint32_t flags); - uint32_t unlock_layer_and_post(size_t i); - void unlock_layer(size_t i); -}; -// --------------------------------------------------------------------------- - -const uint32_t NUM_DISPLAY_MAX = 4; - -struct display_cblk_t -{ - uint16_t w; - uint16_t h; - uint8_t format; - uint8_t orientation; - uint8_t reserved[2]; - float fps; - float density; - float xdpi; - float ydpi; - uint32_t pad[2]; -}; - -struct surface_flinger_cblk_t // 4KB max -{ - uint8_t connected; - uint8_t reserved[3]; - uint32_t pad[7]; - display_cblk_t displays[NUM_DISPLAY_MAX]; -}; - -// --------------------------------------------------------------------------- - -COMPILE_TIME_ASSERT(sizeof(layer_cblk_t) == 128) -COMPILE_TIME_ASSERT(sizeof(per_client_cblk_t) <= 4096) -COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096) - -// --------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_UI_SHARED_STATE_H - diff --git a/include/private/ui/SurfaceBuffer.h b/include/private/ui/SurfaceBuffer.h index bf68406..73e517b 100644 --- a/include/private/ui/SurfaceBuffer.h +++ b/include/private/ui/SurfaceBuffer.h @@ -47,6 +47,9 @@ public: status_t lock(uint32_t usage, const Rect& rect, void** vaddr); status_t unlock(); + void setIndex(int index); + int getIndex() const; + protected: SurfaceBuffer(); SurfaceBuffer(const Parcel& reply); @@ -69,6 +72,7 @@ private: android_native_buffer_t const* buffer); BufferMapper& mBufferMapper; + int mIndex; }; }; // namespace android diff --git a/include/ui/ISurface.h b/include/ui/ISurface.h index 7909c2f..1283033 100644 --- a/include/ui/ISurface.h +++ b/include/ui/ISurface.h @@ -44,13 +44,13 @@ protected: UNREGISTER_BUFFERS, POST_BUFFER, // one-way transaction CREATE_OVERLAY, - GET_BUFFER, + REQUEST_BUFFER, }; public: DECLARE_META_INTERFACE(Surface); - virtual sp<SurfaceBuffer> getBuffer(int usage) = 0; + virtual sp<SurfaceBuffer> requestBuffer(int bufferIdx, int usage) = 0; class BufferHeap { public: diff --git a/include/ui/Surface.h b/include/ui/Surface.h index 30ab82f..118fb83 100644 --- a/include/ui/Surface.h +++ b/include/ui/Surface.h @@ -39,8 +39,8 @@ class IOMX; class Rect; class Surface; class SurfaceComposerClient; -struct per_client_cblk_t; -struct layer_cblk_t; +class SharedClient; +class SharedBufferClient; // --------------------------------------------------------------------------- @@ -109,7 +109,7 @@ private: ~SurfaceControl(); - status_t validate(per_client_cblk_t const* cblk) const; + status_t validate(SharedClient const* cblk) const; void destroy(); sp<SurfaceComposerClient> mClient; @@ -190,8 +190,7 @@ private: status_t getBufferLocked(int index, int usage); - status_t validate(per_client_cblk_t const* cblk) const; - static void _send_dirty_region(layer_cblk_t* lcblk, const Region& dirty); + status_t validate(SharedClient const* cblk) const; inline const BufferMapper& getBufferMapper() const { return mBufferMapper; } inline BufferMapper& getBufferMapper() { return mBufferMapper; } @@ -210,11 +209,10 @@ private: int perform(int operation, va_list args); status_t dequeueBuffer(sp<SurfaceBuffer>* buffer); - status_t lockBuffer(const sp<SurfaceBuffer>& buffer); - status_t queueBuffer(const sp<SurfaceBuffer>& buffer); void setUsage(uint32_t reqUsage); + bool getUsage(uint32_t* usage); // constants sp<SurfaceComposerClient> mClient; @@ -224,21 +222,23 @@ private: PixelFormat mFormat; uint32_t mFlags; BufferMapper& mBufferMapper; + SharedBufferClient* mSharedBufferClient; // protected by mSurfaceLock Rect mSwapRectangle; uint32_t mUsage; - bool mUsageChanged; + int32_t mUsageChanged; // protected by mSurfaceLock. These are also used from lock/unlock // but in that case, they must be called form the same thread. sp<SurfaceBuffer> mBuffers[2]; mutable Region mDirtyRegion; - mutable uint8_t mBackbufferIndex; // must be used from the lock/unlock thread sp<SurfaceBuffer> mLockedBuffer; + sp<SurfaceBuffer> mPostedBuffer; mutable Region mOldDirtyRegion; + bool mNeedFullUpdate; // query() must be called from dequeueBuffer() thread uint32_t mWidth; @@ -246,6 +246,7 @@ private: // Inherently thread-safe mutable Mutex mSurfaceLock; + mutable Mutex mApiLock; }; }; // namespace android diff --git a/include/ui/SurfaceComposerClient.h b/include/ui/SurfaceComposerClient.h index 286f885..269959c 100644 --- a/include/ui/SurfaceComposerClient.h +++ b/include/ui/SurfaceComposerClient.h @@ -21,7 +21,6 @@ #include <sys/types.h> #include <utils/SortedVector.h> -#include <utils/KeyedVector.h> #include <utils/RefBase.h> #include <utils/threads.h> @@ -36,8 +35,7 @@ namespace android { class Region; class SurfaceFlingerSynchro; -struct per_client_cblk_t; -struct layer_cblk_t; +class SharedClient; class SurfaceComposerClient : virtual public RefBase { @@ -63,12 +61,12 @@ public: //! Create a surface sp<SurfaceControl> createSurface( - int pid, //!< pid of the process the surfacec is for - DisplayID display, //!< Display to create this surface on - uint32_t w, //!< width in pixel - uint32_t h, //!< height in pixel - PixelFormat format, //!< pixel-format desired - uint32_t flags = 0 //!< usage flags + int pid, // pid of the process the surface is for + DisplayID display, // Display to create this surface on + uint32_t w, // width in pixel + uint32_t h, // height in pixel + PixelFormat format, // pixel-format desired + uint32_t flags = 0 // usage flags ); // ------------------------------------------------------------------------ @@ -148,7 +146,7 @@ private: // these don't need to be protected because they never change // after assignment status_t mStatus; - per_client_cblk_t* mControl; + SharedClient* mControl; sp<IMemoryHeap> mControlMemory; sp<ISurfaceFlingerClient> mClient; SurfaceFlingerSynchro* mSignalServer; diff --git a/include/utils/Errors.h b/include/utils/Errors.h index 1bf9e6f..81f818b 100644 --- a/include/utils/Errors.h +++ b/include/utils/Errors.h @@ -63,7 +63,7 @@ enum { BAD_INDEX = -EOVERFLOW, NOT_ENOUGH_DATA = -ENODATA, WOULD_BLOCK = -EWOULDBLOCK, - TIMED_OUT = -ETIME, + TIMED_OUT = -ETIMEDOUT, UNKNOWN_TRANSACTION = -EBADMSG, #else BAD_INDEX = -E2BIG, diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk index c4a70c8..49da111 100644 --- a/libs/surfaceflinger/Android.mk +++ b/libs/surfaceflinger/Android.mk @@ -6,12 +6,12 @@ LOCAL_SRC_FILES:= \ DisplayHardware/DisplayHardware.cpp \ DisplayHardware/DisplayHardwareBase.cpp \ BlurFilter.cpp.arm \ + Buffer.cpp \ BufferAllocator.cpp \ Layer.cpp \ LayerBase.cpp \ LayerBuffer.cpp \ LayerBlur.cpp \ - LayerBitmap.cpp \ LayerDim.cpp \ MessageQueue.cpp \ SurfaceFlinger.cpp \ diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/Buffer.cpp index dd61e1a..4a7c55e 100644 --- a/libs/surfaceflinger/LayerBitmap.cpp +++ b/libs/surfaceflinger/Buffer.cpp @@ -27,8 +27,8 @@ #include <ui/Surface.h> #include <pixelflinger/pixelflinger.h> +#include "Buffer.h" #include "BufferAllocator.h" -#include "LayerBitmap.h" #include "SurfaceFlinger.h" @@ -38,15 +38,16 @@ namespace android { // Buffer and implementation of android_native_buffer_t // =========================================================================== +Buffer::Buffer() + : SurfaceBuffer(), mInitCheck(NO_ERROR), mVStride(0) +{ +} + Buffer::Buffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t reqUsage, uint32_t flags) - : SurfaceBuffer(), mInitCheck(NO_INIT), mFlags(flags), - mVStride(0) + : SurfaceBuffer(), mInitCheck(NO_INIT), mVStride(0) { - this->format = format; - if (w>0 && h>0) { - mInitCheck = initSize(w, h, reqUsage); - } + mInitCheck = initSize(w, h, format, reqUsage, flags); } Buffer::~Buffer() @@ -66,7 +67,19 @@ android_native_buffer_t* Buffer::getNativeBuffer() const return static_cast<android_native_buffer_t*>(const_cast<Buffer*>(this)); } -status_t Buffer::initSize(uint32_t w, uint32_t h, uint32_t reqUsage) +status_t Buffer::reallocate(uint32_t w, uint32_t h, PixelFormat f, + uint32_t reqUsage, uint32_t flags) +{ + if (handle) { + BufferAllocator& allocator(BufferAllocator::get()); + allocator.free(handle); + handle = 0; + } + return initSize(w, h, f, reqUsage, flags); +} + +status_t Buffer::initSize(uint32_t w, uint32_t h, PixelFormat format, + uint32_t reqUsage, uint32_t flags) { status_t err = NO_ERROR; @@ -84,7 +97,7 @@ status_t Buffer::initSize(uint32_t w, uint32_t h, uint32_t reqUsage) * */ - if (mFlags & Buffer::SECURE) { + if (flags & Buffer::SECURE) { // secure buffer, don't store it into the GPU usage = BufferAllocator::USAGE_SW_READ_OFTEN | BufferAllocator::USAGE_SW_WRITE_OFTEN; @@ -95,10 +108,10 @@ status_t Buffer::initSize(uint32_t w, uint32_t h, uint32_t reqUsage) } err = allocator.alloc(w, h, format, usage, &handle, &stride); - if (err == NO_ERROR) { - width = w; - height = h; + this->width = w; + this->height = h; + this->format = format; mVStride = 0; } @@ -121,78 +134,6 @@ status_t Buffer::lock(GGLSurface* sur, uint32_t usage) return res; } -// =========================================================================== -// LayerBitmap -// =========================================================================== - -LayerBitmap::LayerBitmap() - : mInfo(0), mWidth(0), mHeight(0) -{ -} - -LayerBitmap::~LayerBitmap() -{ -} - -status_t LayerBitmap::init(surface_info_t* info, - uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) -{ - if (info == NULL) - return BAD_VALUE; - - mFormat = format; - mFlags = flags; - mWidth = w; - mHeight = h; - - mInfo = info; - memset(info, 0, sizeof(surface_info_t)); - info->flags = surface_info_t::eNeedNewBuffer; - - // init the buffer, but don't trigger an allocation - mBuffer = new Buffer(0, 0, format, flags); - return NO_ERROR; -} - -status_t LayerBitmap::setSize(uint32_t w, uint32_t h) -{ - Mutex::Autolock _l(mLock); - if ((w != mWidth) || (h != mHeight)) { - mWidth = w; - mHeight = h; - // this will signal the client that it needs to asks us for a new buffer - mInfo->flags = surface_info_t::eNeedNewBuffer; - } - return NO_ERROR; -} - -sp<Buffer> LayerBitmap::allocate(uint32_t reqUsage) -{ - Mutex::Autolock _l(mLock); - surface_info_t* info = mInfo; - mBuffer.clear(); // free buffer before allocating a new one - sp<Buffer> buffer = new Buffer(mWidth, mHeight, mFormat, reqUsage, mFlags); - status_t err = buffer->initCheck(); - if (LIKELY(err == NO_ERROR)) { - info->flags = surface_info_t::eBufferDirty; - info->status = NO_ERROR; - } else { - memset(info, 0, sizeof(surface_info_t)); - info->status = NO_MEMORY; - } - mBuffer = buffer; - return buffer; -} - -status_t LayerBitmap::free() -{ - mBuffer.clear(); - mWidth = 0; - mHeight = 0; - return NO_ERROR; -} - - // --------------------------------------------------------------------------- }; // namespace android diff --git a/libs/surfaceflinger/LayerBitmap.h b/libs/surfaceflinger/Buffer.h index 87e8f42..79f4eeb 100644 --- a/libs/surfaceflinger/LayerBitmap.h +++ b/libs/surfaceflinger/Buffer.h @@ -30,7 +30,7 @@ #include <pixelflinger/pixelflinger.h> -#include <private/ui/SharedState.h> +#include <private/ui/SharedBufferStack.h> #include <private/ui/SurfaceBuffer.h> class copybit_image_t; @@ -38,10 +38,6 @@ struct android_native_buffer_t; namespace android { -// --------------------------------------------------------------------------- -class IMemory; -class LayerBitmap; - // =========================================================================== // Buffer // =========================================================================== @@ -56,6 +52,8 @@ public: SECURE = 0x00000004 }; + Buffer(); + // creates w * h buffer Buffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t reqUsage, uint32_t flags = 0); @@ -74,6 +72,9 @@ public: android_native_buffer_t* getNativeBuffer() const; + status_t reallocate(uint32_t w, uint32_t h, PixelFormat f, + uint32_t reqUsage, uint32_t flags); + private: friend class LightRefBase<Buffer>; Buffer(const Buffer& rhs); @@ -81,52 +82,11 @@ private: Buffer& operator = (const Buffer& rhs); const Buffer& operator = (const Buffer& rhs) const; - status_t initSize(uint32_t w, uint32_t h, uint32_t reqUsage); - - ssize_t mInitCheck; - uint32_t mFlags; - uint32_t mVStride; -}; - -// =========================================================================== -// LayerBitmap -// =========================================================================== + status_t initSize(uint32_t w, uint32_t h, PixelFormat format, + uint32_t reqUsage, uint32_t flags); -class LayerBitmap -{ -public: - enum { - DONT_CLEAR = Buffer::DONT_CLEAR, - SECURE = Buffer::SECURE - }; - LayerBitmap(); - ~LayerBitmap(); - - status_t init(surface_info_t* info, - uint32_t w, uint32_t h, PixelFormat format, uint32_t flags = 0); - - status_t setSize(uint32_t w, uint32_t h); - - sp<Buffer> allocate(uint32_t reqUsage); - status_t free(); - - sp<const Buffer> getBuffer() const { return mBuffer; } - sp<Buffer> getBuffer() { return mBuffer; } - - uint32_t getWidth() const { return mWidth; } - uint32_t getHeight() const { return mHeight; } - PixelFormat getPixelFormat() const { return mBuffer->getPixelFormat(); } - Rect getBounds() const { return mBuffer->getBounds(); } - -private: - surface_info_t* mInfo; - sp<Buffer> mBuffer; - uint32_t mWidth; - uint32_t mHeight; - PixelFormat mFormat; - uint32_t mFlags; - // protects setSize() and allocate() - mutable Mutex mLock; + ssize_t mInitCheck; + uint32_t mVStride; }; }; // namespace android diff --git a/libs/surfaceflinger/BufferAllocator.cpp b/libs/surfaceflinger/BufferAllocator.cpp index cee8b64..19867a5 100644 --- a/libs/surfaceflinger/BufferAllocator.cpp +++ b/libs/surfaceflinger/BufferAllocator.cpp @@ -71,14 +71,23 @@ void BufferAllocator::dump(String8& result) const result.append(buffer); } +static inline uint32_t clamp(uint32_t c) { + return c>0 ? c : 1; +} + status_t BufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format, int usage, buffer_handle_t* handle, int32_t* stride) { Mutex::Autolock _l(mLock); - + + // make sure to not allocate a 0 x 0 buffer + w = clamp(w); + h = clamp(h); + // we have a h/w allocator and h/w buffer is requested status_t err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride); + LOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)", w, h, format, usage, err, strerror(-err)); diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp index 3f607f6..651e7cf 100644 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -46,22 +46,25 @@ using namespace android; static __attribute__((noinline)) void checkGLErrors() { - GLenum error = glGetError(); - if (error != GL_NO_ERROR) + do { + // there could be more than one error flag + GLenum error = glGetError(); + if (error == GL_NO_ERROR) + break; LOGE("GL error 0x%04x", int(error)); + } while(true); } static __attribute__((noinline)) void checkEGLErrors(const char* token) { EGLint error = eglGetError(); - // GLESonGL seems to be returning 0 when there is no errors? - if (error && error != EGL_SUCCESS) - LOGE("%s error 0x%04x (%s)", + if (error && error != EGL_SUCCESS) { + LOGE("%s: EGL error 0x%04x (%s)", token, int(error), EGLUtils::strerror(error)); + } } - /* * Initialize the display to the specified values. * @@ -158,7 +161,6 @@ void DisplayHardware::init(uint32_t dpy) */ surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL); - checkEGLErrors("eglCreateWindowSurface"); if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) { if (dummy == EGL_BUFFER_PRESERVED) { @@ -212,8 +214,6 @@ void DisplayHardware::init(uint32_t dpy) */ context = eglCreateContext(display, config, NULL, NULL); - //checkEGLErrors("eglCreateContext"); - /* * Gather OpenGL ES extensions diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp index 6f92515..ecb6b32 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/libs/surfaceflinger/Layer.cpp @@ -28,9 +28,9 @@ #include <ui/PixelFormat.h> #include <ui/Surface.h> +#include "Buffer.h" #include "clz.h" #include "Layer.h" -#include "LayerBitmap.h" #include "SurfaceFlinger.h" #include "DisplayHardware/DisplayHardware.h" @@ -47,26 +47,29 @@ const char* const Layer::typeID = "Layer"; // --------------------------------------------------------------------------- -Layer::Layer(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& c, int32_t i) - : LayerBaseClient(flinger, display, c, i), +Layer::Layer(SurfaceFlinger* flinger, DisplayID display, + const sp<Client>& c, int32_t i) + : LayerBaseClient(flinger, display, c, i), lcblk(NULL), mSecure(false), - mFrontBufferIndex(1), - mNeedsBlending(true), - mResizeTransactionDone(false) + mNeedsBlending(true) { // no OpenGL operation is possible here, since we might not be // in the OpenGL thread. + lcblk = new SharedBufferServer(c->ctrlblk, i, NUM_BUFFERS); + mFrontBufferIndex = lcblk->getFrontBuffer(); } Layer::~Layer() { destroy(); // the actual buffers will be destroyed here + delete lcblk; + } void Layer::destroy() { - for (int i=0 ; i<NUM_BUFFERS ; i++) { + for (size_t i=0 ; i<NUM_BUFFERS ; i++) { if (mTextures[i].name != -1U) { glDeleteTextures(1, &mTextures[i].name); mTextures[i].name = -1U; @@ -76,19 +79,11 @@ void Layer::destroy() eglDestroyImageKHR(dpy, mTextures[i].image); mTextures[i].image = EGL_NO_IMAGE_KHR; } - mBuffers[i].free(); + mBuffers[i].clear(); } mSurface.clear(); } -void Layer::initStates(uint32_t w, uint32_t h, uint32_t flags) -{ - LayerBase::initStates(w,h,flags); - - if (flags & ISurfaceComposer::eDestroyBackbuffer) - lcblk->flags |= eNoCopyBack; -} - sp<LayerBaseClient::Surface> Layer::createSurface() const { return mSurface; @@ -112,13 +107,14 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, if (flags & ISurfaceComposer::eSecure) bufferFlags |= Buffer::SECURE; + mFormat = format; + mWidth = w; + mHeight = h; mSecure = (bufferFlags & Buffer::SECURE) ? true : false; mNeedsBlending = (info.h_alpha - info.l_alpha) > 0; - for (int i=0 ; i<2 ; i++) { - err = mBuffers[i].init(lcblk->surface + i, w, h, format, bufferFlags); - if (err != NO_ERROR) { - return err; - } + mBufferFlags = bufferFlags; + for (size_t i=0 ; i<NUM_BUFFERS ; i++) { + mBuffers[i] = new Buffer(); } mSurface = new SurfaceLayer(mFlinger, clientIndex(), this); return NO_ERROR; @@ -126,7 +122,8 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, void Layer::reloadTexture(const Region& dirty) { - const sp<Buffer>& buffer(frontBuffer().getBuffer()); + Mutex::Autolock _l(mLock); + sp<Buffer> buffer(getFrontBuffer()); if (LIKELY(mFlags & DisplayHardware::DIRECT_TEXTURE)) { int index = mFrontBufferIndex; if (LIKELY(!mTextures[index].dirty)) { @@ -202,80 +199,64 @@ void Layer::onDraw(const Region& clip) const const int index = (mFlags & DisplayHardware::DIRECT_TEXTURE) ? mFrontBufferIndex : 0; GLuint textureName = mTextures[index].name; - if (UNLIKELY(textureName == -1LU)) { - LOGW("Layer %p doesn't have a texture", this); + //LOGW("Layer %p doesn't have a texture", this); // the texture has not been created yet, this Layer has // in fact never been drawn into. this happens frequently with // SurfaceView. clearWithOpenGL(clip); return; } + drawWithOpenGL(clip, mTextures[index]); } -sp<SurfaceBuffer> Layer::peekBuffer(int usage) +sp<SurfaceBuffer> Layer::requestBuffer(int index, int usage) { /* - * This is called from the client's Surface::lock(), after it locked - * the surface successfully. We're therefore guaranteed that the - * back-buffer is not in use by ourselves. - * Of course, we need to validate all this, which is not trivial. - * - * FIXME: A resize could happen at any time here. What to do about this? - * - resize() form post() - * - resize() from doTransaction() - * - * We'll probably need an internal lock for this. - * + * This is called from the client's Surface::dequeue(). This can happen + * at any time, especially while we're in the middle of using the + * buffer 'index' as our front buffer. * - * TODO: We need to make sure that post() doesn't swap - * the buffers under us. + * Make sure the buffer we're resizing is not the front buffer and has been + * dequeued. Once this condition is asserted, we are guaranteed that this + * buffer cannot become the front buffer under our feet, since we're called + * from Surface::dequeue() */ + status_t err = lcblk->assertReallocate(index); + LOGE_IF(err, "assertReallocate(%d) failed (%s)", index, strerror(-err)); - // it's okay to read swapState for the purpose of figuring out the - // backbuffer index, which cannot change (since the app has locked it). - const uint32_t state = lcblk->swapState; - const int32_t backBufferIndex = layer_cblk_t::backBuffer(state); + Mutex::Autolock _l(mLock); + uint32_t w = mWidth; + uint32_t h = mHeight; - // get rid of the EGL image, since we shouldn't need it anymore - // (note that we're in a different thread than where it is being used) - if (mTextures[backBufferIndex].image != EGL_NO_IMAGE_KHR) { - EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); - eglDestroyImageKHR(dpy, mTextures[backBufferIndex].image); - mTextures[backBufferIndex].image = EGL_NO_IMAGE_KHR; + sp<Buffer>& buffer(mBuffers[index]); + if (buffer->getStrongCount() == 1) { + err = buffer->reallocate(w, h, mFormat, usage, mBufferFlags); + } else { + // here we have to reallocate a new buffer because we could have a + // client in our process with a reference to it (eg: status bar), + // and we can't release the handle under its feet. + buffer.clear(); + buffer = new Buffer(w, h, mFormat, usage, mBufferFlags); + err = buffer->initCheck(); } - - LayerBitmap& layerBitmap(mBuffers[backBufferIndex]); - sp<SurfaceBuffer> buffer = layerBitmap.allocate(usage); - - LOGD_IF(DEBUG_RESIZE, - "Layer::getBuffer(this=%p), index=%d, (%d,%d), (%d,%d)", - this, backBufferIndex, - layerBitmap.getWidth(), - layerBitmap.getHeight(), - layerBitmap.getBuffer()->getWidth(), - layerBitmap.getBuffer()->getHeight()); - - if (UNLIKELY(buffer == 0)) { - // XXX: what to do, what to do? + + if (err || buffer->handle == 0) { + LOGE_IF(err || buffer->handle == 0, + "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d failed (%s)", + this, index, w, h, strerror(-err)); } else { - // texture is now dirty... - mTextures[backBufferIndex].dirty = true; - // ... so it the visible region (because we consider the surface's - // buffer size for visibility calculations) - forceVisibilityTransaction(); - mFlinger->setTransactionFlags(eTraversalNeeded); + LOGD_IF(DEBUG_RESIZE, + "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d", + this, index, w, h); } - return buffer; -} -void Layer::scheduleBroadcast() -{ - sp<Client> ourClient(client.promote()); - if (ourClient != 0) { - mFlinger->scheduleBroadcast(ourClient); + if (err == NO_ERROR && buffer->handle != 0) { + // texture is now dirty... + mTextures[index].dirty = true; } + return buffer; } uint32_t Layer::doTransaction(uint32_t flags) @@ -283,114 +264,48 @@ uint32_t Layer::doTransaction(uint32_t flags) const Layer::State& front(drawingState()); const Layer::State& temp(currentState()); - // the test front.{w|h} != temp.{w|h} is not enough because it is possible - // that the size changed back to its previous value before the buffer - // was resized (in the eLocked case below), in which case, we still - // need to execute the code below so the clients have a chance to be - // release. resize() deals with the fact that the size can be the same. - - /* - * Various states we could be in... - - resize = state & eResizeRequested; - if (backbufferChanged) { - if (resize == 0) { - // ERROR, the resized buffer doesn't have its resize flag set - } else if (resize == mask) { - // ERROR one of the buffer has already been resized - } else if (resize == mask ^ eResizeRequested) { - // ERROR, the resized buffer doesn't have its resize flag set - } else if (resize == eResizeRequested) { - // OK, Normal case, proceed with resize - } - } else { - if (resize == 0) { - // OK, nothing special, do nothing - } else if (resize == mask) { - // restarted transaction, do nothing - } else if (resize == mask ^ eResizeRequested) { - // restarted transaction, do nothing - } else if (resize == eResizeRequested) { - // OK, size reset to previous value, proceed with resize - } - } - */ - // Index of the back buffer const bool backbufferChanged = (front.w != temp.w) || (front.h != temp.h); - const uint32_t state = lcblk->swapState; - const int32_t clientBackBufferIndex = layer_cblk_t::backBuffer(state); - const uint32_t mask = clientBackBufferIndex ? eResizeBuffer1 : eResizeBuffer0; - uint32_t resizeFlags = state & eResizeRequested; - - if (UNLIKELY(backbufferChanged && (resizeFlags != eResizeRequested))) { - LOGE( "backbuffer size changed, but both resize flags are not set! " - "(layer=%p), state=%08x, requested (%dx%d), drawing (%d,%d), " - "index=%d, (%dx%d), (%dx%d)", - this, state, - int(temp.w), int(temp.h), - int(drawingState().w), int(drawingState().h), - int(clientBackBufferIndex), - int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()), - int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight())); - // if we get there we're pretty screwed. the only reasonable - // thing to do is to pretend we should do the resize since - // backbufferChanged is set (this also will give a chance to - // client to get unblocked) - resizeFlags = eResizeRequested; - } - - if (resizeFlags == eResizeRequested) { - // NOTE: asserting that clientBackBufferIndex!=mFrontBufferIndex - // here, would be wrong and misleading because by this point - // mFrontBufferIndex has not been updated yet. + if (backbufferChanged) { + // the size changed, we need to ask our client to request a new buffer LOGD_IF(DEBUG_RESIZE, - "resize (layer=%p), state=%08x, " - "requested (%dx%d), " - "drawing (%d,%d), " - "index=%d, (%dx%d), (%dx%d)", - this, state, - int(temp.w), int(temp.h), + "resize (layer=%p), requested (%dx%d), " + "drawing (%d,%d), (%dx%d), (%dx%d)", + this, int(temp.w), int(temp.h), int(drawingState().w), int(drawingState().h), - int(clientBackBufferIndex), - int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()), - int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight())); - - if (state & eLocked) { - // if the buffer is locked, we can't resize anything because - // - the backbuffer is currently in use by the user - // - the front buffer is being shown - // We just act as if the transaction didn't happen and we - // reschedule it later... - flags |= eRestartTransaction; - } else { - // This buffer needs to be resized - status_t err = - resize(clientBackBufferIndex, temp.w, temp.h, "transaction"); - if (err == NO_ERROR) { - const uint32_t mask = clientBackBufferIndex ? - eResizeBuffer1 : eResizeBuffer0; - android_atomic_and(~mask, &(lcblk->swapState)); - // since a buffer became available, we can let the client go... - scheduleBroadcast(); - mResizeTransactionDone = true; - - // 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(); - } - } + int(mBuffers[0]->getWidth()), int(mBuffers[0]->getHeight()), + int(mBuffers[1]->getWidth()), int(mBuffers[1]->getHeight())); + + // record the new size, form this point on, when the client request a + // buffer, it'll get the new size. + setDrawingSize(temp.w, temp.h); + + // all buffers need reallocation + lcblk->reallocate(); + + // recompute the visible region + // FIXME: ideally we would do that only when we have received + // a buffer of the right size + flags |= Layer::eVisibleRegion; + this->contentDirty = true; + +#if 0 + // FIXME: handle freeze lock + // 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(); } } +#endif } - + 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 @@ -402,65 +317,10 @@ uint32_t Layer::doTransaction(uint32_t flags) return LayerBase::doTransaction(flags); } -status_t Layer::resize( - int32_t clientBackBufferIndex, - uint32_t width, uint32_t height, - const char* what) -{ - /* - * handle resize (backbuffer and frontbuffer reallocation) - * this is called from post() or from doTransaction() - */ - - const LayerBitmap& clientBackBuffer(mBuffers[clientBackBufferIndex]); - - // if the new (transaction) size is != from the the backbuffer - // then we need to reallocate the backbuffer - bool backbufferChanged = (clientBackBuffer.getWidth() != width) || - (clientBackBuffer.getHeight() != height); - - LOGD_IF(!backbufferChanged, - "(%s) eResizeRequested (layer=%p), but size not changed: " - "requested (%dx%d), drawing (%d,%d), current (%d,%d)," - "state=%08lx, index=%d, (%dx%d), (%dx%d)", - what, this, - int(width), int(height), - int(drawingState().w), int(drawingState().h), - int(currentState().w), int(currentState().h), - long(lcblk->swapState), - int(clientBackBufferIndex), - int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()), - int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight())); - - // this can happen when changing the size back and forth quickly - status_t err = NO_ERROR; - if (backbufferChanged) { - - LOGD_IF(DEBUG_RESIZE, - "resize (layer=%p), requested (%dx%d), " - "index=%d, (%dx%d), (%dx%d)", - this, int(width), int(height), int(clientBackBufferIndex), - int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()), - int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight())); - - err = mBuffers[clientBackBufferIndex].setSize(width, height); - if (UNLIKELY(err != NO_ERROR)) { - // This really should never happen - LOGE("resizing buffer %d to (%u,%u) failed [%08x] %s", - clientBackBufferIndex, width, height, err, strerror(err)); - // couldn't reallocate the surface - android_atomic_write(eInvalidSurface, &lcblk->swapState); - } - } - return err; -} - -void Layer::setSizeChanged(uint32_t w, uint32_t h) -{ - LOGD_IF(DEBUG_RESIZE, - "setSizeChanged w=%d, h=%d (old: w=%d, h=%d)", - w, h, mCurrentState.w, mCurrentState.h); - android_atomic_or(eResizeRequested, &(lcblk->swapState)); +void Layer::setDrawingSize(uint32_t w, uint32_t h) { + Mutex::Autolock _l(mLock); + mWidth = w; + mHeight = h; } // ---------------------------------------------------------------------------- @@ -469,139 +329,26 @@ void Layer::setSizeChanged(uint32_t w, uint32_t h) void Layer::lockPageFlip(bool& recomputeVisibleRegions) { - uint32_t state = android_atomic_or(eBusy, &(lcblk->swapState)); - // preemptively block the client, because he might set - // eFlipRequested at any time and want to use this buffer - // for the next frame. This will be unset below if it - // turns out we didn't need it. - - uint32_t mask = eInvalidSurface | eFlipRequested | eResizeRequested; - if (!(state & mask)) - return; - - if (UNLIKELY(state & eInvalidSurface)) { - // if eInvalidSurface is set, this means the surface - // became invalid during a transaction (NO_MEMORY for instance) - scheduleBroadcast(); + ssize_t buf = lcblk->retireAndLock(); + if (buf < NO_ERROR) { + //LOGW("nothing to retire (%s)", strerror(-buf)); + // NOTE: here the buffer is locked because we will used + // for composition later in the loop return; } - - if (UNLIKELY(state & eFlipRequested)) { - uint32_t oldState; - mPostedDirtyRegion = post(&oldState, recomputeVisibleRegions); - if (oldState & eNextFlipPending) { - // Process another round (we know at least a buffer - // is ready for that client). - mFlinger->signalEvent(); - } - } -} - -Region Layer::post(uint32_t* previousSate, bool& recomputeVisibleRegions) -{ - // atomically swap buffers and (re)set eFlipRequested - int32_t oldValue, newValue; - layer_cblk_t * const lcblk = this->lcblk; - do { - oldValue = lcblk->swapState; - // get the current value - - LOG_ASSERT(oldValue&eFlipRequested, - "eFlipRequested not set, yet we're flipping! (state=0x%08lx)", - long(oldValue)); - - newValue = (oldValue ^ eIndex); - // swap buffers - - newValue &= ~(eFlipRequested | eNextFlipPending); - // clear eFlipRequested and eNextFlipPending - - if (oldValue & eNextFlipPending) - newValue |= eFlipRequested; - // if eNextFlipPending is set (second buffer already has something - // in it) we need to reset eFlipRequested because the client - // might never do it - - } while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState))); - *previousSate = oldValue; - const int32_t index = (newValue & eIndex) ^ 1; - mFrontBufferIndex = index; + // we retired a buffer, which becomes the new front buffer + mFrontBufferIndex = buf; - /* NOTE: it's safe to set this flag here because this is only touched - * from LayerBitmap::allocate(), which by construction cannot happen - * while we're in post(). - */ - lcblk->surface[index].flags &= ~surface_info_t::eBufferDirty; - - // ... post the new front-buffer - Region dirty(lcblk->region + index); - dirty.andSelf(frontBuffer().getBounds()); - - //LOGD("Did post oldValue=%08lx, newValue=%08lx, mFrontBufferIndex=%u\n", - // oldValue, newValue, mFrontBufferIndex); - //dirty.dump("dirty"); + // get the dirty region + sp<Buffer> newFrontBuffer(getBuffer(buf)); + const Region dirty(lcblk->getDirtyRegion(buf)); + mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() ); - if (UNLIKELY(oldValue & eResizeRequested)) { - - LOGD_IF(DEBUG_RESIZE, - "post (layer=%p), state=%08x, " - "index=%d, (%dx%d), (%dx%d)", - this, newValue, - int(1-index), - int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()), - int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight())); - - // here, we just posted the surface and we have resolved - // the front/back buffer indices. The client is blocked, so - // it cannot start using the new backbuffer. - - // If the backbuffer was resized in THIS round, we actually cannot - // resize the frontbuffer because it has *just* been drawn (and we - // would have nothing to draw). In this case we just skip the resize - // it'll happen after the next page flip or during the next - // transaction. - - const uint32_t mask = (1-index) ? eResizeBuffer1 : eResizeBuffer0; - if (mResizeTransactionDone && (newValue & mask)) { - // Resize the layer's second buffer only if the transaction - // happened. It may not have happened yet if eResizeRequested - // was set immediately after the "transactionRequested" test, - // in which case the drawing state's size would be wrong. - mFreezeLock.clear(); - const Layer::State& s(drawingState()); - if (resize(1-index, s.w, s.h, "post") == NO_ERROR) { - do { - oldValue = lcblk->swapState; - if ((oldValue & eResizeRequested) == eResizeRequested) { - // ugh, another resize was requested since we processed - // the first buffer, don't free the client, and let - // the next transaction handle everything. - break; - } - newValue = oldValue & ~mask; - } while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState))); - } - mResizeTransactionDone = false; - recomputeVisibleRegions = true; - this->contentDirty = true; - } - } + // FIXME: signal an event if we have more buffers waiting + // mFlinger->signalEvent(); - reloadTexture(dirty); - - return dirty; -} - -Point Layer::getPhysicalSize() const -{ - sp<const Buffer> front(frontBuffer().getBuffer()); - Point size(front->getWidth(), front->getHeight()); - if ((size.x | size.y) == 0) { - // if we don't have a buffer yet, just use the state's size. - size = LayerBase::getPhysicalSize(); - } - return size; + reloadTexture( mPostedDirtyRegion ); } void Layer::unlockPageFlip( @@ -622,21 +369,15 @@ void Layer::unlockPageFlip( // is in screen space as well). dirtyRegion.andSelf(visibleRegionScreen); outDirtyRegion.orSelf(dirtyRegion); - - // client could be blocked, so signal them so they get a - // chance to reevaluate their condition. - scheduleBroadcast(); } } void Layer::finishPageFlip() { - if (LIKELY(!(lcblk->swapState & eInvalidSurface))) { - LOGE_IF(!(lcblk->swapState & eBusy), - "layer %p wasn't locked!", this); - android_atomic_and(~eBusy, &(lcblk->swapState)); - } - scheduleBroadcast(); + status_t err = lcblk->unlock( mFrontBufferIndex ); + LOGE_IF(err!=NO_ERROR, + "layer %p, buffer=%d wasn't locked!", + this, mFrontBufferIndex); } // --------------------------------------------------------------------------- @@ -651,12 +392,16 @@ Layer::SurfaceLayer::~SurfaceLayer() { } -sp<SurfaceBuffer> Layer::SurfaceLayer::getBuffer(int usage) +sp<SurfaceBuffer> Layer::SurfaceLayer::requestBuffer(int index, int usage) { - sp<SurfaceBuffer> buffer = 0; + sp<SurfaceBuffer> buffer; sp<Layer> owner(getOwner()); if (owner != 0) { - buffer = owner->peekBuffer(usage); + LOGE_IF(uint32_t(index)>=NUM_BUFFERS, + "getBuffer() index (%d) out of range", index); + if (uint32_t(index) < NUM_BUFFERS) { + buffer = owner->requestBuffer(index, usage); + } } return buffer; } diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h index add5d50..3b4489e 100644 --- a/libs/surfaceflinger/Layer.h +++ b/libs/surfaceflinger/Layer.h @@ -21,10 +21,6 @@ #include <sys/types.h> #include <ui/PixelFormat.h> - -#include <private/ui/SharedState.h> -#include <private/ui/LayerState.h> - #include <pixelflinger/pixelflinger.h> #include <EGL/egl.h> @@ -32,7 +28,7 @@ #include <GLES/gl.h> #include <GLES/glext.h> -#include "LayerBitmap.h" +#include "Buffer.h" #include "LayerBase.h" #include "Transform.h" @@ -41,12 +37,12 @@ namespace android { // --------------------------------------------------------------------------- class Client; -class LayerBitmap; class FreezeLock; +class Buffer; // --------------------------------------------------------------------------- -const int NUM_BUFFERS = 2; +const size_t NUM_BUFFERS = 2; class Layer : public LayerBaseClient { @@ -56,23 +52,22 @@ public: virtual char const* getTypeID() const { return typeID; } virtual uint32_t getTypeInfo() const { return typeInfo; } + + SharedBufferServer* lcblk; + + Layer(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& client, int32_t i); virtual ~Layer(); - inline PixelFormat pixelFormat() const { - return frontBuffer().getPixelFormat(); - } + status_t setBuffers(uint32_t w, uint32_t h, + PixelFormat format, uint32_t flags=0); - status_t setBuffers( uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags=0); + void setDrawingSize(uint32_t w, uint32_t h); virtual void onDraw(const Region& clip) const; - virtual void initStates(uint32_t w, uint32_t h, uint32_t flags); - virtual void setSizeChanged(uint32_t w, uint32_t h); virtual uint32_t doTransaction(uint32_t transactionFlags); - virtual Point getPhysicalSize() const; virtual void lockPageFlip(bool& recomputeVisibleRegions); virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); virtual void finishPageFlip(); @@ -80,42 +75,31 @@ public: virtual bool isSecure() const { return mSecure; } virtual sp<Surface> createSurface() const; virtual status_t ditch(); - - const LayerBitmap& getBuffer(int i) const { return mBuffers[i]; } - LayerBitmap& getBuffer(int i) { return mBuffers[i]; } - + // only for debugging - const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; } + inline sp<Buffer> getBuffer(int i) { return mBuffers[i]; } + // only for debugging + inline const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; } + // only for debugging + inline PixelFormat pixelFormat() const { return mFormat; } private: - inline const LayerBitmap& - frontBuffer() const { return getBuffer(mFrontBufferIndex); } - inline LayerBitmap& - frontBuffer() { return getBuffer(mFrontBufferIndex); } - inline const LayerBitmap& - backBuffer() const { return getBuffer(1-mFrontBufferIndex); } - inline LayerBitmap& - backBuffer() { return getBuffer(1-mFrontBufferIndex); } - + inline sp<Buffer> getFrontBuffer() { + return mBuffers[mFrontBufferIndex]; + } + void reloadTexture(const Region& dirty); - status_t resize(int32_t index, uint32_t w, uint32_t h, const char* what); - Region post(uint32_t* oldState, bool& recomputeVisibleRegions); - sp<SurfaceBuffer> peekBuffer(int usage); + sp<SurfaceBuffer> requestBuffer(int index, int usage); void destroy(); - void scheduleBroadcast(); - - class SurfaceLayer : public LayerBaseClient::Surface - { + class SurfaceLayer : public LayerBaseClient::Surface { public: - SurfaceLayer(const sp<SurfaceFlinger>& flinger, - SurfaceID id, const sp<Layer>& owner); - ~SurfaceLayer(); - + SurfaceLayer(const sp<SurfaceFlinger>& flinger, + SurfaceID id, const sp<Layer>& owner); + ~SurfaceLayer(); private: - virtual sp<SurfaceBuffer> getBuffer(int usage); - + virtual sp<SurfaceBuffer> requestBuffer(int index, int usage); sp<Layer> getOwner() const { return static_cast<Layer*>(Surface::getOwner().get()); } @@ -125,13 +109,20 @@ private: sp<Surface> mSurface; bool mSecure; - LayerBitmap mBuffers[NUM_BUFFERS]; - Texture mTextures[NUM_BUFFERS]; int32_t mFrontBufferIndex; bool mNeedsBlending; - bool mResizeTransactionDone; Region mPostedDirtyRegion; sp<FreezeLock> mFreezeLock; + PixelFormat mFormat; + uint32_t mBufferFlags; + + // protected by mLock + sp<Buffer> mBuffers[NUM_BUFFERS]; + Texture mTextures[NUM_BUFFERS]; + uint32_t mWidth; + uint32_t mHeight; + + mutable Mutex mLock; }; // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp index ec38fe9..62e41b0 100644 --- a/libs/surfaceflinger/LayerBase.cpp +++ b/libs/surfaceflinger/LayerBase.cpp @@ -30,7 +30,6 @@ #include "clz.h" #include "LayerBase.h" -#include "LayerBlur.h" #include "SurfaceFlinger.h" #include "DisplayHardware/DisplayHardware.h" @@ -127,9 +126,6 @@ uint32_t LayerBase::setTransactionFlags(uint32_t flags) { return android_atomic_or(flags, &mTransactionFlags); } -void LayerBase::setSizeChanged(uint32_t w, uint32_t h) { -} - bool LayerBase::setPosition(int32_t x, int32_t y) { if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y) return false; @@ -149,7 +145,6 @@ bool LayerBase::setLayer(uint32_t z) { bool LayerBase::setSize(uint32_t w, uint32_t h) { if (mCurrentState.w == w && mCurrentState.h == h) return false; - setSizeChanged(w, h); mCurrentState.w = w; mCurrentState.h = h; requestTransaction(); @@ -219,21 +214,14 @@ uint32_t LayerBase::doTransaction(uint32_t flags) return flags; } -Point LayerBase::getPhysicalSize() const -{ - const Layer::State& front(drawingState()); - return Point(front.w, front.h); -} - void LayerBase::validateVisibility(const Transform& planeTransform) { const Layer::State& s(drawingState()); const Transform tr(planeTransform * s.transform); const bool transformed = tr.transformed(); - const Point size(getPhysicalSize()); - uint32_t w = size.x; - uint32_t h = size.y; + uint32_t w = s.w; + uint32_t h = s.h; tr.transform(mVertices[0], 0, 0); tr.transform(mVertices[1], 0, h); tr.transform(mVertices[2], w, h); @@ -655,9 +643,7 @@ int32_t LayerBaseClient::sIdentity = 0; LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& client, int32_t i) : LayerBase(flinger, display), client(client), - lcblk( client!=0 ? &(client->ctrlblk->layers[i]) : 0 ), - mIndex(i), - mIdentity(uint32_t(android_atomic_inc(&sIdentity))) + mIndex(i), mIdentity(uint32_t(android_atomic_inc(&sIdentity))) { } @@ -666,11 +652,8 @@ void LayerBaseClient::onFirstRef() sp<Client> client(this->client.promote()); if (client != 0) { client->bindLayer(this, mIndex); - // Initialize this layer's control block - memset(this->lcblk, 0, sizeof(layer_cblk_t)); - this->lcblk->identity = mIdentity; - Region::writeEmpty(&(this->lcblk->region[0]), sizeof(flat_region_t)); - Region::writeEmpty(&(this->lcblk->region[1]), sizeof(flat_region_t)); + // Initialize this layer's identity + client->ctrlblk->setIdentity(mIndex, mIdentity); } } @@ -759,7 +742,7 @@ status_t LayerBaseClient::Surface::onTransact( return BnSurface::onTransact(code, data, reply, flags); } -sp<SurfaceBuffer> LayerBaseClient::Surface::getBuffer(int) +sp<SurfaceBuffer> LayerBaseClient::Surface::requestBuffer(int index, int usage) { return NULL; } diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h index 2168de0..78bb4bf 100644 --- a/libs/surfaceflinger/LayerBase.h +++ b/libs/surfaceflinger/LayerBase.h @@ -23,6 +23,7 @@ #include <EGL/egl.h> #include <EGL/eglext.h> +#include <private/ui/SharedBufferStack.h> #include <private/ui/LayerState.h> #include <utils/RefBase.h> @@ -137,11 +138,6 @@ public: virtual void initStates(uint32_t w, uint32_t h, uint32_t flags); /** - * setSizeChanged - called when the *current* state's size is changed. - */ - virtual void setSizeChanged(uint32_t w, uint32_t h); - - /** * doTransaction - process the transaction. This is a good place to figure * out which attributes of the surface have changed. */ @@ -161,13 +157,6 @@ public: virtual void setCoveredRegion(const Region& coveredRegion); /** - * getPhysicalSize - returns the physical size of the drawing state of - * the surface. If the surface is backed by a bitmap, this is the size of - * the bitmap (as opposed to the size of the drawing state). - */ - virtual Point getPhysicalSize() const; - - /** * validateVisibility - cache a bunch of things */ virtual void validateVisibility(const Transform& globalTransform); @@ -308,8 +297,8 @@ public: virtual ~LayerBaseClient(); virtual void onFirstRef(); - wp<Client> client; - layer_cblk_t* const lcblk; + wp<Client> client; +// SharedBufferServer* lcblk; inline uint32_t getIdentity() const { return mIdentity; } inline int32_t clientIndex() const { return mIndex; } @@ -336,7 +325,7 @@ public: sp<LayerBaseClient> getOwner() const; private: - virtual sp<SurfaceBuffer> getBuffer(int usage); + virtual sp<SurfaceBuffer> requestBuffer(int index, int usage); virtual status_t registerBuffers(const ISurface::BufferHeap& buffers); virtual void postBuffer(ssize_t offset); virtual void unregisterBuffers(); diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp index 8a55a3f..433b48e 100644 --- a/libs/surfaceflinger/LayerBuffer.cpp +++ b/libs/surfaceflinger/LayerBuffer.cpp @@ -28,6 +28,7 @@ #include <hardware/copybit.h> +#include "Buffer.h" #include "BufferAllocator.h" #include "LayerBuffer.h" #include "SurfaceFlinger.h" @@ -58,7 +59,7 @@ LayerBuffer::~LayerBuffer() void LayerBuffer::onFirstRef() { LayerBaseClient::onFirstRef(); - mSurface = new SurfaceBuffer(mFlinger, clientIndex(), + mSurface = new SurfaceLayerBuffer(mFlinger, clientIndex(), const_cast<LayerBuffer *>(this)); } @@ -181,21 +182,21 @@ sp<LayerBuffer::Source> LayerBuffer::clearSource() { } // ============================================================================ -// LayerBuffer::SurfaceBuffer +// LayerBuffer::SurfaceLayerBuffer // ============================================================================ -LayerBuffer::SurfaceBuffer::SurfaceBuffer(const sp<SurfaceFlinger>& flinger, +LayerBuffer::SurfaceLayerBuffer::SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger, SurfaceID id, const sp<LayerBuffer>& owner) : LayerBaseClient::Surface(flinger, id, owner->getIdentity(), owner) { } -LayerBuffer::SurfaceBuffer::~SurfaceBuffer() +LayerBuffer::SurfaceLayerBuffer::~SurfaceLayerBuffer() { unregisterBuffers(); } -status_t LayerBuffer::SurfaceBuffer::registerBuffers( +status_t LayerBuffer::SurfaceLayerBuffer::registerBuffers( const ISurface::BufferHeap& buffers) { sp<LayerBuffer> owner(getOwner()); @@ -204,21 +205,21 @@ status_t LayerBuffer::SurfaceBuffer::registerBuffers( return NO_INIT; } -void LayerBuffer::SurfaceBuffer::postBuffer(ssize_t offset) +void LayerBuffer::SurfaceLayerBuffer::postBuffer(ssize_t offset) { sp<LayerBuffer> owner(getOwner()); if (owner != 0) owner->postBuffer(offset); } -void LayerBuffer::SurfaceBuffer::unregisterBuffers() +void LayerBuffer::SurfaceLayerBuffer::unregisterBuffers() { sp<LayerBuffer> owner(getOwner()); if (owner != 0) owner->unregisterBuffers(); } -sp<OverlayRef> LayerBuffer::SurfaceBuffer::createOverlay( +sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::createOverlay( uint32_t w, uint32_t h, int32_t format) { sp<OverlayRef> result; sp<LayerBuffer> owner(getOwner()); @@ -462,8 +463,8 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const const int tmp_h = floorf(src_height * yscale); if (mTempBitmap==0 || - mTempBitmap->getWidth() < tmp_w || - mTempBitmap->getHeight() < tmp_h) { + mTempBitmap->getWidth() < size_t(tmp_w) || + mTempBitmap->getHeight() < size_t(tmp_h)) { mTempBitmap.clear(); mTempBitmap = new android::Buffer( tmp_w, tmp_h, src.img.format, diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h index 8057219..e539f68 100644 --- a/libs/surfaceflinger/LayerBuffer.h +++ b/libs/surfaceflinger/LayerBuffer.h @@ -24,7 +24,6 @@ #include <private/ui/LayerState.h> #include "LayerBase.h" -#include "LayerBitmap.h" struct copybit_device_t; @@ -32,9 +31,12 @@ namespace android { // --------------------------------------------------------------------------- +class Buffer; class Region; class OverlayRef; +// --------------------------------------------------------------------------- + class LayerBuffer : public LayerBaseClient { class Source : public LightRefBase<Source> { @@ -179,12 +181,12 @@ private: }; - class SurfaceBuffer : public LayerBaseClient::Surface + class SurfaceLayerBuffer : public LayerBaseClient::Surface { public: - SurfaceBuffer(const sp<SurfaceFlinger>& flinger, + SurfaceLayerBuffer(const sp<SurfaceFlinger>& flinger, SurfaceID id, const sp<LayerBuffer>& owner); - virtual ~SurfaceBuffer(); + virtual ~SurfaceLayerBuffer(); virtual status_t registerBuffers(const ISurface::BufferHeap& buffers); virtual void postBuffer(ssize_t offset); diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp index f613767..8ba0a9d 100644 --- a/libs/surfaceflinger/LayerDim.cpp +++ b/libs/surfaceflinger/LayerDim.cpp @@ -21,6 +21,7 @@ #include <utils/Errors.h> #include <utils/Log.h> +#include "Buffer.h" #include "BufferAllocator.h" #include "LayerDim.h" #include "SurfaceFlinger.h" diff --git a/libs/surfaceflinger/LayerDim.h b/libs/surfaceflinger/LayerDim.h index 33bd49d..d4672a1 100644 --- a/libs/surfaceflinger/LayerDim.h +++ b/libs/surfaceflinger/LayerDim.h @@ -24,12 +24,11 @@ #include <EGL/eglext.h> #include "LayerBase.h" -#include "LayerBitmap.h" - -namespace android { // --------------------------------------------------------------------------- +namespace android { + class LayerDim : public LayerBaseClient { static bool sUseTexture; diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp index c78921a..b368db6 100644 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ b/libs/surfaceflinger/SurfaceFlinger.cpp @@ -44,12 +44,12 @@ #include <GLES/gl.h> #include "clz.h" +#include "Buffer.h" #include "BufferAllocator.h" #include "Layer.h" #include "LayerBlur.h" #include "LayerBuffer.h" #include "LayerDim.h" -#include "LayerBitmap.h" #include "SurfaceFlinger.h" #include "DisplayHardware/DisplayHardware.h" @@ -173,12 +173,12 @@ SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), Thread(false), mTransactionFlags(0), mTransactionCount(0), + mResizeTransationPending(false), mLayersRemoved(false), mBootTime(systemTime()), mHardwareTest("android.permission.HARDWARE_TEST"), mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"), mDump("android.permission.DUMP"), - mLastScheduledBroadcast(NULL), mVisibleRegionsDirty(false), mDeferReleaseConsole(false), mFreezeDisplay(false), @@ -497,13 +497,11 @@ bool SurfaceFlinger::threadLoop() // release the clients before we flip ('cause flip might block) unlockClients(); - executeScheduledBroadcasts(); postFramebuffer(); } else { // pretend we did the post unlockClients(); - executeScheduledBroadcasts(); usleep(16667); // 60 fps period } return true; @@ -773,7 +771,8 @@ void SurfaceFlinger::computeVisibleRegions( void SurfaceFlinger::commitTransaction() { mDrawingState = mCurrentState; - mTransactionCV.signal(); + mResizeTransationPending = false; + mTransactionCV.broadcast(); } void SurfaceFlinger::handlePageFlip() @@ -910,37 +909,6 @@ void SurfaceFlinger::unlockClients() } } -void SurfaceFlinger::scheduleBroadcast(const sp<Client>& client) -{ - if (mLastScheduledBroadcast != client) { - mLastScheduledBroadcast = client; - mScheduledBroadcasts.add(client); - } -} - -void SurfaceFlinger::executeScheduledBroadcasts() -{ - SortedVector< wp<Client> >& list(mScheduledBroadcasts); - size_t count = list.size(); - while (count--) { - sp<Client> client = list[count].promote(); - if (client != 0) { - per_client_cblk_t* const cblk = client->ctrlblk; - if (cblk->lock.tryLock() == NO_ERROR) { - cblk->cv.broadcast(); - list.removeAt(count); - cblk->lock.unlock(); - } else { - // schedule another round - LOGW("executeScheduledBroadcasts() skipped, " - "contention on the client. We'll try again later..."); - signalDelayedEvent(ms2ns(4)); - } - } - } - mLastScheduledBroadcast = 0; -} - void SurfaceFlinger::debugFlashRegions() { const DisplayHardware& hw(graphicPlane(0).displayHardware()); @@ -1129,18 +1097,10 @@ void SurfaceFlinger::free_resources_l() mLayersRemoved = false; // free resources associated with disconnected clients - SortedVector< wp<Client> >& scheduledBroadcasts(mScheduledBroadcasts); Vector< sp<Client> >& disconnectedClients(mDisconnectedClients); const size_t count = disconnectedClients.size(); for (size_t i=0 ; i<count ; i++) { sp<Client> client = disconnectedClients[i]; - // if this client is the scheduled broadcast list, - // remove it from there (and we don't need to signal it - // since it is dead). - int32_t index = scheduledBroadcasts.indexOf(client); - if (index >= 0) { - scheduledBroadcasts.removeItemsAt(index); - } mTokens.release(client->cid); } disconnectedClients.clear(); @@ -1173,6 +1133,13 @@ void SurfaceFlinger::closeGlobalTransaction() { if (android_atomic_dec(&mTransactionCount) == 1) { signalEvent(); + + // if there is a transaction with a resize, wait for it to + // take effect before returning. + Mutex::Autolock _l(mStateLock); + while (mResizeTransationPending) { + mTransactionCV.wait(mStateLock); + } } } @@ -1424,8 +1391,10 @@ status_t SurfaceFlinger::setClientState( } } if (what & eSizeChanged) { - if (layer->setSize(s.w, s.h)) + if (layer->setSize(s.w, s.h)) { flags |= eTraversalNeeded; + mResizeTransationPending = true; + } } if (what & eAlphaChanged) { if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f))) @@ -1543,28 +1512,27 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) "id=0x%08x, client=0x%08x, identity=%u\n", lbc->clientIndex(), client.get() ? client->cid : 0, lbc->getIdentity()); + + result.append(buffer); + buffer[0] = 0; } - result.append(buffer); - buffer[0] = 0; /*** Layer ***/ sp<Layer> l = LayerBase::dynamicCast< Layer* >(layer.get()); if (l != 0) { - const LayerBitmap& buf0(l->getBuffer(0)); - const LayerBitmap& buf1(l->getBuffer(1)); + result.append( l->lcblk->dump(" ") ); + sp<const Buffer> buf0(l->getBuffer(0)); + sp<const Buffer> buf1(l->getBuffer(1)); snprintf(buffer, SIZE, " " "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u]," - " freezeLock=%p, swapState=0x%08x\n", + " freezeLock=%p\n", l->pixelFormat(), - buf0.getWidth(), buf0.getHeight(), - buf0.getBuffer()->getStride(), - buf1.getWidth(), buf1.getHeight(), - buf1.getBuffer()->getStride(), - l->getFreezeLock().get(), - l->lcblk->swapState); + buf0->getWidth(), buf0->getHeight(), buf0->getStride(), + buf1->getWidth(), buf1->getHeight(), buf1->getStride(), + l->getFreezeLock().get()); + result.append(buffer); + buffer[0] = 0; } - result.append(buffer); - buffer[0] = 0; s.transparentRegion.dump(result, "transparentRegion"); layer->transparentRegionScreen.dump(result, "transparentRegionScreen"); layer->visibleRegionScreen.dump(result, "visibleRegionScreen"); @@ -1657,8 +1625,12 @@ status_t SurfaceFlinger::onTransact( const DisplayHardware& hw(graphicPlane(0).displayHardware()); mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe signalEvent(); + return NO_ERROR; + } + case 1005:{ // force transaction + setTransactionFlags(eTransactionNeeded|eTraversalNeeded); + return NO_ERROR; } - return NO_ERROR; case 1007: // set mFreezeCount mFreezeCount = data.readInt32(); return NO_ERROR; @@ -1688,21 +1660,20 @@ Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger) : ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger) { const int pgsize = getpagesize(); - const int cblksize = ((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1)); + const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1)); mCblkHeap = new MemoryHeapBase(cblksize, 0, "SurfaceFlinger Client control-block"); - ctrlblk = static_cast<per_client_cblk_t *>(mCblkHeap->getBase()); + ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase()); if (ctrlblk) { // construct the shared structure in-place. - new(ctrlblk) per_client_cblk_t; + new(ctrlblk) SharedClient; } } Client::~Client() { if (ctrlblk) { - const int pgsize = getpagesize(); - ctrlblk->~per_client_cblk_t(); // destroy our shared-structure. + ctrlblk->~SharedClient(); // destroy our shared-structure. } } diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h index 69e2f2e..f207f85 100644 --- a/libs/surfaceflinger/SurfaceFlinger.h +++ b/libs/surfaceflinger/SurfaceFlinger.h @@ -34,7 +34,7 @@ #include <ui/ISurfaceComposer.h> #include <ui/ISurfaceFlingerClient.h> -#include <private/ui/SharedState.h> +#include <private/ui/SharedBufferStack.h> #include <private/ui/LayerState.h> #include "Barrier.h" @@ -87,7 +87,7 @@ public: } // pointer to this client's control block - per_client_cblk_t* ctrlblk; + SharedClient* ctrlblk; ClientID cid; @@ -268,8 +268,6 @@ private: bool lockPageFlip(const LayerVector& currentLayers); void unlockPageFlip(const LayerVector& currentLayers); void handleRepaint(); - void scheduleBroadcast(const sp<Client>& client); - void executeScheduledBroadcasts(); void postFramebuffer(); void composeSurfaces(const Region& dirty); void unlockClients(); @@ -313,6 +311,7 @@ private: volatile int32_t mTransactionFlags; volatile int32_t mTransactionCount; Condition mTransactionCV; + bool mResizeTransationPending; // protected by mStateLock (but we could use another lock) Tokenizer mTokens; @@ -337,8 +336,6 @@ private: Region mDirtyRegionRemovedLayer; Region mInvalidRegion; Region mWormholeRegion; - wp<Client> mLastScheduledBroadcast; - SortedVector< wp<Client> > mScheduledBroadcasts; bool mVisibleRegionsDirty; bool mDeferReleaseConsole; bool mFreezeDisplay; diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk index 93c7263..348dd68 100644 --- a/libs/ui/Android.mk +++ b/libs/ui/Android.mk @@ -23,7 +23,9 @@ LOCAL_SRC_FILES:= \ PixelFormat.cpp \ Rect.cpp \ Region.cpp \ + SharedBufferStack.cpp \ Surface.cpp \ + SurfaceBuffer.cpp \ SurfaceComposerClient.cpp \ SurfaceFlingerSynchro.cpp diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp index b78e8b5..a2dbe7f 100644 --- a/libs/ui/ISurface.cpp +++ b/libs/ui/ISurface.cpp @@ -71,12 +71,13 @@ public: { } - virtual sp<SurfaceBuffer> getBuffer(int usage) + virtual sp<SurfaceBuffer> requestBuffer(int bufferIdx, int usage) { Parcel data, reply; data.writeInterfaceToken(ISurface::getInterfaceDescriptor()); + data.writeInt32(bufferIdx); data.writeInt32(usage); - remote()->transact(GET_BUFFER, data, &reply); + remote()->transact(REQUEST_BUFFER, data, &reply); sp<SurfaceBuffer> buffer = new SurfaceBuffer(reply); return buffer; } @@ -134,10 +135,11 @@ status_t BnSurface::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { - case GET_BUFFER: { + case REQUEST_BUFFER: { CHECK_INTERFACE(ISurface, data, reply); + int bufferIdx = data.readInt32(); int usage = data.readInt32(); - sp<SurfaceBuffer> buffer(getBuffer(usage)); + sp<SurfaceBuffer> buffer(requestBuffer(bufferIdx, usage)); return SurfaceBuffer::writeToParcel(reply, buffer.get()); } case REGISTER_BUFFERS: { diff --git a/libs/ui/SharedBufferStack.cpp b/libs/ui/SharedBufferStack.cpp new file mode 100644 index 0000000..5995af5 --- /dev/null +++ b/libs/ui/SharedBufferStack.cpp @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2007 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. + */ + +#define LOG_TAG "SharedBufferStack" + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Debug.h> +#include <utils/Log.h> +#include <utils/threads.h> + +#include <private/ui/SharedBufferStack.h> + +#include <ui/Rect.h> +#include <ui/Region.h> + +#define DEBUG_ATOMICS 0 + +namespace android { +// ---------------------------------------------------------------------------- + +SharedClient::SharedClient() + : lock(Mutex::SHARED) +{ +} + +SharedClient::~SharedClient() { +} + + +// these functions are used by the clients +status_t SharedClient::validate(size_t i) const { + if (uint32_t(i) >= uint32_t(NUM_LAYERS_MAX)) + return BAD_INDEX; + return surfaces[i].status; +} + +uint32_t SharedClient::getIdentity(size_t token) const { + return uint32_t(surfaces[token].identity); +} + +status_t SharedClient::setIdentity(size_t token, uint32_t identity) { + if (token >= NUM_LAYERS_MAX) + return BAD_INDEX; + surfaces[token].identity = identity; + return NO_ERROR; +} + +// ---------------------------------------------------------------------------- + + +SharedBufferStack::SharedBufferStack() + : inUse(-1), identity(-1), status(NO_ERROR) +{ +} + +status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty) +{ + if (uint32_t(buffer) >= NUM_BUFFER_MAX) + return BAD_INDEX; + + // in the current implementation we only send a single rectangle + const Rect bounds(dirty.getBounds()); + FlatRegion& reg(dirtyRegion[buffer]); + reg.count = 1; + reg.rects[0] = uint16_t(bounds.left); + reg.rects[1] = uint16_t(bounds.top); + reg.rects[2] = uint16_t(bounds.right); + reg.rects[3] = uint16_t(bounds.bottom); + return NO_ERROR; +} + +Region SharedBufferStack::getDirtyRegion(int buffer) const +{ + Region res; + if (uint32_t(buffer) >= NUM_BUFFER_MAX) + return res; + + const FlatRegion& reg(dirtyRegion[buffer]); + res.set(Rect(reg.rects[0], reg.rects[1], reg.rects[2], reg.rects[3])); + return res; +} + +// ---------------------------------------------------------------------------- + +SharedBufferBase::SharedBufferBase(SharedClient* sharedClient, + int surface, int num) + : mSharedClient(sharedClient), + mSharedStack(sharedClient->surfaces + surface), + mNumBuffers(num) +{ +} + +SharedBufferBase::~SharedBufferBase() +{ +} + +uint32_t SharedBufferBase::getIdentity() +{ + SharedBufferStack& stack( *mSharedStack ); + return stack.identity; +} + +size_t SharedBufferBase::getFrontBuffer() const +{ + SharedBufferStack& stack( *mSharedStack ); + return size_t( stack.head ); +} + +String8 SharedBufferBase::dump(char const* prefix) const +{ + const size_t SIZE = 1024; + char buffer[SIZE]; + String8 result; + SharedBufferStack& stack( *mSharedStack ); + snprintf(buffer, SIZE, + "%s[ head=%2d, available=%2d, queued=%2d ] " + "reallocMask=%08x, inUse=%2d, identity=%d, status=%d\n", + prefix, stack.head, stack.available, stack.queued, + stack.reallocMask, stack.inUse, stack.identity, stack.status); + result.append(buffer); + return result; +} + + +// ============================================================================ +// conditions and updates +// ============================================================================ + +SharedBufferClient::DequeueCondition::DequeueCondition( + SharedBufferClient* sbc) : ConditionBase(sbc) { +} +bool SharedBufferClient::DequeueCondition::operator()() { + return stack.available > 0; +} + +SharedBufferClient::LockCondition::LockCondition( + SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) { +} +bool SharedBufferClient::LockCondition::operator()() { + return (buf != stack.head || + (stack.queued > 0 && stack.inUse != buf)); +} + +SharedBufferServer::ReallocateCondition::ReallocateCondition( + SharedBufferBase* sbb, int buf) : ConditionBase(sbb), buf(buf) { +} +bool SharedBufferServer::ReallocateCondition::operator()() { + // TODO: we should also check that buf has been dequeued + return (buf != stack.head); +} + +// ---------------------------------------------------------------------------- + +SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb) + : UpdateBase(sbb) { +} +ssize_t SharedBufferClient::QueueUpdate::operator()() { + android_atomic_inc(&stack.queued); + return NO_ERROR; +} + +SharedBufferClient::UndoDequeueUpdate::UndoDequeueUpdate(SharedBufferBase* sbb) + : UpdateBase(sbb) { +} +ssize_t SharedBufferClient::UndoDequeueUpdate::operator()() { + android_atomic_inc(&stack.available); + return NO_ERROR; +} + +SharedBufferServer::UnlockUpdate::UnlockUpdate( + SharedBufferBase* sbb, int lockedBuffer) + : UpdateBase(sbb), lockedBuffer(lockedBuffer) { +} +ssize_t SharedBufferServer::UnlockUpdate::operator()() { + if (stack.inUse != lockedBuffer) { + LOGE("unlocking %d, but currently locked buffer is %d", + lockedBuffer, stack.inUse); + return BAD_VALUE; + } + android_atomic_write(-1, &stack.inUse); + return NO_ERROR; +} + +SharedBufferServer::RetireUpdate::RetireUpdate( + SharedBufferBase* sbb, int numBuffers) + : UpdateBase(sbb), numBuffers(numBuffers) { +} +ssize_t SharedBufferServer::RetireUpdate::operator()() { + // head is only written in this function, which is single-thread. + int32_t head = stack.head; + + // Preventively lock the current buffer before updating queued. + android_atomic_write(head, &stack.inUse); + + // Decrement the number of queued buffers + int32_t queued; + do { + queued = stack.queued; + if (queued == 0) { + return NOT_ENOUGH_DATA; + } + } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued)); + + // update the head pointer + head = ((head+1 >= numBuffers) ? 0 : head+1); + + // lock the buffer before advancing head, which automatically unlocks + // the buffer we preventively locked upon entering this function + android_atomic_write(head, &stack.inUse); + + // advance head + android_atomic_write(head, &stack.head); + + // now that head has moved, we can increment the number of available buffers + android_atomic_inc(&stack.available); + return head; +} + +// ============================================================================ + +SharedBufferClient::SharedBufferClient(SharedClient* sharedClient, + int surface, int num) + : SharedBufferBase(sharedClient, surface, num), tail(0) +{ +} + +ssize_t SharedBufferClient::dequeue() +{ + //LOGD("[%d] about to dequeue a buffer", + // mSharedStack->identity); + DequeueCondition condition(this); + status_t err = waitForCondition(condition); + if (err != NO_ERROR) + return ssize_t(err); + + + SharedBufferStack& stack( *mSharedStack ); + // NOTE: 'stack.available' is part of the conditions, however + // decrementing it, never changes any conditions, so we don't need + // to do this as part of an update. + if (android_atomic_dec(&stack.available) == 0) { + LOGW("dequeue probably called from multiple threads!"); + } + + int dequeued = tail; + tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1); + LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail=%d, %s", + dequeued, tail, dump("").string()); + return dequeued; +} + +status_t SharedBufferClient::undoDequeue(int buf) +{ + UndoDequeueUpdate update(this); + status_t err = updateCondition( update ); + return err; +} + +status_t SharedBufferClient::lock(int buf) +{ + LockCondition condition(this, buf); + status_t err = waitForCondition(condition); + return err; +} + +status_t SharedBufferClient::queue(int buf) +{ + QueueUpdate update(this); + status_t err = updateCondition( update ); + LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string()); + return err; +} + +bool SharedBufferClient::needNewBuffer(int buffer) const +{ + SharedBufferStack& stack( *mSharedStack ); + const uint32_t mask = 1<<buffer; + return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0; +} + +status_t SharedBufferClient::setDirtyRegion(int buffer, const Region& reg) +{ + SharedBufferStack& stack( *mSharedStack ); + return stack.setDirtyRegion(buffer, reg); +} + +// ---------------------------------------------------------------------------- + +SharedBufferServer::SharedBufferServer(SharedClient* sharedClient, + int surface, int num) + : SharedBufferBase(sharedClient, surface, num) +{ + mSharedStack->head = num-1; + mSharedStack->available = num; + mSharedStack->queued = 0; + mSharedStack->reallocMask = 0; + memset(mSharedStack->dirtyRegion, 0, sizeof(mSharedStack->dirtyRegion)); +} + +ssize_t SharedBufferServer::retireAndLock() +{ + RetireUpdate update(this, mNumBuffers); + ssize_t buf = updateCondition( update ); + LOGD_IF(DEBUG_ATOMICS, "retire=%d, %s", int(buf), dump("").string()); + return buf; +} + +status_t SharedBufferServer::unlock(int buffer) +{ + UnlockUpdate update(this, buffer); + status_t err = updateCondition( update ); + return err; +} + +status_t SharedBufferServer::reallocate() +{ + SharedBufferStack& stack( *mSharedStack ); + uint32_t mask = (1<<mNumBuffers)-1; + android_atomic_or(mask, &stack.reallocMask); + return NO_ERROR; +} + +status_t SharedBufferServer::assertReallocate(int buffer) +{ + ReallocateCondition condition(this, buffer); + status_t err = waitForCondition(condition); + return err; +} + +Region SharedBufferServer::getDirtyRegion(int buffer) const +{ + SharedBufferStack& stack( *mSharedStack ); + return stack.getDirtyRegion(buffer); +} + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp index 474308a..c3fbea2 100644 --- a/libs/ui/Surface.cpp +++ b/libs/ui/Surface.cpp @@ -25,6 +25,7 @@ #include <utils/Errors.h> #include <utils/threads.h> +#include <utils/CallStack.h> #include <binder/IPCThreadState.h> #include <binder/IMemory.h> #include <utils/Log.h> @@ -38,102 +39,12 @@ #include <pixelflinger/pixelflinger.h> -#include <private/ui/SharedState.h> +#include <private/ui/SharedBufferStack.h> #include <private/ui/LayerState.h> #include <private/ui/SurfaceBuffer.h> namespace android { -// ============================================================================ -// SurfaceBuffer -// ============================================================================ - -SurfaceBuffer::SurfaceBuffer() - : BASE(), mOwner(false), mBufferMapper(BufferMapper::get()) -{ - width = - height = - stride = - format = - usage = 0; - handle = NULL; -} - -SurfaceBuffer::SurfaceBuffer(const Parcel& data) - : BASE(), mOwner(true), mBufferMapper(BufferMapper::get()) -{ - // we own the handle in this case - width = data.readInt32(); - if (width < 0) { - width = height = stride = format = usage = 0; - handle = 0; - } else { - height = data.readInt32(); - stride = data.readInt32(); - format = data.readInt32(); - usage = data.readInt32(); - handle = data.readNativeHandle(); - } -} - -SurfaceBuffer::~SurfaceBuffer() -{ - if (handle && mOwner) { - native_handle_close(handle); - native_handle_delete(const_cast<native_handle*>(handle)); - } -} - -status_t SurfaceBuffer::lock(uint32_t usage, void** vaddr) -{ - const Rect lockBounds(width, height); - status_t res = lock(usage, lockBounds, vaddr); - return res; -} - -status_t SurfaceBuffer::lock(uint32_t usage, const Rect& rect, void** vaddr) -{ - if (rect.left < 0 || rect.right > this->width || - rect.top < 0 || rect.bottom > this->height) { - LOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", - rect.left, rect.top, rect.right, rect.bottom, - this->width, this->height); - return BAD_VALUE; - } - status_t res = getBufferMapper().lock(handle, usage, rect, vaddr); - return res; -} - -status_t SurfaceBuffer::unlock() -{ - status_t res = getBufferMapper().unlock(handle); - return res; -} - -status_t SurfaceBuffer::writeToParcel(Parcel* reply, - android_native_buffer_t const* buffer) -{ - if (buffer == NULL) - return BAD_VALUE; - - if (buffer->width < 0 || buffer->height < 0) - return BAD_VALUE; - - status_t err = NO_ERROR; - if (buffer->handle == NULL) { - // this buffer doesn't have a handle - reply->writeInt32(NO_MEMORY); - } else { - reply->writeInt32(buffer->width); - reply->writeInt32(buffer->height); - reply->writeInt32(buffer->stride); - reply->writeInt32(buffer->format); - reply->writeInt32(buffer->usage); - err = reply->writeNativeHandle(buffer->handle); - } - return err; -} - // ---------------------------------------------------------------------- static status_t copyBlt( @@ -324,7 +235,7 @@ status_t SurfaceControl::setFreezeTint(uint32_t tint) { return client->setFreezeTint(mToken, tint); } -status_t SurfaceControl::validate(per_client_cblk_t const* cblk) const +status_t SurfaceControl::validate(SharedClient const* cblk) const { if (mToken<0 || mClient==0) { LOGE("invalid token (%d, identity=%u) or client (%p)", @@ -341,9 +252,10 @@ status_t SurfaceControl::validate(per_client_cblk_t const* cblk) const mToken, mIdentity, err, strerror(-err)); return err; } - if (mIdentity != uint32_t(cblk->layers[mToken].identity)) { + uint32_t identity = cblk->getIdentity(mToken); + if (mIdentity != identity) { LOGE("using an invalid surface id=%d, identity=%u should be %d", - mToken, mIdentity, cblk->layers[mToken].identity); + mToken, mIdentity, identity); return NO_INIT; } return NO_ERROR; @@ -398,14 +310,17 @@ Surface::Surface(const sp<SurfaceControl>& surface) : mClient(surface->mClient), mSurface(surface->mSurface), mToken(surface->mToken), mIdentity(surface->mIdentity), mFormat(surface->mFormat), mFlags(surface->mFlags), - mBufferMapper(BufferMapper::get()), + mBufferMapper(BufferMapper::get()), mSharedBufferClient(NULL), mWidth(surface->mWidth), mHeight(surface->mHeight) { + mSharedBufferClient = new SharedBufferClient( + mClient->mControl, mToken, 2); + init(); } Surface::Surface(const Parcel& parcel) - : mBufferMapper(BufferMapper::get()) + : mBufferMapper(BufferMapper::get()), mSharedBufferClient(NULL) { sp<IBinder> clientBinder = parcel.readStrongBinder(); mSurface = interface_cast<ISurface>(parcel.readStrongBinder()); @@ -416,9 +331,14 @@ Surface::Surface(const Parcel& parcel) mFormat = parcel.readInt32(); mFlags = parcel.readInt32(); - if (clientBinder != NULL) + // FIXME: what does that mean if clientBinder is NULL here? + if (clientBinder != NULL) { mClient = SurfaceComposerClient::clientForConnection(clientBinder); + mSharedBufferClient = new SharedBufferClient( + mClient->mControl, mToken, 2); + } + init(); } @@ -442,6 +362,7 @@ void Surface::init() // be default we request a hardware surface mUsage = GRALLOC_USAGE_HW_RENDER; mUsageChanged = true; + mNeedFullUpdate = false; } Surface::~Surface() @@ -458,6 +379,7 @@ Surface::~Surface() // happen without delay, since these resources are quite heavy. mClient.clear(); mSurface.clear(); + delete mSharedBufferClient; IPCThreadState::self()->flushCommands(); } @@ -473,7 +395,7 @@ bool Surface::isValid() { return mToken>=0 && mClient!=0; } -status_t Surface::validate(per_client_cblk_t const* cblk) const +status_t Surface::validate(SharedClient const* cblk) const { sp<SurfaceComposerClient> client(getClient()); if (mToken<0 || mClient==0) { @@ -491,9 +413,10 @@ status_t Surface::validate(per_client_cblk_t const* cblk) const mToken, mIdentity, err, strerror(-err)); return err; } - if (mIdentity != uint32_t(cblk->layers[mToken].identity)) { + uint32_t identity = cblk->getIdentity(mToken); + if (mIdentity != identity) { LOGE("using an invalid surface id=%d, identity=%u should be %d", - mToken, mIdentity, cblk->layers[mToken].identity); + mToken, mIdentity, identity); return NO_INIT; } return NO_ERROR; @@ -511,42 +434,36 @@ bool Surface::isSameSurface( // ---------------------------------------------------------------------------- -int Surface::setSwapInterval(android_native_window_t* window, int interval) -{ +int Surface::setSwapInterval(android_native_window_t* window, int interval) { return 0; } int Surface::dequeueBuffer(android_native_window_t* window, - android_native_buffer_t** buffer) -{ + android_native_buffer_t** buffer) { Surface* self = getSelf(window); return self->dequeueBuffer(buffer); } int Surface::lockBuffer(android_native_window_t* window, - android_native_buffer_t* buffer) -{ + android_native_buffer_t* buffer) { Surface* self = getSelf(window); return self->lockBuffer(buffer); } int Surface::queueBuffer(android_native_window_t* window, - android_native_buffer_t* buffer) -{ + android_native_buffer_t* buffer) { Surface* self = getSelf(window); return self->queueBuffer(buffer); } int Surface::query(android_native_window_t* window, - int what, int* value) -{ + int what, int* value) { Surface* self = getSelf(window); return self->query(what, value); } int Surface::perform(android_native_window_t* window, - int operation, ...) -{ + int operation, ...) { va_list args; va_start(args, operation); Surface* self = getSelf(window); @@ -557,8 +474,7 @@ int Surface::perform(android_native_window_t* window, // ---------------------------------------------------------------------------- -status_t Surface::dequeueBuffer(sp<SurfaceBuffer>* buffer) -{ +status_t Surface::dequeueBuffer(sp<SurfaceBuffer>* buffer) { android_native_buffer_t* out; status_t err = dequeueBuffer(&out); if (err == NO_ERROR) { @@ -567,70 +483,49 @@ status_t Surface::dequeueBuffer(sp<SurfaceBuffer>* buffer) return err; } -status_t Surface::lockBuffer(const sp<SurfaceBuffer>& buffer) -{ - return lockBuffer(buffer.get()); -} - -status_t Surface::queueBuffer(const sp<SurfaceBuffer>& buffer) -{ - return queueBuffer(buffer.get()); -} - // ---------------------------------------------------------------------------- + int Surface::dequeueBuffer(android_native_buffer_t** buffer) { - // FIXME: dequeueBuffer() needs proper implementation - - Mutex::Autolock _l(mSurfaceLock); - sp<SurfaceComposerClient> client(getClient()); - per_client_cblk_t* const cblk = client->mControl; - status_t err = validate(cblk); + status_t err = validate(client->mControl); if (err != NO_ERROR) return err; - SurfaceID index(mToken); - - int32_t backIdx = cblk->lock_layer(size_t(index), - per_client_cblk_t::BLOCKING); - - if (backIdx < 0) - return status_t(backIdx); - - mBackbufferIndex = backIdx; - layer_cblk_t* const lcblk = &(cblk->layers[index]); - volatile const surface_info_t* const back = lcblk->surface + backIdx; - - const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]); - - if (backBuffer==0 && - !((back->flags & surface_info_t::eNeedNewBuffer) || mUsageChanged)) { - LOGW("dequeueBuffer: backbuffer is null, but eNeedNewBuffer " - "is not set, fetching a buffer anyways..."); + ssize_t bufIdx = mSharedBufferClient->dequeue(); + if (bufIdx < 0) { + LOGE("error dequeuing a buffer (%s)", strerror(bufIdx)); + return bufIdx; } - - if ((back->flags & surface_info_t::eNeedNewBuffer) ||mUsageChanged || - backBuffer==0) - { - mUsageChanged = false; - err = getBufferLocked(backIdx, mUsage); + + // FIXME: in case of failure below, we need to undo the dequeue + + uint32_t usage; + const bool usageChanged = getUsage(&usage); + const sp<SurfaceBuffer>& backBuffer(mBuffers[bufIdx]); + if ((backBuffer == 0) || usageChanged || + mSharedBufferClient->needNewBuffer(bufIdx)) { + err = getBufferLocked(bufIdx, usage); + LOGE_IF(err, "getBufferLocked(%ld, %08x) failed (%s)", + bufIdx, usage, strerror(-err)); if (err == NO_ERROR) { // reset the width/height with the what we get from the buffer - const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]); mWidth = uint32_t(backBuffer->width); mHeight = uint32_t(backBuffer->height); } } + // if we still don't have a buffer here, we probably ran out of memory + if (!err && backBuffer==0) { + err = NO_MEMORY; + } + if (err == NO_ERROR) { - if (backBuffer != 0) { - mDirtyRegion.set(backBuffer->width, backBuffer->height); - *buffer = backBuffer.get(); - } else { - err = NO_MEMORY; - } + mDirtyRegion.set(backBuffer->width, backBuffer->height); + *buffer = backBuffer.get(); + } else { + mSharedBufferClient->undoDequeue(bufIdx); } return err; @@ -638,25 +533,21 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer) int Surface::lockBuffer(android_native_buffer_t* buffer) { - Mutex::Autolock _l(mSurfaceLock); - sp<SurfaceComposerClient> client(getClient()); - per_client_cblk_t* const cblk = client->mControl; - status_t err = validate(cblk); + status_t err = validate(client->mControl); if (err != NO_ERROR) return err; - // FIXME: lockBuffer() needs proper implementation - return 0; + int32_t bufIdx = SurfaceBuffer::getSelf(buffer)->getIndex(); + err = mSharedBufferClient->lock(bufIdx); + LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err)); + return err; } int Surface::queueBuffer(android_native_buffer_t* buffer) { - Mutex::Autolock _l(mSurfaceLock); - sp<SurfaceComposerClient> client(getClient()); - per_client_cblk_t* const cblk = client->mControl; - status_t err = validate(cblk); + status_t err = validate(client->mControl); if (err != NO_ERROR) return err; @@ -664,30 +555,30 @@ int Surface::queueBuffer(android_native_buffer_t* buffer) mDirtyRegion.set(mSwapRectangle); } - // transmit the dirty region - SurfaceID index(mToken); - layer_cblk_t* const lcblk = &(cblk->layers[index]); - _send_dirty_region(lcblk, mDirtyRegion); + int32_t bufIdx = SurfaceBuffer::getSelf(buffer)->getIndex(); + mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion); + err = mSharedBufferClient->queue(bufIdx); + LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err)); - uint32_t newstate = cblk->unlock_layer_and_post(size_t(index)); - if (!(newstate & eNextFlipPending)) + if (err == NO_ERROR) { + // FIXME: can we avoid this IPC if we know there is one pending? client->signalServer(); - - return NO_ERROR; + } + return err; } int Surface::query(int what, int* value) { switch (what) { - case NATIVE_WINDOW_WIDTH: - *value = int(mWidth); - return NO_ERROR; - case NATIVE_WINDOW_HEIGHT: - *value = int(mHeight); - return NO_ERROR; - case NATIVE_WINDOW_FORMAT: - *value = int(mFormat); - return NO_ERROR; + case NATIVE_WINDOW_WIDTH: + *value = int(mWidth); + return NO_ERROR; + case NATIVE_WINDOW_HEIGHT: + *value = int(mHeight); + return NO_ERROR; + case NATIVE_WINDOW_FORMAT: + *value = int(mFormat); + return NO_ERROR; } return BAD_VALUE; } @@ -715,6 +606,17 @@ void Surface::setUsage(uint32_t reqUsage) } } +bool Surface::getUsage(uint32_t* usage) +{ + Mutex::Autolock _l(mSurfaceLock); + *usage = mUsage; + if (mUsageChanged) { + mUsageChanged = false; + return true; + } + return false; +} + // ---------------------------------------------------------------------------- status_t Surface::lock(SurfaceInfo* info, bool blocking) { @@ -723,43 +625,55 @@ status_t Surface::lock(SurfaceInfo* info, bool blocking) { status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) { + if (mApiLock.tryLock() != NO_ERROR) { + LOGE("calling Surface::lock() from different threads!"); + CallStack stack; + stack.update(); + stack.dump("Surface::lock called from different threads"); + return WOULD_BLOCK; + } + // we're intending to do software rendering from this point setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); sp<SurfaceBuffer> backBuffer; status_t err = dequeueBuffer(&backBuffer); + LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err)); if (err == NO_ERROR) { - err = lockBuffer(backBuffer); + err = lockBuffer(backBuffer.get()); + LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)", + backBuffer->getIndex(), strerror(-err)); if (err == NO_ERROR) { // we handle copy-back here... - + const Rect bounds(backBuffer->width, backBuffer->height); Region scratch(bounds); Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch); - sp<SurfaceComposerClient> client(getClient()); - per_client_cblk_t* const cblk = client->mControl; - layer_cblk_t* const lcblk = &(cblk->layers[SurfaceID(mToken)]); - volatile const surface_info_t* const back = lcblk->surface + mBackbufferIndex; - if (back->flags & surface_info_t::eBufferDirty) { - // content is meaningless in this case and the whole surface - // needs to be redrawn. + if (mNeedFullUpdate) { + // reset newDirtyRegion to bounds when a buffer is reallocated + // it would be better if this information was associated with + // the buffer and made available to outside of Surface. + // This will do for now though. + mNeedFullUpdate = false; newDirtyRegion.set(bounds); } else { newDirtyRegion.andSelf(bounds); - const sp<SurfaceBuffer>& frontBuffer(mBuffers[1-mBackbufferIndex]); - if (frontBuffer !=0 && - backBuffer->width == frontBuffer->width && - backBuffer->height == frontBuffer->height && - !(lcblk->flags & eNoCopyBack)) - { - const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion)); - if (!copyback.isEmpty() && frontBuffer!=0) { - // copy front to back - copyBlt(backBuffer, frontBuffer, copyback); - } + } + + const sp<SurfaceBuffer>& frontBuffer(mPostedBuffer); + if (frontBuffer !=0 && + backBuffer->width == frontBuffer->width && + backBuffer->height == frontBuffer->height && + !(mFlags & ISurfaceComposer::eDestroyBackbuffer)) + { + const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion)); + if (!copyback.isEmpty() && frontBuffer!=0) { + // copy front to back + copyBlt(backBuffer, frontBuffer, copyback); } } + mDirtyRegion = newDirtyRegion; mOldDirtyRegion = newDirtyRegion; @@ -768,8 +682,8 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, newDirtyRegion.bounds(), &vaddr); - LOGW_IF(res, "failed locking buffer %d (%p)", - mBackbufferIndex, backBuffer->handle); + LOGW_IF(res, "failed locking buffer (handle = %p)", + backBuffer->handle); mLockedBuffer = backBuffer; other->w = backBuffer->width; @@ -780,36 +694,29 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) other->bits = vaddr; } } + mApiLock.unlock(); return err; } status_t Surface::unlockAndPost() { - if (mLockedBuffer == 0) + if (mLockedBuffer == 0) { + LOGE("unlockAndPost failed, no locked buffer"); return BAD_VALUE; + } - status_t res = mLockedBuffer->unlock(); - LOGW_IF(res, "failed unlocking buffer %d (%p)", - mBackbufferIndex, mLockedBuffer->handle); + status_t err = mLockedBuffer->unlock(); + LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle); - status_t err = queueBuffer(mLockedBuffer); + err = queueBuffer(mLockedBuffer.get()); + LOGE_IF(err, "queueBuffer (idx=%d) failed (%s)", + mLockedBuffer->getIndex(), strerror(-err)); + + mPostedBuffer = mLockedBuffer; mLockedBuffer = 0; return err; } -void Surface::_send_dirty_region( - layer_cblk_t* lcblk, const Region& dirty) -{ - const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift; - flat_region_t* flat_region = lcblk->region + index; - status_t err = dirty.write(flat_region, sizeof(flat_region_t)); - if (err < NO_ERROR) { - // region doesn't fit, use the bounds - const Region reg(dirty.bounds()); - reg.write(flat_region, sizeof(flat_region_t)); - } -} - void Surface::setSwapRectangle(const Rect& r) { Mutex::Autolock _l(mSurfaceLock); mSwapRectangle = r; @@ -829,15 +736,22 @@ status_t Surface::getBufferLocked(int index, int usage) currentBuffer.clear(); } - sp<SurfaceBuffer> buffer = s->getBuffer(usage); - LOGE_IF(buffer==0, "ISurface::getBuffer() returned NULL"); + sp<SurfaceBuffer> buffer = s->requestBuffer(index, usage); + LOGE_IF(buffer==0, + "ISurface::getBuffer(%d, %08x) returned NULL", + index, usage); if (buffer != 0) { // this should never happen by construction + LOGE_IF(buffer->handle == NULL, + "requestBuffer(%d, %08x) returned a buffer with a null handle", + index, usage); if (buffer->handle != NULL) { err = getBufferMapper().registerBuffer(buffer->handle); LOGW_IF(err, "registerBuffer(...) failed %d (%s)", err, strerror(-err)); if (err == NO_ERROR) { currentBuffer = buffer; + currentBuffer->setIndex(index); + mNeedFullUpdate = true; } } } diff --git a/libs/ui/SurfaceBuffer.cpp b/libs/ui/SurfaceBuffer.cpp new file mode 100644 index 0000000..0510bc1 --- /dev/null +++ b/libs/ui/SurfaceBuffer.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2009 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. + */ + +#define LOG_TAG "SurfaceBuffer" + +#include <stdint.h> +#include <errno.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/Log.h> +#include <binder/Parcel.h> + +#include <ui/BufferMapper.h> +#include <ui/Rect.h> +#include <private/ui/SurfaceBuffer.h> + +namespace android { + +// ============================================================================ +// SurfaceBuffer +// ============================================================================ + +SurfaceBuffer::SurfaceBuffer() + : BASE(), mOwner(false), mBufferMapper(BufferMapper::get()), mIndex(-1) +{ + width = + height = + stride = + format = + usage = 0; + handle = NULL; +} + +SurfaceBuffer::SurfaceBuffer(const Parcel& data) + : BASE(), mOwner(true), mBufferMapper(BufferMapper::get()) +{ + // we own the handle in this case + width = data.readInt32(); + if (width < 0) { + width = height = stride = format = usage = 0; + handle = 0; + } else { + height = data.readInt32(); + stride = data.readInt32(); + format = data.readInt32(); + usage = data.readInt32(); + handle = data.readNativeHandle(); + } +} + +SurfaceBuffer::~SurfaceBuffer() +{ + if (handle && mOwner) { + native_handle_close(handle); + native_handle_delete(const_cast<native_handle*>(handle)); + } +} + +status_t SurfaceBuffer::lock(uint32_t usage, void** vaddr) +{ + const Rect lockBounds(width, height); + status_t res = lock(usage, lockBounds, vaddr); + return res; +} + +status_t SurfaceBuffer::lock(uint32_t usage, const Rect& rect, void** vaddr) +{ + if (rect.left < 0 || rect.right > this->width || + rect.top < 0 || rect.bottom > this->height) { + LOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", + rect.left, rect.top, rect.right, rect.bottom, + this->width, this->height); + return BAD_VALUE; + } + status_t res = getBufferMapper().lock(handle, usage, rect, vaddr); + return res; +} + +status_t SurfaceBuffer::unlock() +{ + status_t res = getBufferMapper().unlock(handle); + return res; +} + +status_t SurfaceBuffer::writeToParcel(Parcel* reply, + android_native_buffer_t const* buffer) +{ + if (buffer == NULL) + return BAD_VALUE; + + if (buffer->width < 0 || buffer->height < 0) + return BAD_VALUE; + + status_t err = NO_ERROR; + if (buffer->handle == NULL) { + // this buffer doesn't have a handle + reply->writeInt32(NO_MEMORY); + } else { + reply->writeInt32(buffer->width); + reply->writeInt32(buffer->height); + reply->writeInt32(buffer->stride); + reply->writeInt32(buffer->format); + reply->writeInt32(buffer->usage); + err = reply->writeNativeHandle(buffer->handle); + } + return err; +} + + +void SurfaceBuffer::setIndex(int index) { + mIndex = index; +} + +int SurfaceBuffer::getIndex() const { + return mIndex; +} + + +}; // namespace android + diff --git a/libs/ui/SurfaceComposerClient.cpp b/libs/ui/SurfaceComposerClient.cpp index d2cef78..8401cb6 100644 --- a/libs/ui/SurfaceComposerClient.cpp +++ b/libs/ui/SurfaceComposerClient.cpp @@ -40,8 +40,8 @@ #include <ui/SurfaceComposerClient.h> #include <ui/Rect.h> -#include <private/ui/SharedState.h> #include <private/ui/LayerState.h> +#include <private/ui/SharedBufferStack.h> #include <private/ui/SurfaceFlingerSynchro.h> #define VERBOSE(...) ((void)0) @@ -103,169 +103,6 @@ static volatile surface_flinger_cblk_t const * get_cblk() // --------------------------------------------------------------------------- -// these functions are used by the clients -status_t per_client_cblk_t::validate(size_t i) const { - if (uint32_t(i) >= NUM_LAYERS_MAX) - return BAD_INDEX; - if (layers[i].swapState & eInvalidSurface) - return NO_MEMORY; - return NO_ERROR; -} - -int32_t per_client_cblk_t::lock_layer(size_t i, uint32_t flags) -{ - int32_t index; - uint32_t state; - int timeout = 0; - status_t result; - layer_cblk_t * const layer = layers + i; - const bool blocking = flags & BLOCKING; - const bool inspect = flags & INSPECT; - - do { - state = layer->swapState; - - if (UNLIKELY((state&(eFlipRequested|eNextFlipPending)) == eNextFlipPending)) { - LOGE("eNextFlipPending set but eFlipRequested not set, " - "layer=%d (lcblk=%p), state=%08x", - int(i), layer, int(state)); - return INVALID_OPERATION; - } - - if (UNLIKELY(state&eLocked)) { - LOGE("eLocked set when entering lock_layer(), " - "layer=%d (lcblk=%p), state=%08x", - int(i), layer, int(state)); - return WOULD_BLOCK; - } - - - if (state & (eFlipRequested | eNextFlipPending | eResizeRequested - | eInvalidSurface)) - { - int32_t resizeIndex; - Mutex::Autolock _l(lock); - // might block for a very short amount of time - // will never cause the server to block (trylock()) - - goto start_loop_here; - - // We block the client if: - // eNextFlipPending: we've used both buffers already, so we need to - // wait for one to become availlable. - // eResizeRequested: the buffer we're going to acquire is being - // resized. Block until it is done. - // eFlipRequested && eBusy: the buffer we're going to acquire is - // currently in use by the server. - // eInvalidSurface: this is a special case, we don't block in this - // case, we just return an error. - - while((state & (eNextFlipPending|eInvalidSurface)) || - (state & ((resizeIndex) ? eResizeBuffer1 : eResizeBuffer0)) || - ((state & (eFlipRequested|eBusy)) == (eFlipRequested|eBusy)) ) - { - if (state & eInvalidSurface) - return NO_MEMORY; - - if (!blocking) - return WOULD_BLOCK; - - timeout = 0; - result = cv.waitRelative(lock, seconds(1)); - if (__builtin_expect(result!=NO_ERROR, false)) { - const int newState = layer->swapState; - LOGW( "lock_layer timed out (is the CPU pegged?) " - "layer=%d, lcblk=%p, state=%08x (was %08x)", - int(i), layer, newState, int(state)); - timeout = newState != int(state); - } - - start_loop_here: - state = layer->swapState; - resizeIndex = (state&eIndex) ^ ((state&eFlipRequested)>>1); - } - - LOGW_IF(timeout, - "lock_layer() timed out but didn't appear to need " - "to be locked and we recovered " - "(layer=%d, lcblk=%p, state=%08x)", - int(i), layer, int(state)); - } - - // eFlipRequested is not set and cannot be set by another thread: it's - // safe to use the first buffer without synchronization. - - // Choose the index depending on eFlipRequested. - // When it's set, choose the 'other' buffer. - index = (state&eIndex) ^ ((state&eFlipRequested)>>1); - - // make sure this buffer is valid - status_t err = layer->surface[index].status; - if (err < 0) { - return err; - } - - if (inspect) { - // we just want to inspect this layer. don't lock it. - goto done; - } - - // last thing before we're done, we need to atomically lock the state - } while (android_atomic_cmpxchg(state, state|eLocked, &(layer->swapState))); - - VERBOSE("locked layer=%d (lcblk=%p), buffer=%d, state=0x%08x", - int(i), layer, int(index), int(state)); - - // store the index of the locked buffer (for client use only) - layer->flags &= ~eBufferIndex; - layer->flags |= ((index << eBufferIndexShift) & eBufferIndex); - -done: - return index; -} - -uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i) -{ - // atomically set eFlipRequested and clear eLocked and optionally - // set eNextFlipPending if eFlipRequested was already set - - layer_cblk_t * const layer = layers + i; - int32_t oldvalue, newvalue; - do { - oldvalue = layer->swapState; - // get current value - - newvalue = oldvalue & ~eLocked; - // clear eLocked - - newvalue |= eFlipRequested; - // set eFlipRequested - - if (oldvalue & eFlipRequested) - newvalue |= eNextFlipPending; - // if eFlipRequested was already set, set eNextFlipPending - - } while (android_atomic_cmpxchg(oldvalue, newvalue, &(layer->swapState))); - - VERBOSE("request pageflip for layer=%d, buffer=%d, state=0x%08x", - int(i), int((layer->flags & eBufferIndex) >> eBufferIndexShift), - int(newvalue)); - - // from this point, the server can kick in at any time and use the first - // buffer, so we cannot use it anymore, and we must use the 'other' - // buffer instead (or wait if it is not available yet, see lock_layer). - - return newvalue; -} - -void per_client_cblk_t::unlock_layer(size_t i) -{ - layer_cblk_t * const layer = layers + i; - android_atomic_and(~eLocked, &layer->swapState); -} - -// --------------------------------------------------------------------------- - static inline int compare_type( const layer_state_t& lhs, const layer_state_t& rhs) { if (lhs.surface < rhs.surface) return -1; @@ -315,7 +152,7 @@ void SurfaceComposerClient::_init( mControlMemory = mClient->getControlBlock(); mSignalServer = new SurfaceFlingerSynchro(sm); - mControl = static_cast<per_client_cblk_t *>(mControlMemory->getBase()); + mControl = static_cast<SharedClient *>(mControlMemory->getBase()); } SurfaceComposerClient::~SurfaceComposerClient() @@ -539,18 +376,17 @@ void SurfaceComposerClient::closeGlobalTransaction() const size_t N = clients.size(); VERBOSE("closeGlobalTransaction (%ld clients)", N); - if (N == 1) { - clients[0]->closeTransaction(); - } else { - const sp<ISurfaceComposer>& sm(_get_surface_manager()); - sm->openGlobalTransaction(); - for (size_t i=0; i<N; i++) { - clients[i]->closeTransaction(); - } - sm->closeGlobalTransaction(); + + const sp<ISurfaceComposer>& sm(_get_surface_manager()); + sm->openGlobalTransaction(); + for (size_t i=0; i<N; i++) { + clients[i]->closeTransaction(); } + sm->closeGlobalTransaction(); + } + status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags) { const sp<ISurfaceComposer>& sm(_get_surface_manager()); |