blob: 46b67664387644d2b7992d74d600210c1f4bd027 [file] [log] [blame]
Mathias Agopian9779b222009-09-07 16:32:45 -07001/*
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#define LOG_TAG "SharedBufferStack"
18
19#include <stdint.h>
20#include <sys/types.h>
21
22#include <utils/Debug.h>
23#include <utils/Log.h>
24#include <utils/threads.h>
25
26#include <private/ui/SharedBufferStack.h>
27
28#include <ui/Rect.h>
29#include <ui/Region.h>
30
31#define DEBUG_ATOMICS 0
32
33namespace android {
34// ----------------------------------------------------------------------------
35
36SharedClient::SharedClient()
37 : lock(Mutex::SHARED)
38{
39}
40
41SharedClient::~SharedClient() {
42}
43
44
45// these functions are used by the clients
46status_t SharedClient::validate(size_t i) const {
47 if (uint32_t(i) >= uint32_t(NUM_LAYERS_MAX))
48 return BAD_INDEX;
49 return surfaces[i].status;
50}
51
52uint32_t SharedClient::getIdentity(size_t token) const {
53 return uint32_t(surfaces[token].identity);
54}
55
Mathias Agopian9779b222009-09-07 16:32:45 -070056// ----------------------------------------------------------------------------
57
58
59SharedBufferStack::SharedBufferStack()
Mathias Agopian9779b222009-09-07 16:32:45 -070060{
61}
62
Mathias Agopian248b5bd2009-09-10 19:41:18 -070063void SharedBufferStack::init(int32_t i)
64{
65 inUse = -1;
66 status = NO_ERROR;
67 identity = i;
68}
69
Mathias Agopian9779b222009-09-07 16:32:45 -070070status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
71{
72 if (uint32_t(buffer) >= NUM_BUFFER_MAX)
73 return BAD_INDEX;
74
75 // in the current implementation we only send a single rectangle
76 const Rect bounds(dirty.getBounds());
77 FlatRegion& reg(dirtyRegion[buffer]);
78 reg.count = 1;
79 reg.rects[0] = uint16_t(bounds.left);
80 reg.rects[1] = uint16_t(bounds.top);
81 reg.rects[2] = uint16_t(bounds.right);
82 reg.rects[3] = uint16_t(bounds.bottom);
83 return NO_ERROR;
84}
85
86Region SharedBufferStack::getDirtyRegion(int buffer) const
87{
88 Region res;
89 if (uint32_t(buffer) >= NUM_BUFFER_MAX)
90 return res;
91
92 const FlatRegion& reg(dirtyRegion[buffer]);
93 res.set(Rect(reg.rects[0], reg.rects[1], reg.rects[2], reg.rects[3]));
94 return res;
95}
96
97// ----------------------------------------------------------------------------
98
99SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
Mathias Agopian4961c952009-10-06 19:00:57 -0700100 int surface, int num, int32_t identity)
Mathias Agopian9779b222009-09-07 16:32:45 -0700101 : mSharedClient(sharedClient),
102 mSharedStack(sharedClient->surfaces + surface),
Mathias Agopian4961c952009-10-06 19:00:57 -0700103 mNumBuffers(num), mIdentity(identity)
Mathias Agopian9779b222009-09-07 16:32:45 -0700104{
105}
106
107SharedBufferBase::~SharedBufferBase()
108{
109}
110
111uint32_t SharedBufferBase::getIdentity()
112{
113 SharedBufferStack& stack( *mSharedStack );
114 return stack.identity;
115}
116
Mathias Agopian0c4cec72009-10-02 18:12:30 -0700117status_t SharedBufferBase::getStatus() const
118{
119 SharedBufferStack& stack( *mSharedStack );
120 return stack.status;
121}
122
Mathias Agopian9779b222009-09-07 16:32:45 -0700123size_t SharedBufferBase::getFrontBuffer() const
124{
125 SharedBufferStack& stack( *mSharedStack );
126 return size_t( stack.head );
127}
128
129String8 SharedBufferBase::dump(char const* prefix) const
130{
131 const size_t SIZE = 1024;
132 char buffer[SIZE];
133 String8 result;
134 SharedBufferStack& stack( *mSharedStack );
135 snprintf(buffer, SIZE,
136 "%s[ head=%2d, available=%2d, queued=%2d ] "
137 "reallocMask=%08x, inUse=%2d, identity=%d, status=%d\n",
138 prefix, stack.head, stack.available, stack.queued,
139 stack.reallocMask, stack.inUse, stack.identity, stack.status);
140 result.append(buffer);
141 return result;
142}
143
Mathias Agopian9779b222009-09-07 16:32:45 -0700144// ============================================================================
145// conditions and updates
146// ============================================================================
147
148SharedBufferClient::DequeueCondition::DequeueCondition(
149 SharedBufferClient* sbc) : ConditionBase(sbc) {
150}
151bool SharedBufferClient::DequeueCondition::operator()() {
152 return stack.available > 0;
153}
154
155SharedBufferClient::LockCondition::LockCondition(
156 SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) {
157}
158bool SharedBufferClient::LockCondition::operator()() {
159 return (buf != stack.head ||
160 (stack.queued > 0 && stack.inUse != buf));
161}
162
163SharedBufferServer::ReallocateCondition::ReallocateCondition(
164 SharedBufferBase* sbb, int buf) : ConditionBase(sbb), buf(buf) {
165}
166bool SharedBufferServer::ReallocateCondition::operator()() {
167 // TODO: we should also check that buf has been dequeued
168 return (buf != stack.head);
169}
170
171// ----------------------------------------------------------------------------
172
173SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb)
174 : UpdateBase(sbb) {
175}
176ssize_t SharedBufferClient::QueueUpdate::operator()() {
177 android_atomic_inc(&stack.queued);
178 return NO_ERROR;
179}
180
181SharedBufferClient::UndoDequeueUpdate::UndoDequeueUpdate(SharedBufferBase* sbb)
182 : UpdateBase(sbb) {
183}
184ssize_t SharedBufferClient::UndoDequeueUpdate::operator()() {
185 android_atomic_inc(&stack.available);
186 return NO_ERROR;
187}
188
189SharedBufferServer::UnlockUpdate::UnlockUpdate(
190 SharedBufferBase* sbb, int lockedBuffer)
191 : UpdateBase(sbb), lockedBuffer(lockedBuffer) {
192}
193ssize_t SharedBufferServer::UnlockUpdate::operator()() {
194 if (stack.inUse != lockedBuffer) {
195 LOGE("unlocking %d, but currently locked buffer is %d",
196 lockedBuffer, stack.inUse);
197 return BAD_VALUE;
198 }
199 android_atomic_write(-1, &stack.inUse);
200 return NO_ERROR;
201}
202
203SharedBufferServer::RetireUpdate::RetireUpdate(
204 SharedBufferBase* sbb, int numBuffers)
205 : UpdateBase(sbb), numBuffers(numBuffers) {
206}
207ssize_t SharedBufferServer::RetireUpdate::operator()() {
208 // head is only written in this function, which is single-thread.
209 int32_t head = stack.head;
210
211 // Preventively lock the current buffer before updating queued.
212 android_atomic_write(head, &stack.inUse);
213
214 // Decrement the number of queued buffers
215 int32_t queued;
216 do {
217 queued = stack.queued;
218 if (queued == 0) {
219 return NOT_ENOUGH_DATA;
220 }
221 } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued));
222
223 // update the head pointer
224 head = ((head+1 >= numBuffers) ? 0 : head+1);
225
226 // lock the buffer before advancing head, which automatically unlocks
227 // the buffer we preventively locked upon entering this function
228 android_atomic_write(head, &stack.inUse);
229
230 // advance head
231 android_atomic_write(head, &stack.head);
232
233 // now that head has moved, we can increment the number of available buffers
234 android_atomic_inc(&stack.available);
235 return head;
236}
237
Mathias Agopian436c6272009-09-10 16:55:13 -0700238SharedBufferServer::StatusUpdate::StatusUpdate(
239 SharedBufferBase* sbb, status_t status)
240 : UpdateBase(sbb), status(status) {
241}
242
243ssize_t SharedBufferServer::StatusUpdate::operator()() {
244 android_atomic_write(status, &stack.status);
245 return NO_ERROR;
246}
247
Mathias Agopian9779b222009-09-07 16:32:45 -0700248// ============================================================================
249
250SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,
Mathias Agopian4961c952009-10-06 19:00:57 -0700251 int surface, int num, int32_t identity)
252 : SharedBufferBase(sharedClient, surface, num, identity), tail(0)
Mathias Agopian9779b222009-09-07 16:32:45 -0700253{
Mathias Agopianbd852712009-09-14 15:48:42 -0700254 tail = computeTail();
255}
256
257int32_t SharedBufferClient::computeTail() const
258{
Mathias Agopian3e63f912009-09-11 19:18:20 -0700259 SharedBufferStack& stack( *mSharedStack );
Mathias Agopian3e63f912009-09-11 19:18:20 -0700260 // we need to make sure we read available and head coherently,
261 // w.r.t RetireUpdate.
Mathias Agopianbd852712009-09-14 15:48:42 -0700262 int32_t newTail;
263 int32_t avail;
264 int32_t head;
Mathias Agopian3e63f912009-09-11 19:18:20 -0700265 do {
266 avail = stack.available;
267 head = stack.head;
268 } while (stack.available != avail);
Mathias Agopianbd852712009-09-14 15:48:42 -0700269 newTail = head - avail + 1;
270 if (newTail < 0) {
271 newTail += mNumBuffers;
Mathias Agopian3e63f912009-09-11 19:18:20 -0700272 }
Mathias Agopianbd852712009-09-14 15:48:42 -0700273 return newTail;
Mathias Agopian9779b222009-09-07 16:32:45 -0700274}
275
276ssize_t SharedBufferClient::dequeue()
277{
Mathias Agopian3e63f912009-09-11 19:18:20 -0700278 SharedBufferStack& stack( *mSharedStack );
279
280 if (stack.head == tail && stack.available == 2) {
281 LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
282 tail, stack.head, stack.available, stack.queued);
283 }
Mathias Agopianbcef9ac2009-09-17 01:35:28 -0700284
285 const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
Mathias Agopian3e63f912009-09-11 19:18:20 -0700286
Mathias Agopian9779b222009-09-07 16:32:45 -0700287 //LOGD("[%d] about to dequeue a buffer",
288 // mSharedStack->identity);
289 DequeueCondition condition(this);
290 status_t err = waitForCondition(condition);
291 if (err != NO_ERROR)
292 return ssize_t(err);
293
Mathias Agopian9779b222009-09-07 16:32:45 -0700294 // NOTE: 'stack.available' is part of the conditions, however
295 // decrementing it, never changes any conditions, so we don't need
296 // to do this as part of an update.
297 if (android_atomic_dec(&stack.available) == 0) {
298 LOGW("dequeue probably called from multiple threads!");
299 }
300
301 int dequeued = tail;
302 tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1);
303 LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail=%d, %s",
304 dequeued, tail, dump("").string());
Mathias Agopian3e63f912009-09-11 19:18:20 -0700305
Mathias Agopianbcef9ac2009-09-17 01:35:28 -0700306 mDequeueTime[dequeued] = dequeueTime;
307
Mathias Agopian9779b222009-09-07 16:32:45 -0700308 return dequeued;
309}
310
311status_t SharedBufferClient::undoDequeue(int buf)
312{
313 UndoDequeueUpdate update(this);
314 status_t err = updateCondition( update );
Mathias Agopianbd852712009-09-14 15:48:42 -0700315 if (err == NO_ERROR) {
316 tail = computeTail();
317 }
Mathias Agopian9779b222009-09-07 16:32:45 -0700318 return err;
319}
320
321status_t SharedBufferClient::lock(int buf)
322{
323 LockCondition condition(this, buf);
Mathias Agopianbcef9ac2009-09-17 01:35:28 -0700324 status_t err = waitForCondition(condition);
Mathias Agopian9779b222009-09-07 16:32:45 -0700325 return err;
326}
327
328status_t SharedBufferClient::queue(int buf)
329{
330 QueueUpdate update(this);
331 status_t err = updateCondition( update );
332 LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
Mathias Agopianbcef9ac2009-09-17 01:35:28 -0700333 SharedBufferStack& stack( *mSharedStack );
334 const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
335 stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
Mathias Agopian9779b222009-09-07 16:32:45 -0700336 return err;
337}
338
339bool SharedBufferClient::needNewBuffer(int buffer) const
340{
341 SharedBufferStack& stack( *mSharedStack );
342 const uint32_t mask = 1<<buffer;
343 return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0;
344}
345
346status_t SharedBufferClient::setDirtyRegion(int buffer, const Region& reg)
347{
348 SharedBufferStack& stack( *mSharedStack );
349 return stack.setDirtyRegion(buffer, reg);
350}
351
352// ----------------------------------------------------------------------------
353
354SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
Mathias Agopian248b5bd2009-09-10 19:41:18 -0700355 int surface, int num, int32_t identity)
Mathias Agopian4961c952009-10-06 19:00:57 -0700356 : SharedBufferBase(sharedClient, surface, num, identity)
Mathias Agopian9779b222009-09-07 16:32:45 -0700357{
Mathias Agopian248b5bd2009-09-10 19:41:18 -0700358 mSharedStack->init(identity);
Mathias Agopian9779b222009-09-07 16:32:45 -0700359 mSharedStack->head = num-1;
360 mSharedStack->available = num;
361 mSharedStack->queued = 0;
362 mSharedStack->reallocMask = 0;
363 memset(mSharedStack->dirtyRegion, 0, sizeof(mSharedStack->dirtyRegion));
364}
365
366ssize_t SharedBufferServer::retireAndLock()
367{
368 RetireUpdate update(this, mNumBuffers);
369 ssize_t buf = updateCondition( update );
Mathias Agopian3e63f912009-09-11 19:18:20 -0700370 LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s", int(buf), dump("").string());
Mathias Agopian9779b222009-09-07 16:32:45 -0700371 return buf;
372}
373
374status_t SharedBufferServer::unlock(int buffer)
375{
376 UnlockUpdate update(this, buffer);
377 status_t err = updateCondition( update );
378 return err;
379}
380
Mathias Agopian436c6272009-09-10 16:55:13 -0700381void SharedBufferServer::setStatus(status_t status)
382{
Mathias Agopian0c4cec72009-10-02 18:12:30 -0700383 if (status < NO_ERROR) {
384 StatusUpdate update(this, status);
385 updateCondition( update );
386 }
Mathias Agopian436c6272009-09-10 16:55:13 -0700387}
388
Mathias Agopian9779b222009-09-07 16:32:45 -0700389status_t SharedBufferServer::reallocate()
390{
391 SharedBufferStack& stack( *mSharedStack );
392 uint32_t mask = (1<<mNumBuffers)-1;
393 android_atomic_or(mask, &stack.reallocMask);
394 return NO_ERROR;
395}
396
Mathias Agopiane05f07d2009-10-07 16:44:10 -0700397int32_t SharedBufferServer::getQueuedCount() const
398{
399 SharedBufferStack& stack( *mSharedStack );
400 return stack.queued;
401}
402
Mathias Agopian9779b222009-09-07 16:32:45 -0700403status_t SharedBufferServer::assertReallocate(int buffer)
404{
405 ReallocateCondition condition(this, buffer);
406 status_t err = waitForCondition(condition);
407 return err;
408}
409
410Region SharedBufferServer::getDirtyRegion(int buffer) const
411{
412 SharedBufferStack& stack( *mSharedStack );
413 return stack.getDirtyRegion(buffer);
414}
415
Mathias Agopianbcef9ac2009-09-17 01:35:28 -0700416SharedBufferStack::Statistics SharedBufferServer::getStats() const
417{
418 SharedBufferStack& stack( *mSharedStack );
419 return stack.stats;
420}
421
422
Mathias Agopian9779b222009-09-07 16:32:45 -0700423// ---------------------------------------------------------------------------
424}; // namespace android