/* * 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_SF_SHARED_BUFFER_STACK_H #define ANDROID_SF_SHARED_BUFFER_STACK_H #include #include #include #include #include #include #include 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. * */ // ---------------------------------------------------------------------------- class Region; class SharedBufferStack; class SharedClient; // ---------------------------------------------------------------------------- class SharedBufferStack { friend class SharedClient; friend class SharedBufferBase; friend class SharedBufferClient; friend class SharedBufferServer; public: // When changing these values, the COMPILE_TIME_ASSERT at the end of this // file need to be updated. static const unsigned int NUM_LAYERS_MAX = 31; static const unsigned int NUM_BUFFER_MAX = 16; static const unsigned int NUM_BUFFER_MIN = 2; static const unsigned int NUM_DISPLAY_MAX = 4; struct Statistics { // 4 longs typedef int32_t usecs_t; usecs_t totalTime; usecs_t reserved[3]; }; struct SmallRect { uint16_t l, t, r, b; }; struct FlatRegion { // 52 bytes = 4 * (1 + 2*N) static const unsigned int NUM_RECT_MAX = 5; uint32_t count; SmallRect rects[NUM_RECT_MAX]; }; struct BufferData { FlatRegion dirtyRegion; SmallRect crop; uint8_t transform; uint8_t reserved[3]; }; SharedBufferStack(); void init(int32_t identity); status_t setDirtyRegion(int buffer, const Region& reg); status_t setCrop(int buffer, const Rect& reg); status_t setTransform(int buffer, uint8_t transform); Region getDirtyRegion(int buffer) const; Rect getCrop(int buffer) const; uint32_t getTransform(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 reserved1; volatile status_t status; // surface's status code // not part of the conditions volatile int32_t reallocMask; volatile int8_t index[NUM_BUFFER_MAX]; int32_t identity; // surface's identity (const) int32_t token; // surface's token (for debugging) Statistics stats; int8_t headBuf; // last retired buffer uint8_t reservedBytes[3]; int32_t reserved; BufferData buffers[NUM_BUFFER_MAX]; // 1024 bytes }; // ---------------------------------------------------------------------------- // 32 KB max class SharedClient { public: SharedClient(); ~SharedClient(); status_t validate(size_t token) const; 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[ SharedBufferStack::NUM_LAYERS_MAX ]; }; // ============================================================================ class SharedBufferBase { public: SharedBufferBase(SharedClient* sharedClient, int surface, int32_t identity); ~SharedBufferBase(); status_t getStatus() const; int32_t getIdentity() const; String8 dump(char const* prefix) const; protected: SharedClient* const mSharedClient; SharedBufferStack* const mSharedStack; const int mIdentity; friend struct Update; friend struct QueueUpdate; struct ConditionBase { SharedBufferStack& stack; inline ConditionBase(SharedBufferBase* sbc) : stack(*sbc->mSharedStack) { } virtual ~ConditionBase() { }; virtual bool operator()() const = 0; virtual const char* name() const = 0; }; status_t waitForCondition(const ConditionBase& condition); struct UpdateBase { SharedBufferStack& stack; inline UpdateBase(SharedBufferBase* sbb) : stack(*sbb->mSharedStack) { } }; template status_t updateCondition(T update); }; /* * During Monkey runs, sometimes, a process, holding SharedClient * LOCK, dies while holding that lock. Since SharedClient lock is * of type SHARED, SF and Binder threads cannot acquire it anymore * causing a system hang. Since it seems like posix would not allow * us to unlock a mutex not owned by the caller thread, we are out * of luck and need to ignore that update. * It is assumed to be safe since because if the client dies (process * dies which was the client to SF), so it is safe to ignore all related * pending updates and/or transactions. * */ class SharedClientTryLock { public: SharedClientTryLock(Mutex& m); ~SharedClientTryLock() { if(LOCKED == _status) { _m.unlock(); } } bool locked() const { return _status == LOCKED; } private: enum Status { LOCKED, UNLOCKED } _status; Mutex& _m; }; template status_t SharedBufferBase::updateCondition(T update) { SharedClient& client( *mSharedClient ); SharedClientTryLock _l(client.lock); ssize_t result = 0; if(_l.locked()) { // only update+broadcast if we acquired the lock result = update(); client.cv.broadcast(); } return result; } // ---------------------------------------------------------------------------- class SharedBufferClient : public SharedBufferBase { public: SharedBufferClient(SharedClient* sharedClient, int surface, int num, int32_t identity); ssize_t dequeue(); status_t undoDequeue(int buf); status_t lock(int buf); status_t cancel(int buf); status_t queue(int buf); bool needNewBuffer(int buffer) const; status_t setDirtyRegion(int buffer, const Region& reg); status_t setCrop(int buffer, const Rect& reg); status_t setTransform(int buffer, uint32_t transform); class SetBufferCountCallback { friend class SharedBufferClient; virtual status_t operator()(int bufferCount) const = 0; protected: virtual ~SetBufferCountCallback() { } }; status_t setBufferCount(int bufferCount, const SetBufferCountCallback& ipc); private: friend struct Condition; friend struct DequeueCondition; friend struct LockCondition; struct QueueUpdate : public UpdateBase { inline QueueUpdate(SharedBufferBase* sbb); inline ssize_t operator()(); }; struct DequeueUpdate : public UpdateBase { inline DequeueUpdate(SharedBufferBase* sbb); inline ssize_t operator()(); }; struct CancelUpdate : public UpdateBase { int tail, buf; inline CancelUpdate(SharedBufferBase* sbb, int tail, int buf); inline ssize_t operator()(); }; // -- struct DequeueCondition : public ConditionBase { inline DequeueCondition(SharedBufferClient* sbc); inline bool operator()() const; inline const char* name() const { return "DequeueCondition"; } }; struct LockCondition : public ConditionBase { int buf; inline LockCondition(SharedBufferClient* sbc, int buf); inline bool operator()() const; inline const char* name() const { return "LockCondition"; } }; int32_t computeTail() const; mutable RWLock mLock; int mNumBuffers; int32_t tail; int32_t queued_head; // statistics... nsecs_t mDequeueTime[SharedBufferStack::NUM_BUFFER_MAX]; }; // ---------------------------------------------------------------------------- class SharedBufferServer : public SharedBufferBase, public LightRefBase { public: SharedBufferServer(SharedClient* sharedClient, int surface, int num, int32_t identity); ssize_t retireAndLock(); void setStatus(status_t status); status_t reallocateAll(); status_t reallocateAllExcept(int buffer); int32_t getQueuedCount() const; Region getDirtyRegion(int buffer) const; Rect getCrop(int buffer) const; uint32_t getTransform(int buffer) const; status_t resize(int newNumBuffers); status_t setInUseBypass(int buffer); SharedBufferStack::Statistics getStats() const; private: friend class LightRefBase; ~SharedBufferServer(); /* * BufferList is basically a fixed-capacity sorted-vector of * unsigned 5-bits ints using a 32-bits int as storage. * it has efficient iterators to find items in the list and not in the list. */ class BufferList { size_t mCapacity; uint32_t mList; public: BufferList(size_t c = SharedBufferStack::NUM_BUFFER_MAX) : mCapacity(c), mList(0) { } status_t add(int value); status_t remove(int value); uint32_t getMask() const { return mList; } class const_iterator { friend class BufferList; uint32_t mask, curr; const_iterator(uint32_t mask) : mask(mask), curr(__builtin_clz(mask)) { } public: inline bool operator == (const const_iterator& rhs) const { return mask == rhs.mask; } inline bool operator != (const const_iterator& rhs) const { return mask != rhs.mask; } inline int operator *() const { return curr; } inline const const_iterator& operator ++() { mask &= ~(1<<(31-curr)); curr = __builtin_clz(mask); return *this; } }; inline const_iterator begin() const { return const_iterator(mList); } inline const_iterator end() const { return const_iterator(0); } inline const_iterator free_begin() const { uint32_t mask = (1 << (32-mCapacity)) - 1; return const_iterator( ~(mList | mask) ); } }; // this protects mNumBuffers and mBufferList mutable RWLock mLock; int mNumBuffers; BufferList mBufferList; struct RetireUpdate : public UpdateBase { const int numBuffers; inline RetireUpdate(SharedBufferBase* sbb, int numBuffers); inline ssize_t operator()(); }; struct StatusUpdate : public UpdateBase { const status_t status; inline StatusUpdate(SharedBufferBase* sbb, status_t status); inline ssize_t operator()(); }; struct BypassUpdate : public UpdateBase { const int lockedBuffer; inline BypassUpdate(SharedBufferBase* sbb, int lockedBuffer); inline ssize_t operator()(); }; }; // =========================================================================== 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[SharedBufferStack::NUM_DISPLAY_MAX]; }; // --------------------------------------------------------------------------- COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 32768) COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096) // --------------------------------------------------------------------------- }; // namespace android #endif /* ANDROID_SF_SHARED_BUFFER_STACK_H */