| /* | 
 |  * 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. | 
 |  * | 
 |  *  | 
 |  * 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  = 16; | 
 | const unsigned int NUM_DISPLAY_MAX = 4; | 
 |  | 
 | // ---------------------------------------------------------------------------- | 
 |  | 
 | 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: | 
 |     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     reserved32[2]; | 
 |     Statistics  stats; | 
 |     int32_t     reserved; | 
 |     BufferData  buffers[NUM_BUFFER_MAX];     // 960 bytes | 
 | }; | 
 |  | 
 | // ---------------------------------------------------------------------------- | 
 |  | 
 | // 4 KB max | 
 | class SharedClient | 
 | { | 
 | public: | 
 |     SharedClient(); | 
 |     ~SharedClient(); | 
 |  | 
 |     status_t validate(size_t token) const; | 
 |     uint32_t getIdentity(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[ NUM_LAYERS_MAX ]; | 
 | }; | 
 |  | 
 | // ============================================================================ | 
 |  | 
 | class SharedBufferBase | 
 | { | 
 | public: | 
 |     SharedBufferBase(SharedClient* sharedClient, int surface, int num, | 
 |             int32_t identity); | 
 |     ~SharedBufferBase(); | 
 |     uint32_t getIdentity(); | 
 |     status_t getStatus() const; | 
 |     size_t getFrontBuffer() const; | 
 |     String8 dump(char const* prefix) const; | 
 |  | 
 | protected: | 
 |     SharedClient* const mSharedClient; | 
 |     SharedBufferStack* const mSharedStack; | 
 |     const int mNumBuffers; | 
 |     const int mIdentity; | 
 |     int32_t computeTail() const; | 
 |  | 
 |     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); | 
 |      | 
 | 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 tail; | 
 |     int32_t undoDequeueTail; | 
 |     int32_t queued_head; | 
 |     // statistics... | 
 |     nsecs_t mDequeueTime[NUM_BUFFER_MAX]; | 
 | }; | 
 |  | 
 | // ---------------------------------------------------------------------------- | 
 |  | 
 | class SharedBufferServer : public SharedBufferBase | 
 | { | 
 | 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 reallocate(); | 
 |     status_t assertReallocate(int buffer); | 
 |     int32_t getQueuedCount() const; | 
 |      | 
 |     Region getDirtyRegion(int buffer) const; | 
 |  | 
 |     SharedBufferStack::Statistics getStats() 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 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[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 */ |