| /* | |
| * 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 <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. | |
| * | |
| */ | |
| // ---------------------------------------------------------------------------- | |
| class Region; | |
| class SharedBufferStack; | |
| class SharedClient; | |
| // ---------------------------------------------------------------------------- | |
| // 4 * (11 + 7 + (1 + 2*NUM_RECT_MAX) * NUM_BUFFER_MAX) * NUM_LAYERS_MAX | |
| // 4 * (11 + 7 + (1 + 2*7)*16) * 31 | |
| // 1032 * 31 | |
| // = ~27 KiB (31992) | |
| 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 = 6; | |
| uint32_t count; | |
| SmallRect rects[NUM_RECT_MAX]; | |
| }; | |
| struct BufferData { | |
| FlatRegion dirtyRegion; | |
| SmallRect crop; | |
| }; | |
| SharedBufferStack(); | |
| void init(int32_t identity); | |
| status_t setDirtyRegion(int buffer, const Region& reg); | |
| status_t setCrop(int buffer, const Rect& 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 | |
| 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) | |
| int32_t reserved32[1]; | |
| Statistics stats; | |
| int32_t reserved; | |
| BufferData buffers[NUM_BUFFER_MAX]; // 960 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; | |
| size_t getFrontBuffer() 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 <typename T> | |
| status_t updateCondition(T update); | |
| }; | |
| 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, | |
| int32_t identity); | |
| 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); | |
| status_t setCrop(int buffer, const Rect& reg); | |
| 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 UndoDequeueUpdate : public UpdateBase { | |
| inline UndoDequeueUpdate(SharedBufferBase* sbb); | |
| 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 undoDequeueTail; | |
| int32_t queued_head; | |
| // statistics... | |
| nsecs_t mDequeueTime[SharedBufferStack::NUM_BUFFER_MAX]; | |
| }; | |
| // ---------------------------------------------------------------------------- | |
| class SharedBufferServer | |
| : public SharedBufferBase, | |
| public LightRefBase<SharedBufferServer> | |
| { | |
| public: | |
| SharedBufferServer(SharedClient* sharedClient, int surface, int num, | |
| int32_t identity); | |
| ssize_t retireAndLock(); | |
| status_t unlock(int buffer); | |
| void setStatus(status_t status); | |
| status_t reallocateAll(); | |
| status_t reallocateAllExcept(int buffer); | |
| status_t assertReallocate(int buffer); | |
| int32_t getQueuedCount() const; | |
| Region getDirtyRegion(int buffer) const; | |
| status_t resize(int newNumBuffers); | |
| SharedBufferStack::Statistics getStats() const; | |
| private: | |
| friend class LightRefBase<SharedBufferServer>; | |
| ~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 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 StatusUpdate : public UpdateBase { | |
| const status_t status; | |
| inline StatusUpdate(SharedBufferBase* sbb, status_t status); | |
| inline ssize_t operator()(); | |
| }; | |
| struct ReallocateCondition : public ConditionBase { | |
| int buf; | |
| inline ReallocateCondition(SharedBufferBase* sbb, int buf); | |
| inline bool operator()() const; | |
| inline const char* name() const { 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[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 */ |