• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ANDROID_UI_SHARED_BUFFER_STACK_H
18 #define ANDROID_UI_SHARED_BUFFER_STACK_H
19 
20 #include <stdint.h>
21 #include <sys/types.h>
22 
23 #include <cutils/compiler.h>
24 
25 #include <utils/Debug.h>
26 #include <utils/threads.h>
27 #include <utils/String8.h>
28 
29 #include <ui/Rect.h>
30 
31 namespace android {
32 // ---------------------------------------------------------------------------
33 
34 /*
35  * These classes manage a stack of buffers in shared memory.
36  *
37  * SharedClient: represents a client with several stacks
38  * SharedBufferStack: represents a stack of buffers
39  * SharedBufferClient: manipulates the SharedBufferStack from the client side
40  * SharedBufferServer: manipulates the SharedBufferStack from the server side
41  *
42  * Buffers can be dequeued until there are none available, they can be locked
43  * unless they are in use by the server, which is only the case for the last
44  * dequeue-able buffer. When these various conditions are not met, the caller
45  * waits until the condition is met.
46  *
47  *
48  * CAVEATS:
49  *
50  * In the current implementation there are several limitations:
51  * - buffers must be locked in the same order they've been dequeued
52  * - buffers must be enqueued in the same order they've been locked
53  * - dequeue() is not reentrant
54  * - no error checks are done on the condition above
55  *
56  */
57 
58 // When changing these values, the COMPILE_TIME_ASSERT at the end of this
59 // file need to be updated.
60 const unsigned int NUM_LAYERS_MAX  = 31;
61 const unsigned int NUM_BUFFER_MAX  = 4;
62 const unsigned int NUM_DISPLAY_MAX = 4;
63 
64 // ----------------------------------------------------------------------------
65 
66 class Region;
67 class SharedBufferStack;
68 class SharedClient;
69 
70 // ----------------------------------------------------------------------------
71 
72 // should be 128 bytes (32 longs)
73 class SharedBufferStack
74 {
75     friend class SharedClient;
76     friend class SharedBufferBase;
77     friend class SharedBufferClient;
78     friend class SharedBufferServer;
79 
80 public:
81     struct FlatRegion { // 12 bytes
82         static const unsigned int NUM_RECT_MAX = 1;
83         uint32_t    count;
84         uint16_t    rects[4*NUM_RECT_MAX];
85     };
86 
87     struct Statistics { // 4 longs
88         typedef int32_t usecs_t;
89         usecs_t  totalTime;
90         usecs_t  reserved[3];
91     };
92 
93     SharedBufferStack();
94     void init(int32_t identity);
95     status_t setDirtyRegion(int buffer, const Region& reg);
96     Region getDirtyRegion(int buffer) const;
97 
98     // these attributes are part of the conditions/updates
99     volatile int32_t head;      // server's current front buffer
100     volatile int32_t available; // number of dequeue-able buffers
101     volatile int32_t queued;    // number of buffers waiting for post
102     volatile int32_t inUse;     // buffer currently in use by SF
103     volatile status_t status;   // surface's status code
104 
105     // not part of the conditions
106     volatile int32_t reallocMask;
107 
108     int32_t     identity;       // surface's identity (const)
109     int32_t     reserved32[9];
110     Statistics  stats;
111     FlatRegion  dirtyRegion[NUM_BUFFER_MAX];    // 12*4=48 bytes
112 };
113 
114 // ----------------------------------------------------------------------------
115 
116 // 4 KB max
117 class SharedClient
118 {
119 public:
120     SharedClient();
121     ~SharedClient();
122 
123     status_t validate(size_t token) const;
124     uint32_t getIdentity(size_t token) const;
125 
126 private:
127     friend class SharedBufferBase;
128     friend class SharedBufferClient;
129     friend class SharedBufferServer;
130 
131     // FIXME: this should be replaced by a lock-less primitive
132     Mutex lock;
133     Condition cv;
134     SharedBufferStack surfaces[ NUM_LAYERS_MAX ];
135 };
136 
137 // ============================================================================
138 
139 class SharedBufferBase
140 {
141 public:
142     SharedBufferBase(SharedClient* sharedClient, int surface, int num,
143             int32_t identity);
144     ~SharedBufferBase();
145     uint32_t getIdentity();
146     status_t getStatus() const;
147     size_t getFrontBuffer() const;
148     String8 dump(char const* prefix) const;
149 
150 protected:
151     SharedClient* const mSharedClient;
152     SharedBufferStack* const mSharedStack;
153     const int mNumBuffers;
154     const int mIdentity;
155 
156     friend struct Update;
157     friend struct QueueUpdate;
158 
159     struct ConditionBase {
160         SharedBufferStack& stack;
ConditionBaseConditionBase161         inline ConditionBase(SharedBufferBase* sbc)
162             : stack(*sbc->mSharedStack) { }
163     };
164 
165     struct UpdateBase {
166         SharedBufferStack& stack;
UpdateBaseUpdateBase167         inline UpdateBase(SharedBufferBase* sbb)
168             : stack(*sbb->mSharedStack) { }
169     };
170 
171     template <typename T>
172     status_t waitForCondition(T condition);
173 
174     template <typename T>
175     status_t updateCondition(T update);
176 };
177 
178 template <typename T>
waitForCondition(T condition)179 status_t SharedBufferBase::waitForCondition(T condition)
180 {
181     const SharedBufferStack& stack( *mSharedStack );
182     SharedClient& client( *mSharedClient );
183     const nsecs_t TIMEOUT = s2ns(1);
184     Mutex::Autolock _l(client.lock);
185     while ((condition()==false) &&
186             (stack.identity == mIdentity) &&
187             (stack.status == NO_ERROR))
188     {
189         status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
190 
191         // handle errors and timeouts
192         if (CC_UNLIKELY(err != NO_ERROR)) {
193             if (err == TIMED_OUT) {
194                 if (condition()) {
195                     LOGE("waitForCondition(%s) timed out (identity=%d), "
196                         "but condition is true! We recovered but it "
197                         "shouldn't happen." , T::name(),
198                         stack.identity);
199                     break;
200                 } else {
201                     LOGW("waitForCondition(%s) timed out "
202                         "(identity=%d, status=%d). "
203                         "CPU may be pegged. trying again.", T::name(),
204                         stack.identity, stack.status);
205                 }
206             } else {
207                 LOGE("waitForCondition(%s) error (%s) ",
208                         T::name(), strerror(-err));
209                 return err;
210             }
211         }
212     }
213     return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status;
214 }
215 
216 
217 template <typename T>
updateCondition(T update)218 status_t SharedBufferBase::updateCondition(T update) {
219     SharedClient& client( *mSharedClient );
220     Mutex::Autolock _l(client.lock);
221     ssize_t result = update();
222     client.cv.broadcast();
223     return result;
224 }
225 
226 // ----------------------------------------------------------------------------
227 
228 class SharedBufferClient : public SharedBufferBase
229 {
230 public:
231     SharedBufferClient(SharedClient* sharedClient, int surface, int num,
232             int32_t identity);
233 
234     ssize_t dequeue();
235     status_t undoDequeue(int buf);
236 
237     status_t lock(int buf);
238     status_t queue(int buf);
239     bool needNewBuffer(int buffer) const;
240     status_t setDirtyRegion(int buffer, const Region& reg);
241 
242 private:
243     friend struct Condition;
244     friend struct DequeueCondition;
245     friend struct LockCondition;
246 
247     int32_t computeTail() const;
248 
249     struct QueueUpdate : public UpdateBase {
250         inline QueueUpdate(SharedBufferBase* sbb);
251         inline ssize_t operator()();
252     };
253 
254     struct UndoDequeueUpdate : public UpdateBase {
255         inline UndoDequeueUpdate(SharedBufferBase* sbb);
256         inline ssize_t operator()();
257     };
258 
259     // --
260 
261     struct DequeueCondition : public ConditionBase {
262         inline DequeueCondition(SharedBufferClient* sbc);
263         inline bool operator()();
nameDequeueCondition264         static inline const char* name() { return "DequeueCondition"; }
265     };
266 
267     struct LockCondition : public ConditionBase {
268         int buf;
269         inline LockCondition(SharedBufferClient* sbc, int buf);
270         inline bool operator()();
nameLockCondition271         static inline const char* name() { return "LockCondition"; }
272     };
273 
274     int32_t tail;
275     // statistics...
276     nsecs_t mDequeueTime[NUM_BUFFER_MAX];
277 };
278 
279 // ----------------------------------------------------------------------------
280 
281 class SharedBufferServer : public SharedBufferBase
282 {
283 public:
284     SharedBufferServer(SharedClient* sharedClient, int surface, int num,
285             int32_t identity);
286 
287     ssize_t retireAndLock();
288     status_t unlock(int buffer);
289     void setStatus(status_t status);
290     status_t reallocate();
291     status_t assertReallocate(int buffer);
292     int32_t getQueuedCount() const;
293 
294     Region getDirtyRegion(int buffer) const;
295 
296     SharedBufferStack::Statistics getStats() const;
297 
298 
299 private:
300     struct UnlockUpdate : public UpdateBase {
301         const int lockedBuffer;
302         inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer);
303         inline ssize_t operator()();
304     };
305 
306     struct RetireUpdate : public UpdateBase {
307         const int numBuffers;
308         inline RetireUpdate(SharedBufferBase* sbb, int numBuffers);
309         inline ssize_t operator()();
310     };
311 
312     struct StatusUpdate : public UpdateBase {
313         const status_t status;
314         inline StatusUpdate(SharedBufferBase* sbb, status_t status);
315         inline ssize_t operator()();
316     };
317 
318     struct ReallocateCondition : public ConditionBase {
319         int buf;
320         inline ReallocateCondition(SharedBufferBase* sbb, int buf);
321         inline bool operator()();
nameReallocateCondition322         static inline const char* name() { return "ReallocateCondition"; }
323     };
324 };
325 
326 // ===========================================================================
327 
328 struct display_cblk_t
329 {
330     uint16_t    w;
331     uint16_t    h;
332     uint8_t     format;
333     uint8_t     orientation;
334     uint8_t     reserved[2];
335     float       fps;
336     float       density;
337     float       xdpi;
338     float       ydpi;
339     uint32_t    pad[2];
340 };
341 
342 struct surface_flinger_cblk_t   // 4KB max
343 {
344     uint8_t         connected;
345     uint8_t         reserved[3];
346     uint32_t        pad[7];
347     display_cblk_t  displays[NUM_DISPLAY_MAX];
348 };
349 
350 // ---------------------------------------------------------------------------
351 
352 COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 4096)
353 COMPILE_TIME_ASSERT(sizeof(SharedBufferStack) == 128)
354 COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
355 
356 // ---------------------------------------------------------------------------
357 }; // namespace android
358 
359 #endif /* ANDROID_UI_SHARED_BUFFER_STACK_H */
360