diff options
Diffstat (limited to 'libs/surfaceflinger_client')
-rw-r--r-- | libs/surfaceflinger_client/Android.mk | 2 | ||||
-rw-r--r-- | libs/surfaceflinger_client/ISurface.cpp | 30 | ||||
-rw-r--r-- | libs/surfaceflinger_client/ISurfaceComposer.cpp | 18 | ||||
-rw-r--r-- | libs/surfaceflinger_client/ISurfaceComposerClient.cpp (renamed from libs/surfaceflinger_client/ISurfaceFlingerClient.cpp) | 55 | ||||
-rw-r--r-- | libs/surfaceflinger_client/SharedBufferStack.cpp | 398 | ||||
-rw-r--r-- | libs/surfaceflinger_client/Surface.cpp | 511 | ||||
-rw-r--r-- | libs/surfaceflinger_client/SurfaceComposerClient.cpp | 403 | ||||
-rw-r--r-- | libs/surfaceflinger_client/tests/Android.mk | 1 | ||||
-rw-r--r-- | libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk | 17 | ||||
-rw-r--r-- | libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp | 279 |
10 files changed, 1192 insertions, 522 deletions
diff --git a/libs/surfaceflinger_client/Android.mk b/libs/surfaceflinger_client/Android.mk index fe85b34..ce3c71a 100644 --- a/libs/surfaceflinger_client/Android.mk +++ b/libs/surfaceflinger_client/Android.mk @@ -4,7 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ ISurfaceComposer.cpp \ ISurface.cpp \ - ISurfaceFlingerClient.cpp \ + ISurfaceComposerClient.cpp \ LayerState.cpp \ SharedBufferStack.cpp \ Surface.cpp \ diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/surfaceflinger_client/ISurface.cpp index bb86199..7049d9e 100644 --- a/libs/surfaceflinger_client/ISurface.cpp +++ b/libs/surfaceflinger_client/ISurface.cpp @@ -71,11 +71,15 @@ public: { } - virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) + virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(ISurface::getInterfaceDescriptor()); data.writeInt32(bufferIdx); + data.writeInt32(w); + data.writeInt32(h); + data.writeInt32(format); data.writeInt32(usage); remote()->transact(REQUEST_BUFFER, data, &reply); sp<GraphicBuffer> buffer = new GraphicBuffer(); @@ -83,6 +87,16 @@ public: return buffer; } + virtual status_t setBufferCount(int bufferCount) + { + Parcel data, reply; + data.writeInterfaceToken(ISurface::getInterfaceDescriptor()); + data.writeInt32(bufferCount); + remote()->transact(SET_BUFFER_COUNT, data, &reply); + status_t err = reply.readInt32(); + return err; + } + virtual status_t registerBuffers(const BufferHeap& buffers) { Parcel data, reply; @@ -140,12 +154,22 @@ status_t BnSurface::onTransact( case REQUEST_BUFFER: { CHECK_INTERFACE(ISurface, data, reply); int bufferIdx = data.readInt32(); - int usage = data.readInt32(); - sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage)); + uint32_t w = data.readInt32(); + uint32_t h = data.readInt32(); + uint32_t format = data.readInt32(); + uint32_t usage = data.readInt32(); + sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format, usage)); if (buffer == NULL) return BAD_VALUE; return reply->write(*buffer); } + case SET_BUFFER_COUNT: { + CHECK_INTERFACE(ISurface, data, reply); + int bufferCount = data.readInt32(); + status_t err = setBufferCount(bufferCount); + reply->writeInt32(err); + return NO_ERROR; + } case REGISTER_BUFFERS: { CHECK_INTERFACE(ISurface, data, reply); BufferHeap buffer; diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp index b6f4e24..5c111f6 100644 --- a/libs/surfaceflinger_client/ISurfaceComposer.cpp +++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp @@ -46,13 +46,22 @@ public: { } - virtual sp<ISurfaceFlingerClient> createConnection() + virtual sp<ISurfaceComposerClient> createConnection() { uint32_t n; Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply); - return interface_cast<ISurfaceFlingerClient>(reply.readStrongBinder()); + return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder()); + } + + virtual sp<ISurfaceComposerClient> createClientConnection() + { + uint32_t n; + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::CREATE_CLIENT_CONNECTION, data, &reply); + return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder()); } virtual sp<IMemoryHeap> getCblk() const @@ -136,6 +145,11 @@ status_t BnSurfaceComposer::onTransact( sp<IBinder> b = createConnection()->asBinder(); reply->writeStrongBinder(b); } break; + case CREATE_CLIENT_CONNECTION: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> b = createClientConnection()->asBinder(); + reply->writeStrongBinder(b); + } break; case OPEN_GLOBAL_TRANSACTION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); openGlobalTransaction(); diff --git a/libs/surfaceflinger_client/ISurfaceFlingerClient.cpp b/libs/surfaceflinger_client/ISurfaceComposerClient.cpp index def96d7..2cc1f8e 100644 --- a/libs/surfaceflinger_client/ISurfaceFlingerClient.cpp +++ b/libs/surfaceflinger_client/ISurfaceComposerClient.cpp @@ -30,7 +30,7 @@ #include <ui/Rect.h> #include <surfaceflinger/ISurface.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h> #include <private/surfaceflinger/LayerState.h> // --------------------------------------------------------------------------- @@ -51,27 +51,37 @@ namespace android { enum { GET_CBLK = IBinder::FIRST_CALL_TRANSACTION, + GET_TOKEN, CREATE_SURFACE, DESTROY_SURFACE, SET_STATE }; -class BpSurfaceFlingerClient : public BpInterface<ISurfaceFlingerClient> +class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient> { public: - BpSurfaceFlingerClient(const sp<IBinder>& impl) - : BpInterface<ISurfaceFlingerClient>(impl) + BpSurfaceComposerClient(const sp<IBinder>& impl) + : BpInterface<ISurfaceComposerClient>(impl) { } virtual sp<IMemoryHeap> getControlBlock() const { Parcel data, reply; - data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); + data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); remote()->transact(GET_CBLK, data, &reply); return interface_cast<IMemoryHeap>(reply.readStrongBinder()); } + virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); + data.writeStrongBinder(sur->asBinder()); + remote()->transact(GET_TOKEN, data, &reply); + return reply.readInt32(); + } + virtual sp<ISurface> createSurface( surface_data_t* params, int pid, const String8& name, @@ -82,7 +92,7 @@ public: uint32_t flags) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); + data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); data.writeInt32(pid); data.writeString8(name); data.writeInt32(display); @@ -94,11 +104,11 @@ public: params->readFromParcel(reply); return interface_cast<ISurface>(reply.readStrongBinder()); } - + virtual status_t destroySurface(SurfaceID sid) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); + data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); data.writeInt32(sid); remote()->transact(DESTROY_SURFACE, data, &reply); return reply.readInt32(); @@ -107,7 +117,7 @@ public: virtual status_t setState(int32_t count, const layer_state_t* states) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); + data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); data.writeInt32(count); for (int i=0 ; i<count ; i++) states[i].write(data); @@ -116,26 +126,33 @@ public: } }; -IMPLEMENT_META_INTERFACE(SurfaceFlingerClient, "android.ui.ISurfaceFlingerClient"); +IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient"); // ---------------------------------------------------------------------- -status_t BnSurfaceFlingerClient::onTransact( +status_t BnSurfaceComposerClient::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { // codes that don't require permission check switch(code) { case GET_CBLK: { - CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); + CHECK_INTERFACE(ISurfaceComposerClient, data, reply); sp<IMemoryHeap> ctl(getControlBlock()); reply->writeStrongBinder(ctl->asBinder()); return NO_ERROR; } break; + case GET_TOKEN: { + CHECK_INTERFACE(ISurfaceComposerClient, data, reply); + sp<ISurface> sur = interface_cast<ISurface>(data.readStrongBinder()); + ssize_t token = getTokenForSurface(sur); + reply->writeInt32(token); + return NO_ERROR; + } break; } // these must be checked - + IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); @@ -150,10 +167,10 @@ status_t BnSurfaceFlingerClient::onTransact( return PERMISSION_DENIED; } } - + switch(code) { case CREATE_SURFACE: { - CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); + CHECK_INTERFACE(ISurfaceComposerClient, data, reply); surface_data_t params; int32_t pid = data.readInt32(); String8 name = data.readString8(); @@ -169,12 +186,12 @@ status_t BnSurfaceFlingerClient::onTransact( return NO_ERROR; } break; case DESTROY_SURFACE: { - CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); + CHECK_INTERFACE(ISurfaceComposerClient, data, reply); reply->writeInt32( destroySurface( data.readInt32() ) ); return NO_ERROR; } break; case SET_STATE: { - CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); + CHECK_INTERFACE(ISurfaceComposerClient, data, reply); int32_t count = data.readInt32(); layer_state_t* states = new layer_state_t[count]; for (int i=0 ; i<count ; i++) @@ -191,7 +208,7 @@ status_t BnSurfaceFlingerClient::onTransact( // ---------------------------------------------------------------------- -status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& parcel) +status_t ISurfaceComposerClient::surface_data_t::readFromParcel(const Parcel& parcel) { token = parcel.readInt32(); identity = parcel.readInt32(); @@ -201,7 +218,7 @@ status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& par return NO_ERROR; } -status_t ISurfaceFlingerClient::surface_data_t::writeToParcel(Parcel* parcel) const +status_t ISurfaceComposerClient::surface_data_t::writeToParcel(Parcel* parcel) const { parcel->writeInt32(token); parcel->writeInt32(identity); diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp index a17e8ac..d67a589 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/surfaceflinger_client/SharedBufferStack.cpp @@ -44,15 +44,11 @@ SharedClient::~SharedClient() { // these functions are used by the clients status_t SharedClient::validate(size_t i) const { - if (uint32_t(i) >= uint32_t(NUM_LAYERS_MAX)) + if (uint32_t(i) >= uint32_t(SharedBufferStack::NUM_LAYERS_MAX)) return BAD_INDEX; return surfaces[i].status; } -uint32_t SharedClient::getIdentity(size_t token) const { - return uint32_t(surfaces[token].identity); -} - // ---------------------------------------------------------------------------- @@ -62,24 +58,52 @@ SharedBufferStack::SharedBufferStack() void SharedBufferStack::init(int32_t i) { - inUse = -1; + inUse = -2; status = NO_ERROR; identity = i; } +status_t SharedBufferStack::setCrop(int buffer, const Rect& crop) +{ + if (uint32_t(buffer) >= NUM_BUFFER_MAX) + return BAD_INDEX; + + buffers[buffer].crop.l = uint16_t(crop.left); + buffers[buffer].crop.t = uint16_t(crop.top); + buffers[buffer].crop.r = uint16_t(crop.right); + buffers[buffer].crop.b = uint16_t(crop.bottom); + return NO_ERROR; +} + status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty) { if (uint32_t(buffer) >= NUM_BUFFER_MAX) return BAD_INDEX; - // in the current implementation we only send a single rectangle - const Rect bounds(dirty.getBounds()); - FlatRegion& reg(dirtyRegion[buffer]); - reg.count = 1; - reg.rects[0] = uint16_t(bounds.left); - reg.rects[1] = uint16_t(bounds.top); - reg.rects[2] = uint16_t(bounds.right); - reg.rects[3] = uint16_t(bounds.bottom); + FlatRegion& reg(buffers[buffer].dirtyRegion); + if (dirty.isEmpty()) { + reg.count = 0; + return NO_ERROR; + } + + size_t count; + Rect const* r = dirty.getArray(&count); + if (count > FlatRegion::NUM_RECT_MAX) { + const Rect bounds(dirty.getBounds()); + reg.count = 1; + reg.rects[0].l = uint16_t(bounds.left); + reg.rects[0].t = uint16_t(bounds.top); + reg.rects[0].r = uint16_t(bounds.right); + reg.rects[0].b = uint16_t(bounds.bottom); + } else { + reg.count = count; + for (size_t i=0 ; i<count ; i++) { + reg.rects[i].l = uint16_t(r[i].left); + reg.rects[i].t = uint16_t(r[i].top); + reg.rects[i].r = uint16_t(r[i].right); + reg.rects[i].b = uint16_t(r[i].bottom); + } + } return NO_ERROR; } @@ -89,18 +113,37 @@ Region SharedBufferStack::getDirtyRegion(int buffer) const if (uint32_t(buffer) >= NUM_BUFFER_MAX) return res; - const FlatRegion& reg(dirtyRegion[buffer]); - res.set(Rect(reg.rects[0], reg.rects[1], reg.rects[2], reg.rects[3])); + const FlatRegion& reg(buffers[buffer].dirtyRegion); + if (reg.count > FlatRegion::NUM_RECT_MAX) + return res; + + if (reg.count == 1) { + const Rect r( + reg.rects[0].l, + reg.rects[0].t, + reg.rects[0].r, + reg.rects[0].b); + res.set(r); + } else { + for (size_t i=0 ; i<reg.count ; i++) { + const Rect r( + reg.rects[i].l, + reg.rects[i].t, + reg.rects[i].r, + reg.rects[i].b); + res.orSelf(r); + } + } return res; } // ---------------------------------------------------------------------------- SharedBufferBase::SharedBufferBase(SharedClient* sharedClient, - int surface, int num, int32_t identity) + int surface, int32_t identity) : mSharedClient(sharedClient), mSharedStack(sharedClient->surfaces + surface), - mNumBuffers(num), mIdentity(identity) + mIdentity(identity) { } @@ -108,16 +151,16 @@ SharedBufferBase::~SharedBufferBase() { } -uint32_t SharedBufferBase::getIdentity() +status_t SharedBufferBase::getStatus() const { SharedBufferStack& stack( *mSharedStack ); - return stack.identity; + return stack.status; } -status_t SharedBufferBase::getStatus() const +int32_t SharedBufferBase::getIdentity() const { SharedBufferStack& stack( *mSharedStack ); - return stack.status; + return stack.identity; } size_t SharedBufferBase::getFrontBuffer() const @@ -132,16 +175,52 @@ String8 SharedBufferBase::dump(char const* prefix) const char buffer[SIZE]; String8 result; SharedBufferStack& stack( *mSharedStack ); - int tail = (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers; snprintf(buffer, SIZE, - "%s[ head=%2d, available=%2d, queued=%2d, tail=%2d ] " - "reallocMask=%08x, inUse=%2d, identity=%d, status=%d\n", - prefix, stack.head, stack.available, stack.queued, tail, + "%s[ head=%2d, available=%2d, queued=%2d ] " + "reallocMask=%08x, inUse=%2d, identity=%d, status=%d", + prefix, stack.head, stack.available, stack.queued, stack.reallocMask, stack.inUse, stack.identity, stack.status); result.append(buffer); + result.append("\n"); return result; } +status_t SharedBufferBase::waitForCondition(const ConditionBase& condition) +{ + const SharedBufferStack& stack( *mSharedStack ); + SharedClient& client( *mSharedClient ); + const nsecs_t TIMEOUT = s2ns(1); + const int identity = mIdentity; + + Mutex::Autolock _l(client.lock); + while ((condition()==false) && + (stack.identity == identity) && + (stack.status == NO_ERROR)) + { + status_t err = client.cv.waitRelative(client.lock, TIMEOUT); + // handle errors and timeouts + if (CC_UNLIKELY(err != NO_ERROR)) { + if (err == TIMED_OUT) { + if (condition()) { + LOGE("waitForCondition(%s) timed out (identity=%d), " + "but condition is true! We recovered but it " + "shouldn't happen." , condition.name(), stack.identity); + break; + } else { + LOGW("waitForCondition(%s) timed out " + "(identity=%d, status=%d). " + "CPU may be pegged. trying again.", condition.name(), + stack.identity, stack.status); + } + } else { + LOGE("waitForCondition(%s) error (%s) ", + condition.name(), strerror(-err)); + return err; + } + } + } + return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status; +} // ============================================================================ // conditions and updates // ============================================================================ @@ -149,24 +228,34 @@ String8 SharedBufferBase::dump(char const* prefix) const SharedBufferClient::DequeueCondition::DequeueCondition( SharedBufferClient* sbc) : ConditionBase(sbc) { } -bool SharedBufferClient::DequeueCondition::operator()() { +bool SharedBufferClient::DequeueCondition::operator()() const { return stack.available > 0; } SharedBufferClient::LockCondition::LockCondition( SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) { } -bool SharedBufferClient::LockCondition::operator()() { - return (buf != stack.head || +bool SharedBufferClient::LockCondition::operator()() const { + // NOTE: if stack.head is messed up, we could crash the client + // or cause some drawing artifacts. This is okay, as long as it is + // limited to the client. + return (buf != stack.index[stack.head] || (stack.queued > 0 && stack.inUse != buf)); } SharedBufferServer::ReallocateCondition::ReallocateCondition( SharedBufferBase* sbb, int buf) : ConditionBase(sbb), buf(buf) { } -bool SharedBufferServer::ReallocateCondition::operator()() { +bool SharedBufferServer::ReallocateCondition::operator()() const { + int32_t head = stack.head; + if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX) { + // if stack.head is messed up, we cannot allow the server to + // crash (since stack.head is mapped on the client side) + stack.status = BAD_VALUE; + return false; + } // TODO: we should also check that buf has been dequeued - return (buf != stack.head); + return (buf != stack.index[head]); } // ---------------------------------------------------------------------------- @@ -193,8 +282,10 @@ SharedBufferServer::UnlockUpdate::UnlockUpdate( } ssize_t SharedBufferServer::UnlockUpdate::operator()() { if (stack.inUse != lockedBuffer) { - LOGE("unlocking %d, but currently locked buffer is %d", - lockedBuffer, stack.inUse); + LOGE("unlocking %d, but currently locked buffer is %d " + "(identity=%d, token=%d)", + lockedBuffer, stack.inUse, + stack.identity, stack.token); return BAD_VALUE; } android_atomic_write(-1, &stack.inUse); @@ -206,11 +297,12 @@ SharedBufferServer::RetireUpdate::RetireUpdate( : UpdateBase(sbb), numBuffers(numBuffers) { } ssize_t SharedBufferServer::RetireUpdate::operator()() { - // head is only written in this function, which is single-thread. int32_t head = stack.head; + if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX) + return BAD_VALUE; // Preventively lock the current buffer before updating queued. - android_atomic_write(head, &stack.inUse); + android_atomic_write(stack.index[head], &stack.inUse); // Decrement the number of queued buffers int32_t queued; @@ -221,16 +313,15 @@ ssize_t SharedBufferServer::RetireUpdate::operator()() { } } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued)); - // update the head pointer - head = ((head+1 >= numBuffers) ? 0 : head+1); - // lock the buffer before advancing head, which automatically unlocks // the buffer we preventively locked upon entering this function - android_atomic_write(head, &stack.inUse); - // advance head + head = (head + 1) % numBuffers; + android_atomic_write(stack.index[head], &stack.inUse); + + // head is only modified here, so we don't need to use cmpxchg android_atomic_write(head, &stack.head); - + // now that head has moved, we can increment the number of available buffers android_atomic_inc(&stack.available); return head; @@ -250,41 +341,31 @@ ssize_t SharedBufferServer::StatusUpdate::operator()() { SharedBufferClient::SharedBufferClient(SharedClient* sharedClient, int surface, int num, int32_t identity) - : SharedBufferBase(sharedClient, surface, num, identity), tail(0) + : SharedBufferBase(sharedClient, surface, identity), + mNumBuffers(num), tail(0), undoDequeueTail(0) { + SharedBufferStack& stack( *mSharedStack ); tail = computeTail(); + queued_head = stack.head; } int32_t SharedBufferClient::computeTail() const { SharedBufferStack& stack( *mSharedStack ); - // we need to make sure we read available and head coherently, - // w.r.t RetireUpdate. - int32_t newTail; - int32_t avail; - int32_t head; - do { - avail = stack.available; - head = stack.head; - } while (stack.available != avail); - newTail = head - avail + 1; - if (newTail < 0) { - newTail += mNumBuffers; - } else if (newTail >= mNumBuffers) { - newTail -= mNumBuffers; - } - return newTail; + return (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers; } ssize_t SharedBufferClient::dequeue() { SharedBufferStack& stack( *mSharedStack ); - if (stack.head == tail && stack.available == 2) { + if (stack.head == tail && stack.available == mNumBuffers) { LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d", tail, stack.head, stack.available, stack.queued); } - + + RWLock::AutoRLock _rd(mLock); + const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD); //LOGD("[%d] about to dequeue a buffer", @@ -301,9 +382,10 @@ ssize_t SharedBufferClient::dequeue() LOGW("dequeue probably called from multiple threads!"); } - int dequeued = tail; + undoDequeueTail = tail; + int dequeued = stack.index[tail]; tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1); - LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail=%d, %s", + LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail++=%d, %s", dequeued, tail, dump("").string()); mDequeueTime[dequeued] = dequeueTime; @@ -313,16 +395,23 @@ ssize_t SharedBufferClient::dequeue() status_t SharedBufferClient::undoDequeue(int buf) { + RWLock::AutoRLock _rd(mLock); + + // TODO: we can only undo the previous dequeue, we should + // enforce that in the api UndoDequeueUpdate update(this); status_t err = updateCondition( update ); if (err == NO_ERROR) { - tail = computeTail(); + tail = undoDequeueTail; } return err; } status_t SharedBufferClient::lock(int buf) { + RWLock::AutoRLock _rd(mLock); + + SharedBufferStack& stack( *mSharedStack ); LockCondition condition(this, buf); status_t err = waitForCondition(condition); return err; @@ -330,53 +419,105 @@ status_t SharedBufferClient::lock(int buf) status_t SharedBufferClient::queue(int buf) { + RWLock::AutoRLock _rd(mLock); + + SharedBufferStack& stack( *mSharedStack ); + + queued_head = (queued_head + 1) % mNumBuffers; + stack.index[queued_head] = buf; + QueueUpdate update(this); status_t err = updateCondition( update ); LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string()); - SharedBufferStack& stack( *mSharedStack ); + const nsecs_t now = systemTime(SYSTEM_TIME_THREAD); stack.stats.totalTime = ns2us(now - mDequeueTime[buf]); return err; } -bool SharedBufferClient::needNewBuffer(int buffer) const +bool SharedBufferClient::needNewBuffer(int buf) const { SharedBufferStack& stack( *mSharedStack ); - const uint32_t mask = 1<<buffer; + const uint32_t mask = 1<<(31-buf); return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0; } -status_t SharedBufferClient::setDirtyRegion(int buffer, const Region& reg) +status_t SharedBufferClient::setCrop(int buf, const Rect& crop) { SharedBufferStack& stack( *mSharedStack ); - return stack.setDirtyRegion(buffer, reg); + return stack.setCrop(buf, crop); +} + +status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg) +{ + SharedBufferStack& stack( *mSharedStack ); + return stack.setDirtyRegion(buf, reg); +} + +status_t SharedBufferClient::setBufferCount( + int bufferCount, const SetBufferCountCallback& ipc) +{ + SharedBufferStack& stack( *mSharedStack ); + if (uint32_t(bufferCount) >= SharedBufferStack::NUM_BUFFER_MAX) + return BAD_VALUE; + + if (uint32_t(bufferCount) < SharedBufferStack::NUM_BUFFER_MIN) + return BAD_VALUE; + + RWLock::AutoWLock _wr(mLock); + + status_t err = ipc(bufferCount); + if (err == NO_ERROR) { + mNumBuffers = bufferCount; + queued_head = (stack.head + stack.queued) % mNumBuffers; + } + return err; } // ---------------------------------------------------------------------------- SharedBufferServer::SharedBufferServer(SharedClient* sharedClient, int surface, int num, int32_t identity) - : SharedBufferBase(sharedClient, surface, num, identity) + : SharedBufferBase(sharedClient, surface, identity), + mNumBuffers(num) { mSharedStack->init(identity); + mSharedStack->token = surface; mSharedStack->head = num-1; mSharedStack->available = num; mSharedStack->queued = 0; mSharedStack->reallocMask = 0; - memset(mSharedStack->dirtyRegion, 0, sizeof(mSharedStack->dirtyRegion)); + memset(mSharedStack->buffers, 0, sizeof(mSharedStack->buffers)); + for (int i=0 ; i<num ; i++) { + mBufferList.add(i); + mSharedStack->index[i] = i; + } +} + +SharedBufferServer::~SharedBufferServer() +{ } ssize_t SharedBufferServer::retireAndLock() { + RWLock::AutoRLock _l(mLock); + RetireUpdate update(this, mNumBuffers); ssize_t buf = updateCondition( update ); - LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s", int(buf), dump("").string()); + if (buf >= 0) { + if (uint32_t(buf) >= SharedBufferStack::NUM_BUFFER_MAX) + return BAD_VALUE; + SharedBufferStack& stack( *mSharedStack ); + buf = stack.index[buf]; + LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s", + int(buf), dump("").string()); + } return buf; } -status_t SharedBufferServer::unlock(int buffer) +status_t SharedBufferServer::unlock(int buf) { - UnlockUpdate update(this, buffer); + UnlockUpdate update(this, buf); status_t err = updateCondition( update ); return err; } @@ -389,11 +530,25 @@ void SharedBufferServer::setStatus(status_t status) } } -status_t SharedBufferServer::reallocate() +status_t SharedBufferServer::reallocateAll() { + RWLock::AutoRLock _l(mLock); + SharedBufferStack& stack( *mSharedStack ); - uint32_t mask = (1<<mNumBuffers)-1; - android_atomic_or(mask, &stack.reallocMask); + uint32_t mask = mBufferList.getMask(); + android_atomic_or(mask, &stack.reallocMask); + return NO_ERROR; +} + +status_t SharedBufferServer::reallocateAllExcept(int buffer) +{ + RWLock::AutoRLock _l(mLock); + + SharedBufferStack& stack( *mSharedStack ); + BufferList temp(mBufferList); + temp.remove(buffer); + uint32_t mask = temp.getMask(); + android_atomic_or(mask, &stack.reallocMask); return NO_ERROR; } @@ -403,17 +558,77 @@ int32_t SharedBufferServer::getQueuedCount() const return stack.queued; } -status_t SharedBufferServer::assertReallocate(int buffer) +status_t SharedBufferServer::assertReallocate(int buf) { - ReallocateCondition condition(this, buffer); + /* + * NOTE: it's safe to hold mLock for read while waiting for + * the ReallocateCondition because that condition is not updated + * by the thread that holds mLock for write. + */ + RWLock::AutoRLock _l(mLock); + + // TODO: need to validate "buf" + ReallocateCondition condition(this, buf); status_t err = waitForCondition(condition); return err; } -Region SharedBufferServer::getDirtyRegion(int buffer) const +Region SharedBufferServer::getDirtyRegion(int buf) const +{ + SharedBufferStack& stack( *mSharedStack ); + return stack.getDirtyRegion(buf); +} + +/* + * NOTE: this is not thread-safe on the server-side, meaning + * 'head' cannot move during this operation. The client-side + * can safely operate an usual. + * + */ +status_t SharedBufferServer::resize(int newNumBuffers) { + if (uint32_t(newNumBuffers) >= SharedBufferStack::NUM_BUFFER_MAX) + return BAD_VALUE; + + RWLock::AutoWLock _l(mLock); + + // for now we're not supporting shrinking + const int numBuffers = mNumBuffers; + if (newNumBuffers < numBuffers) + return BAD_VALUE; + SharedBufferStack& stack( *mSharedStack ); - return stack.getDirtyRegion(buffer); + const int extra = newNumBuffers - numBuffers; + + // read the head, make sure it's valid + int32_t head = stack.head; + if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX) + return BAD_VALUE; + + int base = numBuffers; + int32_t avail = stack.available; + int tail = head - avail + 1; + + if (tail >= 0) { + int8_t* const index = const_cast<int8_t*>(stack.index); + const int nb = numBuffers - head; + memmove(&index[head + extra], &index[head], nb); + base = head; + // move head 'extra' ahead, this doesn't impact stack.index[head]; + stack.head = head + extra; + } + stack.available += extra; + + // fill the new free space with unused buffers + BufferList::const_iterator curr(mBufferList.free_begin()); + for (int i=0 ; i<extra ; i++) { + stack.index[base+i] = *curr; + mBufferList.add(*curr); + ++curr; + } + + mNumBuffers = newNumBuffers; + return NO_ERROR; } SharedBufferStack::Statistics SharedBufferServer::getStats() const @@ -422,6 +637,29 @@ SharedBufferStack::Statistics SharedBufferServer::getStats() const return stack.stats; } +// --------------------------------------------------------------------------- +status_t SharedBufferServer::BufferList::add(int value) +{ + if (uint32_t(value) >= mCapacity) + return BAD_VALUE; + uint32_t mask = 1<<(31-value); + if (mList & mask) + return ALREADY_EXISTS; + mList |= mask; + return NO_ERROR; +} + +status_t SharedBufferServer::BufferList::remove(int value) +{ + if (uint32_t(value) >= mCapacity) + return BAD_VALUE; + uint32_t mask = 1<<(31-value); + if (!(mList & mask)) + return NAME_NOT_FOUND; + mList &= ~mask; + return NO_ERROR; +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index 5dd75c3..8617d94 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -17,8 +17,6 @@ #define LOG_TAG "Surface" #include <stdint.h> -#include <unistd.h> -#include <fcntl.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> @@ -28,8 +26,6 @@ #include <utils/CallStack.h> #include <utils/Log.h> -#include <pixelflinger/pixelflinger.h> - #include <binder/IPCThreadState.h> #include <binder/IMemory.h> @@ -55,6 +51,8 @@ static status_t copyBlt( const sp<GraphicBuffer>& src, const Region& reg) { + // src and dst with, height and format must be identical. no verification + // is done here. status_t err; uint8_t const * src_bits = NULL; err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits); @@ -67,7 +65,6 @@ static status_t copyBlt( Region::const_iterator head(reg.begin()); Region::const_iterator tail(reg.end()); if (head != tail && src_bits && dst_bits) { - // NOTE: dst and src must be the same format const size_t bpp = bytesPerPixel(src->format); const size_t dbpr = dst->stride * bpp; const size_t sbpr = src->stride * bpp; @@ -107,7 +104,7 @@ static status_t copyBlt( SurfaceControl::SurfaceControl( const sp<SurfaceComposerClient>& client, const sp<ISurface>& surface, - const ISurfaceFlingerClient::surface_data_t& data, + const ISurfaceComposerClient::surface_data_t& data, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) : mClient(client), mSurface(surface), mToken(data.token), mIdentity(data.identity), @@ -154,75 +151,75 @@ bool SurfaceControl::isSameSurface( } status_t SurfaceControl::setLayer(int32_t layer) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setLayer(mToken, layer); } status_t SurfaceControl::setPosition(int32_t x, int32_t y) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setPosition(mToken, x, y); } status_t SurfaceControl::setSize(uint32_t w, uint32_t h) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setSize(mToken, w, h); } status_t SurfaceControl::hide() { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->hide(mToken); } status_t SurfaceControl::show(int32_t layer) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->show(mToken, layer); } status_t SurfaceControl::freeze() { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->freeze(mToken); } status_t SurfaceControl::unfreeze() { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->unfreeze(mToken); } status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setFlags(mToken, flags, mask); } status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setTransparentRegionHint(mToken, transparent); } status_t SurfaceControl::setAlpha(float alpha) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setAlpha(mToken, alpha); } status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setMatrix(mToken, dsdx, dtdx, dsdy, dtdy); } status_t SurfaceControl::setFreezeTint(uint32_t tint) { - const sp<SurfaceComposerClient>& client(mClient); status_t err = validate(); if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); return client->setFreezeTint(mToken, tint); } @@ -233,50 +230,27 @@ status_t SurfaceControl::validate() const mToken, mIdentity, mClient.get()); return NO_INIT; } - SharedClient const* cblk = mClient->mControl; - if (cblk == 0) { - LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity); - return NO_INIT; - } - status_t err = cblk->validate(mToken); - if (err != NO_ERROR) { - LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)", - mToken, mIdentity, err, strerror(-err)); - return err; - } - uint32_t identity = cblk->getIdentity(mToken); - if (mIdentity != identity) { - LOGE("using an invalid surface id=%d, identity=%u should be %d", - mToken, mIdentity, identity); - return NO_INIT; - } return NO_ERROR; } status_t SurfaceControl::writeSurfaceToParcel( const sp<SurfaceControl>& control, Parcel* parcel) { - uint32_t flags = 0; - uint32_t format = 0; - SurfaceID token = -1; + sp<ISurface> sur; uint32_t identity = 0; uint32_t width = 0; uint32_t height = 0; - sp<SurfaceComposerClient> client; - sp<ISurface> sur; + uint32_t format = 0; + uint32_t flags = 0; if (SurfaceControl::isValid(control)) { - token = control->mToken; - identity = control->mIdentity; - client = control->mClient; sur = control->mSurface; + identity = control->mIdentity; width = control->mWidth; height = control->mHeight; format = control->mFormat; flags = control->mFlags; } - parcel->writeStrongBinder(client!=0 ? client->connection() : NULL); - parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL); - parcel->writeInt32(token); + parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL); parcel->writeInt32(identity); parcel->writeInt32(width); parcel->writeInt32(height); @@ -298,40 +272,117 @@ sp<Surface> SurfaceControl::getSurface() const // Surface // ============================================================================ +class SurfaceClient : public Singleton<SurfaceClient> +{ + // all these attributes are constants + sp<ISurfaceComposer> mComposerService; + sp<ISurfaceComposerClient> mClient; + status_t mStatus; + SharedClient* mControl; + sp<IMemoryHeap> mControlMemory; + + SurfaceClient() + : Singleton<SurfaceClient>(), mStatus(NO_INIT) + { + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + mComposerService = sf; + mClient = sf->createClientConnection(); + if (mClient != NULL) { + mControlMemory = mClient->getControlBlock(); + if (mControlMemory != NULL) { + mControl = static_cast<SharedClient *>( + mControlMemory->getBase()); + if (mControl) { + mStatus = NO_ERROR; + } + } + } + } + friend class Singleton<SurfaceClient>; +public: + status_t initCheck() const { + return mStatus; + } + SharedClient* getSharedClient() const { + return mControl; + } + ssize_t getTokenForSurface(const sp<ISurface>& sur) const { + // TODO: we could cache a few tokens here to avoid an IPC + return mClient->getTokenForSurface(sur); + } + void signalServer() const { + mComposerService->signal(); + } +}; + +ANDROID_SINGLETON_STATIC_INSTANCE(SurfaceClient); + +// --------------------------------------------------------------------------- + Surface::Surface(const sp<SurfaceControl>& surface) - : mClient(surface->mClient), mSurface(surface->mSurface), - mToken(surface->mToken), mIdentity(surface->mIdentity), + : mBufferMapper(GraphicBufferMapper::get()), + mClient(SurfaceClient::getInstance()), + mSharedBufferClient(NULL), + mInitCheck(NO_INIT), + mSurface(surface->mSurface), + mIdentity(surface->mIdentity), mFormat(surface->mFormat), mFlags(surface->mFlags), - mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL), mWidth(surface->mWidth), mHeight(surface->mHeight) { - mSharedBufferClient = new SharedBufferClient( - mClient->mControl, mToken, 2, mIdentity); - init(); } -Surface::Surface(const Parcel& parcel) - : mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL) +Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref) + : mBufferMapper(GraphicBufferMapper::get()), + mClient(SurfaceClient::getInstance()), + mSharedBufferClient(NULL), + mInitCheck(NO_INIT) { - sp<IBinder> clientBinder = parcel.readStrongBinder(); - mSurface = interface_cast<ISurface>(parcel.readStrongBinder()); - mToken = parcel.readInt32(); + mSurface = interface_cast<ISurface>(ref); mIdentity = parcel.readInt32(); mWidth = parcel.readInt32(); mHeight = parcel.readInt32(); mFormat = parcel.readInt32(); mFlags = parcel.readInt32(); + init(); +} + +status_t Surface::writeToParcel( + const sp<Surface>& surface, Parcel* parcel) +{ + sp<ISurface> sur; + uint32_t identity = 0; + uint32_t width = 0; + uint32_t height = 0; + uint32_t format = 0; + uint32_t flags = 0; + if (Surface::isValid(surface)) { + sur = surface->mSurface; + identity = surface->mIdentity; + width = surface->mWidth; + height = surface->mHeight; + format = surface->mFormat; + flags = surface->mFlags; + } + parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL); + parcel->writeInt32(identity); + parcel->writeInt32(width); + parcel->writeInt32(height); + parcel->writeInt32(format); + parcel->writeInt32(flags); + return NO_ERROR; - // FIXME: what does that mean if clientBinder is NULL here? - if (clientBinder != NULL) { - mClient = SurfaceComposerClient::clientForConnection(clientBinder); +} - mSharedBufferClient = new SharedBufferClient( - mClient->mControl, mToken, 2, mIdentity); +sp<Surface> Surface::readFromParcel( + const Parcel& data, const sp<Surface>& other) +{ + sp<Surface> result(other); + sp<IBinder> binder(data.readStrongBinder()); + if (other==0 || binder != other->mSurface->asBinder()) { + result = new Surface(data, binder); } - - init(); + return result; } void Surface::init() @@ -342,7 +393,7 @@ void Surface::init() android_native_window_t::queueBuffer = queueBuffer; android_native_window_t::query = query; android_native_window_t::perform = perform; - mSwapRectangle.makeInvalid(); + DisplayInfo dinfo; SurfaceComposerClient::getDisplayInfo(0, &dinfo); const_cast<float&>(android_native_window_t::xdpi) = dinfo.xdpi; @@ -351,17 +402,29 @@ void Surface::init() const_cast<int&>(android_native_window_t::minSwapInterval) = 1; const_cast<int&>(android_native_window_t::maxSwapInterval) = 1; const_cast<uint32_t&>(android_native_window_t::flags) = 0; - // be default we request a hardware surface - mUsage = GRALLOC_USAGE_HW_RENDER; + mConnected = 0; - mNeedFullUpdate = false; + mSwapRectangle.makeInvalid(); + // two buffers by default + mBuffers.setCapacity(2); + mBuffers.insertAt(0, 2); + + if (mSurface != 0 && mClient.initCheck() == NO_ERROR) { + int32_t token = mClient.getTokenForSurface(mSurface); + if (token >= 0) { + mSharedBufferClient = new SharedBufferClient( + mClient.getSharedClient(), token, 2, mIdentity); + mInitCheck = mClient.getSharedClient()->validate(token); + } + } } Surface::~Surface() { // this is a client-side operation, the surface is destroyed, unmap // its buffers in this process. - for (int i=0 ; i<2 ; i++) { + size_t size = mBuffers.size(); + for (size_t i=0 ; i<size ; i++) { if (mBuffers[i] != 0 && mBuffers[i]->handle != 0) { getBufferMapper().unregisterBuffer(mBuffers[i]->handle); } @@ -369,60 +432,55 @@ Surface::~Surface() // clear all references and trigger an IPC now, to make sure things // happen without delay, since these resources are quite heavy. - mClient.clear(); + mBuffers.clear(); mSurface.clear(); delete mSharedBufferClient; IPCThreadState::self()->flushCommands(); } -sp<SurfaceComposerClient> Surface::getClient() const { - return mClient; -} - -sp<ISurface> Surface::getISurface() const { - return mSurface; -} - bool Surface::isValid() { - return mToken>=0 && mClient!=0; + return mInitCheck == NO_ERROR; } status_t Surface::validate() const { - sp<SurfaceComposerClient> client(getClient()); - if (mToken<0 || mClient==0) { - LOGE("invalid token (%d, identity=%u) or client (%p)", - mToken, mIdentity, client.get()); - return NO_INIT; + // check that we initialized ourself properly + if (mInitCheck != NO_ERROR) { + LOGE("invalid token (identity=%u)", mIdentity); + return mInitCheck; + } + + // verify the identity of this surface + uint32_t identity = mSharedBufferClient->getIdentity(); + + // this is a bit of a (temporary) special case, identity==0 means that + // no operation are allowed from the client (eg: dequeue/queue), this + // is used with PUSH_BUFFER surfaces for instance + if (identity == 0) { + LOGE("[Surface] invalid operation (identity=%u)", mIdentity); + return INVALID_OPERATION; } - SharedClient const* cblk = mClient->mControl; - if (cblk == 0) { - LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity); + + if (mIdentity != identity) { + LOGE("[Surface] using an invalid surface, " + "identity=%u should be %d", + mIdentity, identity); return NO_INIT; } - status_t err = cblk->validate(mToken); + + // check the surface didn't become invalid + status_t err = mSharedBufferClient->getStatus(); if (err != NO_ERROR) { - LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)", - mToken, mIdentity, err, strerror(-err)); + LOGE("surface (identity=%u) is invalid, err=%d (%s)", + mIdentity, err, strerror(-err)); return err; } - uint32_t identity = cblk->getIdentity(mToken); - if (mIdentity != identity) { - LOGE("using an invalid surface id=%d, identity=%u should be %d", - mToken, mIdentity, identity); - return NO_INIT; - } + return NO_ERROR; } - -bool Surface::isSameSurface( - const sp<Surface>& lhs, const sp<Surface>& rhs) -{ - if (lhs == 0 || rhs == 0) - return false; - - return lhs->mSurface->asBinder() == rhs->mSurface->asBinder(); +sp<ISurface> Surface::getISurface() const { + return mSurface; } // ---------------------------------------------------------------------------- @@ -467,21 +525,24 @@ int Surface::perform(android_native_window_t* window, // ---------------------------------------------------------------------------- -status_t Surface::dequeueBuffer(sp<GraphicBuffer>* buffer) { - android_native_buffer_t* out; - status_t err = dequeueBuffer(&out); - if (err == NO_ERROR) { - *buffer = GraphicBuffer::getSelf(out); +bool Surface::needNewBuffer(int bufIdx, + uint32_t *pWidth, uint32_t *pHeight, + uint32_t *pFormat, uint32_t *pUsage) const +{ + Mutex::Autolock _l(mSurfaceLock); + + // Always call needNewBuffer(), since it clears the needed buffers flags + bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx); + bool validBuffer = mBufferInfo.validateBuffer(mBuffers[bufIdx]); + bool newNeewBuffer = needNewBuffer || !validBuffer; + if (newNeewBuffer) { + mBufferInfo.get(pWidth, pHeight, pFormat, pUsage); } - return err; + return newNeewBuffer; } -// ---------------------------------------------------------------------------- - - int Surface::dequeueBuffer(android_native_buffer_t** buffer) { - sp<SurfaceComposerClient> client(getClient()); status_t err = validate(); if (err != NO_ERROR) return err; @@ -492,24 +553,28 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer) return bufIdx; } - // below we make sure we AT LEAST have the usage flags we want - const uint32_t usage(getUsage()); - const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]); - if (backBuffer == 0 || - ((uint32_t(backBuffer->usage) & usage) != usage) || - mSharedBufferClient->needNewBuffer(bufIdx)) - { - err = getBufferLocked(bufIdx, usage); - LOGE_IF(err, "getBufferLocked(%ld, %08x) failed (%s)", - bufIdx, usage, strerror(-err)); + // grow the buffer array if needed + const size_t size = mBuffers.size(); + const size_t needed = bufIdx+1; + if (size < needed) { + mBuffers.insertAt(size, needed-size); + } + + uint32_t w, h, format, usage; + if (needNewBuffer(bufIdx, &w, &h, &format, &usage)) { + err = getBufferLocked(bufIdx, w, h, format, usage); + LOGE_IF(err, "getBufferLocked(%ld, %u, %u, %u, %08x) failed (%s)", + bufIdx, w, h, format, usage, strerror(-err)); if (err == NO_ERROR) { // reset the width/height with the what we get from the buffer + const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]); mWidth = uint32_t(backBuffer->width); mHeight = uint32_t(backBuffer->height); } } // if we still don't have a buffer here, we probably ran out of memory + const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]); if (!err && backBuffer==0) { err = NO_MEMORY; } @@ -526,12 +591,11 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer) int Surface::lockBuffer(android_native_buffer_t* buffer) { - sp<SurfaceComposerClient> client(getClient()); status_t err = validate(); if (err != NO_ERROR) return err; - int32_t bufIdx = GraphicBuffer::getSelf(buffer)->getIndex(); + int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer)); err = mSharedBufferClient->lock(bufIdx); LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err)); return err; @@ -539,7 +603,6 @@ int Surface::lockBuffer(android_native_buffer_t* buffer) int Surface::queueBuffer(android_native_buffer_t* buffer) { - sp<SurfaceComposerClient> client(getClient()); status_t err = validate(); if (err != NO_ERROR) return err; @@ -548,14 +611,15 @@ int Surface::queueBuffer(android_native_buffer_t* buffer) mDirtyRegion.set(mSwapRectangle); } - int32_t bufIdx = GraphicBuffer::getSelf(buffer)->getIndex(); + int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer)); + mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop); mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion); err = mSharedBufferClient->queue(bufIdx); LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err)); if (err == NO_ERROR) { - // FIXME: can we avoid this IPC if we know there is one pending? - client->signalServer(); + // TODO: can we avoid this IPC if we know there is one pending? + mClient.signalServer(); } return err; } @@ -578,6 +642,10 @@ int Surface::query(int what, int* value) int Surface::perform(int operation, va_list args) { + status_t err = validate(); + if (err != NO_ERROR) + return err; + int res = NO_ERROR; switch (operation) { case NATIVE_WINDOW_SET_USAGE: @@ -589,6 +657,15 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_DISCONNECT: res = dispatch_disconnect( args ); break; + case NATIVE_WINDOW_SET_CROP: + res = dispatch_crop( args ); + break; + case NATIVE_WINDOW_SET_BUFFER_COUNT: + res = dispatch_set_buffer_count( args ); + break; + case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: + res = dispatch_set_buffers_geometry( args ); + break; default: res = NAME_NOT_FOUND; break; @@ -608,12 +685,25 @@ int Surface::dispatch_disconnect(va_list args) { int api = va_arg(args, int); return disconnect( api ); } - +int Surface::dispatch_crop(va_list args) { + android_native_rect_t const* rect = va_arg(args, android_native_rect_t*); + return crop( reinterpret_cast<Rect const*>(rect) ); +} +int Surface::dispatch_set_buffer_count(va_list args) { + size_t bufferCount = va_arg(args, size_t); + return setBufferCount(bufferCount); +} +int Surface::dispatch_set_buffers_geometry(va_list args) { + int w = va_arg(args, int); + int h = va_arg(args, int); + int f = va_arg(args, int); + return setBuffersGeometry(w, h, f); +} void Surface::setUsage(uint32_t reqUsage) { Mutex::Autolock _l(mSurfaceLock); - mUsage = reqUsage; + mBufferInfo.set(reqUsage); } int Surface::connect(int api) @@ -654,19 +744,55 @@ int Surface::disconnect(int api) return err; } -uint32_t Surface::getUsage() const +int Surface::crop(Rect const* rect) { Mutex::Autolock _l(mSurfaceLock); - return mUsage; + // TODO: validate rect size + mNextBufferCrop = *rect; + return NO_ERROR; } +int Surface::setBufferCount(int bufferCount) +{ + sp<ISurface> s(mSurface); + if (s == 0) return NO_INIT; + + class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback { + sp<ISurface> surface; + virtual status_t operator()(int bufferCount) const { + return surface->setBufferCount(bufferCount); + } + public: + SetBufferCountIPC(const sp<ISurface>& surface) : surface(surface) { } + } ipc(s); + + status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc); + LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s", + bufferCount, strerror(-err)); + return err; +} + +int Surface::setBuffersGeometry(int w, int h, int format) +{ + if (w<0 || h<0 || format<0) + return BAD_VALUE; + + if ((w && !h) || (!w && h)) + return BAD_VALUE; + + Mutex::Autolock _l(mSurfaceLock); + mBufferInfo.set(w, h, format); + return NO_ERROR; +} + +// ---------------------------------------------------------------------------- + int Surface::getConnectedApi() const { Mutex::Autolock _l(mSurfaceLock); return mConnected; } - // ---------------------------------------------------------------------------- status_t Surface::lock(SurfaceInfo* info, bool blocking) { @@ -703,45 +829,47 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) // we're intending to do software rendering from this point setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); - sp<GraphicBuffer> backBuffer; - status_t err = dequeueBuffer(&backBuffer); + android_native_buffer_t* out; + status_t err = dequeueBuffer(&out); LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err)); if (err == NO_ERROR) { + sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out)); err = lockBuffer(backBuffer.get()); LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)", - backBuffer->getIndex(), strerror(-err)); + getBufferIndex(backBuffer), strerror(-err)); if (err == NO_ERROR) { - // we handle copy-back here... - const Rect bounds(backBuffer->width, backBuffer->height); - Region scratch(bounds); + const Region boundsRegion(bounds); + Region scratch(boundsRegion); Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch); + newDirtyRegion &= boundsRegion; - if (mNeedFullUpdate) { - // reset newDirtyRegion to bounds when a buffer is reallocated - // it would be better if this information was associated with - // the buffer and made available to outside of Surface. - // This will do for now though. - mNeedFullUpdate = false; - newDirtyRegion.set(bounds); - } else { - newDirtyRegion.andSelf(bounds); - } - + // figure out if we can copy the frontbuffer back const sp<GraphicBuffer>& frontBuffer(mPostedBuffer); - if (frontBuffer !=0 && - backBuffer->width == frontBuffer->width && - backBuffer->height == frontBuffer->height && - !(mFlags & ISurfaceComposer::eDestroyBackbuffer)) - { + const bool canCopyBack = (frontBuffer != 0 && + backBuffer->width == frontBuffer->width && + backBuffer->height == frontBuffer->height && + backBuffer->format == frontBuffer->format && + !(mFlags & ISurfaceComposer::eDestroyBackbuffer)); + + // the dirty region we report to surfaceflinger is the one + // given by the user (as opposed to the one *we* return to the + // user). + mDirtyRegion = newDirtyRegion; + + if (canCopyBack) { + // copy the area that is invalid and not repainted this round const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion)); - if (!copyback.isEmpty() && frontBuffer!=0) { - // copy front to back + if (!copyback.isEmpty()) copyBlt(backBuffer, frontBuffer, copyback); - } + } else { + // if we can't copy-back anything, modify the user's dirty + // region to make sure they redraw the whole buffer + newDirtyRegion = boundsRegion; } - mDirtyRegion = newDirtyRegion; + // keep track of the are of the buffer that is "clean" + // (ie: that will be redrawn) mOldDirtyRegion = newDirtyRegion; void* vaddr; @@ -777,7 +905,7 @@ status_t Surface::unlockAndPost() err = queueBuffer(mLockedBuffer.get()); LOGE_IF(err, "queueBuffer (idx=%d) failed (%s)", - mLockedBuffer->getIndex(), strerror(-err)); + getBufferIndex(mLockedBuffer), strerror(-err)); mPostedBuffer = mLockedBuffer; mLockedBuffer = 0; @@ -789,7 +917,13 @@ void Surface::setSwapRectangle(const Rect& r) { mSwapRectangle = r; } -status_t Surface::getBufferLocked(int index, int usage) +int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const +{ + return buffer->getIndex(); +} + +status_t Surface::getBufferLocked(int index, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { sp<ISurface> s(mSurface); if (s == 0) return NO_INIT; @@ -797,20 +931,21 @@ status_t Surface::getBufferLocked(int index, int usage) status_t err = NO_MEMORY; // free the current buffer - sp<GraphicBuffer>& currentBuffer(mBuffers[index]); + sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index)); if (currentBuffer != 0) { getBufferMapper().unregisterBuffer(currentBuffer->handle); currentBuffer.clear(); } - sp<GraphicBuffer> buffer = s->requestBuffer(index, usage); + sp<GraphicBuffer> buffer = s->requestBuffer(index, w, h, format, usage); LOGE_IF(buffer==0, "ISurface::getBuffer(%d, %08x) returned NULL", index, usage); if (buffer != 0) { // this should never happen by construction LOGE_IF(buffer->handle == NULL, - "Surface (identity=%d) requestBuffer(%d, %08x) returned" - "a buffer with a null handle", mIdentity, index, usage); + "Surface (identity=%d) requestBuffer(%d, %u, %u, %u, %08x) " + "returned a buffer with a null handle", + mIdentity, index, w, h, format, usage); err = mSharedBufferClient->getStatus(); LOGE_IF(err, "Surface (identity=%d) state = %d", mIdentity, err); if (!err && buffer->handle != NULL) { @@ -820,14 +955,52 @@ status_t Surface::getBufferLocked(int index, int usage) if (err == NO_ERROR) { currentBuffer = buffer; currentBuffer->setIndex(index); - mNeedFullUpdate = true; } } else { - err = err<0 ? err : NO_MEMORY; + err = err<0 ? err : status_t(NO_MEMORY); } } return err; } +// ---------------------------------------------------------------------------- +Surface::BufferInfo::BufferInfo() + : mWidth(0), mHeight(0), mFormat(0), + mUsage(GRALLOC_USAGE_HW_RENDER), mDirty(0) +{ +} + +void Surface::BufferInfo::set(uint32_t w, uint32_t h, uint32_t format) { + if ((mWidth != w) || (mHeight != h) || (mFormat != format)) { + mWidth = w; + mHeight = h; + mFormat = format; + mDirty |= GEOMETRY; + } +} + +void Surface::BufferInfo::set(uint32_t usage) { + mUsage = usage; +} + +void Surface::BufferInfo::get(uint32_t *pWidth, uint32_t *pHeight, + uint32_t *pFormat, uint32_t *pUsage) const { + *pWidth = mWidth; + *pHeight = mHeight; + *pFormat = mFormat; + *pUsage = mUsage; +} + +bool Surface::BufferInfo::validateBuffer(const sp<GraphicBuffer>& buffer) const { + // make sure we AT LEAST have the usage flags we want + if (mDirty || buffer==0 || + ((buffer->usage & mUsage) != mUsage)) { + mDirty = 0; + return false; + } + return true; +} + +// ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/surfaceflinger_client/SurfaceComposerClient.cpp index 3117495..4096ac6 100644 --- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp +++ b/libs/surfaceflinger_client/SurfaceComposerClient.cpp @@ -17,98 +17,137 @@ #define LOG_TAG "SurfaceComposerClient" #include <stdint.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> #include <sys/types.h> -#include <sys/stat.h> -#include <cutils/memory.h> - -#include <utils/Atomic.h> #include <utils/Errors.h> #include <utils/threads.h> -#include <utils/KeyedVector.h> +#include <utils/SortedVector.h> #include <utils/Log.h> +#include <utils/Singleton.h> #include <binder/IServiceManager.h> #include <binder/IMemory.h> #include <ui/DisplayInfo.h> -#include <ui/Rect.h> #include <surfaceflinger/ISurfaceComposer.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h> #include <surfaceflinger/ISurface.h> #include <surfaceflinger/SurfaceComposerClient.h> #include <private/surfaceflinger/LayerState.h> #include <private/surfaceflinger/SharedBufferStack.h> -#define VERBOSE(...) ((void)0) -//#define VERBOSE LOGD - -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) namespace android { +// --------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService); + +ComposerService::ComposerService() +: Singleton<ComposerService>() { + const String16 name("SurfaceFlinger"); + while (getService(name, &mComposerService) != NO_ERROR) { + usleep(250000); + } + mServerCblkMemory = mComposerService->getCblk(); + mServerCblk = static_cast<surface_flinger_cblk_t volatile *>( + mServerCblkMemory->getBase()); +} + +sp<ISurfaceComposer> ComposerService::getComposerService() { + return ComposerService::getInstance().mComposerService; +} + +surface_flinger_cblk_t const volatile * ComposerService::getControlBlock() { + return ComposerService::getInstance().mServerCblk; +} + +static inline sp<ISurfaceComposer> getComposerService() { + return ComposerService::getComposerService(); +} + +static inline surface_flinger_cblk_t const volatile * get_cblk() { + return ComposerService::getControlBlock(); +} // --------------------------------------------------------------------------- -// Must not be holding SurfaceComposerClient::mLock when acquiring gLock here. -static Mutex gLock; -static sp<ISurfaceComposer> gSurfaceManager; -static DefaultKeyedVector< sp<IBinder>, sp<SurfaceComposerClient> > gActiveConnections; -static SortedVector<sp<SurfaceComposerClient> > gOpenTransactions; -static sp<IMemoryHeap> gServerCblkMemory; -static volatile surface_flinger_cblk_t* gServerCblk; - -static sp<ISurfaceComposer> getComposerService() -{ - sp<ISurfaceComposer> sc; - Mutex::Autolock _l(gLock); - if (gSurfaceManager != 0) { - sc = gSurfaceManager; - } else { - // release the lock while we're waiting... - gLock.unlock(); - - sp<IBinder> binder; - sp<IServiceManager> sm = defaultServiceManager(); - do { - binder = sm->getService(String16("SurfaceFlinger")); - if (binder == 0) { - LOGW("SurfaceFlinger not published, waiting..."); - usleep(500000); // 0.5 s +class Composer : public Singleton<Composer> +{ + Mutex mLock; + SortedVector< wp<SurfaceComposerClient> > mActiveConnections; + SortedVector<sp<SurfaceComposerClient> > mOpenTransactions; + + Composer() : Singleton<Composer>() { + } + + void addClientImpl(const sp<SurfaceComposerClient>& client) { + Mutex::Autolock _l(mLock); + mActiveConnections.add(client); + } + + void removeClientImpl(const sp<SurfaceComposerClient>& client) { + Mutex::Autolock _l(mLock); + mActiveConnections.remove(client); + } + + void openGlobalTransactionImpl() + { + Mutex::Autolock _l(mLock); + if (mOpenTransactions.size()) { + LOGE("openGlobalTransaction() called more than once. skipping."); + return; + } + const size_t N = mActiveConnections.size(); + for (size_t i=0; i<N; i++) { + sp<SurfaceComposerClient> client(mActiveConnections[i].promote()); + if (client != 0 && mOpenTransactions.indexOf(client) < 0) { + if (client->openTransaction() == NO_ERROR) { + mOpenTransactions.add(client); + } else { + LOGE("openTransaction on client %p failed", client.get()); + // let it go, it'll fail later when the user + // tries to do something with the transaction + } } - } while(binder == 0); - - // grab the lock again for updating gSurfaceManager - gLock.lock(); - if (gSurfaceManager == 0) { - sc = interface_cast<ISurfaceComposer>(binder); - gSurfaceManager = sc; - } else { - sc = gSurfaceManager; } } - return sc; -} -static volatile surface_flinger_cblk_t const * get_cblk() -{ - if (gServerCblk == 0) { + void closeGlobalTransactionImpl() + { + mLock.lock(); + SortedVector< sp<SurfaceComposerClient> > clients(mOpenTransactions); + mOpenTransactions.clear(); + mLock.unlock(); + sp<ISurfaceComposer> sm(getComposerService()); - Mutex::Autolock _l(gLock); - if (gServerCblk == 0) { - gServerCblkMemory = sm->getCblk(); - LOGE_IF(gServerCblkMemory==0, "Can't get server control block"); - gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->getBase(); - LOGE_IF(gServerCblk==0, "Can't get server control block address"); - } + sm->openGlobalTransaction(); + const size_t N = clients.size(); + for (size_t i=0; i<N; i++) { + clients[i]->closeTransaction(); + } + sm->closeGlobalTransaction(); } - return gServerCblk; -} + + friend class Singleton<Composer>; + +public: + static void addClient(const sp<SurfaceComposerClient>& client) { + Composer::getInstance().addClientImpl(client); + } + static void removeClient(const sp<SurfaceComposerClient>& client) { + Composer::getInstance().removeClientImpl(client); + } + static void openGlobalTransaction() { + Composer::getInstance().openGlobalTransactionImpl(); + } + static void closeGlobalTransaction() { + Composer::getInstance().closeGlobalTransactionImpl(); + } +}; + +ANDROID_SINGLETON_STATIC_INSTANCE(Composer); // --------------------------------------------------------------------------- @@ -120,61 +159,27 @@ static inline int compare_type( const layer_state_t& lhs, } SurfaceComposerClient::SurfaceComposerClient() + : mTransactionOpen(0), mPrebuiltLayerState(0), mStatus(NO_INIT) { - sp<ISurfaceComposer> sm(getComposerService()); - if (sm == 0) { - _init(0, 0); - return; - } - - _init(sm, sm->createConnection()); - - if (mClient != 0) { - Mutex::Autolock _l(gLock); - VERBOSE("Adding client %p to map", this); - gActiveConnections.add(mClient->asBinder(), this); - } } -SurfaceComposerClient::SurfaceComposerClient( - const sp<ISurfaceComposer>& sm, const sp<IBinder>& conn) -{ - _init(sm, interface_cast<ISurfaceFlingerClient>(conn)); -} - - -status_t SurfaceComposerClient::linkToComposerDeath( - const sp<IBinder::DeathRecipient>& recipient, - void* cookie, uint32_t flags) +void SurfaceComposerClient::onFirstRef() { sp<ISurfaceComposer> sm(getComposerService()); - return sm->asBinder()->linkToDeath(recipient, cookie, flags); -} - -void SurfaceComposerClient::_init( - const sp<ISurfaceComposer>& sm, const sp<ISurfaceFlingerClient>& conn) -{ - VERBOSE("Creating client %p, conn %p", this, conn.get()); - - mPrebuiltLayerState = 0; - mTransactionOpen = 0; - mStatus = NO_ERROR; - mControl = 0; - - mClient = conn; - if (mClient == 0) { - mStatus = NO_INIT; - return; + if (sm != 0) { + sp<ISurfaceComposerClient> conn = sm->createConnection(); + if (conn != 0) { + mClient = conn; + Composer::addClient(this); + mPrebuiltLayerState = new layer_state_t; + mStatus = NO_ERROR; + } } - - mControlMemory = mClient->getControlBlock(); - mSignalServer = sm; - mControl = static_cast<SharedClient *>(mControlMemory->getBase()); } SurfaceComposerClient::~SurfaceComposerClient() { - VERBOSE("Destroying client %p, conn %p", this, mClient.get()); + delete mPrebuiltLayerState; dispose(); } @@ -188,69 +193,31 @@ sp<IBinder> SurfaceComposerClient::connection() const return (mClient != 0) ? mClient->asBinder() : 0; } -sp<SurfaceComposerClient> -SurfaceComposerClient::clientForConnection(const sp<IBinder>& conn) +status_t SurfaceComposerClient::linkToComposerDeath( + const sp<IBinder::DeathRecipient>& recipient, + void* cookie, uint32_t flags) { - sp<SurfaceComposerClient> client; - - { // scope for lock - Mutex::Autolock _l(gLock); - client = gActiveConnections.valueFor(conn); - } - - if (client == 0) { - // Need to make a new client. - sp<ISurfaceComposer> sm(getComposerService()); - client = new SurfaceComposerClient(sm, conn); - if (client != 0 && client->initCheck() == NO_ERROR) { - Mutex::Autolock _l(gLock); - gActiveConnections.add(conn, client); - //LOGD("we have %d connections", gActiveConnections.size()); - } else { - client.clear(); - } - } - - return client; + sp<ISurfaceComposer> sm(getComposerService()); + return sm->asBinder()->linkToDeath(recipient, cookie, flags); } void SurfaceComposerClient::dispose() { // this can be called more than once. - - sp<IMemoryHeap> controlMemory; - sp<ISurfaceFlingerClient> client; - - { - Mutex::Autolock _lg(gLock); - Mutex::Autolock _lm(mLock); - - mSignalServer = 0; - - if (mClient != 0) { - client = mClient; - mClient.clear(); - - ssize_t i = gActiveConnections.indexOfKey(client->asBinder()); - if (i >= 0 && gActiveConnections.valueAt(i) == this) { - VERBOSE("Removing client %p from map at %d", this, int(i)); - gActiveConnections.removeItemsAt(i); - } - } - - delete mPrebuiltLayerState; - mPrebuiltLayerState = 0; - controlMemory = mControlMemory; - mControlMemory.clear(); - mControl = 0; - mStatus = NO_INIT; + sp<ISurfaceComposerClient> client; + Mutex::Autolock _lm(mLock); + if (mClient != 0) { + Composer::removeClient(this); + client = mClient; // hold ref while lock is held + mClient.clear(); } + mStatus = NO_INIT; } status_t SurfaceComposerClient::getDisplayInfo( DisplayID dpy, DisplayInfo* info) { - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); @@ -268,7 +235,7 @@ status_t SurfaceComposerClient::getDisplayInfo( ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy) { - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); volatile display_cblk_t const * dcblk = cblk->displays + dpy; @@ -277,7 +244,7 @@ ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy) ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy) { - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); volatile display_cblk_t const * dcblk = cblk->displays + dpy; @@ -286,7 +253,7 @@ ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy) ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy) { - if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); volatile display_cblk_t const * dcblk = cblk->displays + dpy; @@ -305,12 +272,6 @@ ssize_t SurfaceComposerClient::getNumberOfDisplays() return n; } - -void SurfaceComposerClient::signalServer() -{ - mSignalServer->signal(); -} - sp<SurfaceControl> SurfaceComposerClient::createSurface( int pid, DisplayID display, @@ -327,7 +288,6 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( return SurfaceComposerClient::createSurface(pid, name, display, w, h, format, flags); - } sp<SurfaceControl> SurfaceComposerClient::createSurface( @@ -341,13 +301,11 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( { sp<SurfaceControl> result; if (mStatus == NO_ERROR) { - ISurfaceFlingerClient::surface_data_t data; + ISurfaceComposerClient::surface_data_t data; sp<ISurface> surface = mClient->createSurface(&data, pid, name, display, w, h, format, flags); if (surface != 0) { - if (uint32_t(data.token) < NUM_LAYERS_MAX) { - result = new SurfaceControl(this, surface, data, w, h, format, flags); - } + result = new SurfaceControl(this, surface, data, w, h, format, flags); } } return result; @@ -373,56 +331,14 @@ status_t SurfaceComposerClient::destroySurface(SurfaceID sid) void SurfaceComposerClient::openGlobalTransaction() { - Mutex::Autolock _l(gLock); - - if (gOpenTransactions.size()) { - LOGE("openGlobalTransaction() called more than once. skipping."); - return; - } - - const size_t N = gActiveConnections.size(); - VERBOSE("openGlobalTransaction (%ld clients)", N); - for (size_t i=0; i<N; i++) { - sp<SurfaceComposerClient> client(gActiveConnections.valueAt(i)); - if (gOpenTransactions.indexOf(client) < 0) { - if (client->openTransaction() == NO_ERROR) { - if (gOpenTransactions.add(client) < 0) { - // Ooops! - LOGE( "Unable to add a SurfaceComposerClient " - "to the global transaction set (out of memory?)"); - client->closeTransaction(); - // let it go, it'll fail later when the user - // tries to do something with the transaction - } - } else { - LOGE("openTransaction on client %p failed", client.get()); - // let it go, it'll fail later when the user - // tries to do something with the transaction - } - } - } + Composer::openGlobalTransaction(); } void SurfaceComposerClient::closeGlobalTransaction() { - gLock.lock(); - SortedVector< sp<SurfaceComposerClient> > clients(gOpenTransactions); - gOpenTransactions.clear(); - gLock.unlock(); - - const size_t N = clients.size(); - VERBOSE("closeGlobalTransaction (%ld clients)", N); - - sp<ISurfaceComposer> sm(getComposerService()); - sm->openGlobalTransaction(); - for (size_t i=0; i<N; i++) { - clients[i]->closeTransaction(); - } - sm->closeGlobalTransaction(); - + Composer::closeGlobalTransaction(); } - status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags) { sp<ISurfaceComposer> sm(getComposerService()); @@ -447,26 +363,16 @@ status_t SurfaceComposerClient::openTransaction() if (mStatus != NO_ERROR) return mStatus; Mutex::Autolock _l(mLock); - VERBOSE( "openTransaction (client %p, mTransactionOpen=%d)", - this, mTransactionOpen); mTransactionOpen++; - if (mPrebuiltLayerState == 0) { - mPrebuiltLayerState = new layer_state_t; - } return NO_ERROR; } - status_t SurfaceComposerClient::closeTransaction() { if (mStatus != NO_ERROR) return mStatus; Mutex::Autolock _l(mLock); - - VERBOSE( "closeTransaction (client %p, mTransactionOpen=%d)", - this, mTransactionOpen); - if (mTransactionOpen <= 0) { LOGE( "closeTransaction (client %p, mTransactionOpen=%d) " "called more times than openTransaction()", @@ -488,7 +394,7 @@ status_t SurfaceComposerClient::closeTransaction() return NO_ERROR; } -layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index) +layer_state_t* SurfaceComposerClient::get_state_l(SurfaceID index) { // API usage error, do nothing. if (mTransactionOpen<=0) { @@ -498,7 +404,7 @@ layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index) } // use mPrebuiltLayerState just to find out if we already have it - layer_state_t& dummy = *mPrebuiltLayerState; + layer_state_t& dummy(*mPrebuiltLayerState); dummy.surface = index; ssize_t i = mStates.indexOf(dummy); if (i < 0) { @@ -508,49 +414,49 @@ layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index) return mStates.editArray() + i; } -layer_state_t* SurfaceComposerClient::_lockLayerState(SurfaceID id) +layer_state_t* SurfaceComposerClient::lockLayerState(SurfaceID id) { layer_state_t* s; mLock.lock(); - s = _get_state_l(id); + s = get_state_l(id); if (!s) mLock.unlock(); return s; } -void SurfaceComposerClient::_unlockLayerState() +void SurfaceComposerClient::unlockLayerState() { mLock.unlock(); } status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::ePositionChanged; s->x = x; s->y = y; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eSizeChanged; s->w = w; s->h = h; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eLayerChanged; s->z = z; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } @@ -579,34 +485,34 @@ status_t SurfaceComposerClient::unfreeze(SurfaceID id) status_t SurfaceComposerClient::setFlags(SurfaceID id, uint32_t flags, uint32_t mask) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eVisibilityChanged; s->flags &= ~mask; s->flags |= (flags & mask); s->mask |= mask; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setTransparentRegionHint( SurfaceID id, const Region& transparentRegion) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eTransparentRegionChanged; s->transparentRegion = transparentRegion; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eAlphaChanged; s->alpha = alpha; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } @@ -615,7 +521,7 @@ status_t SurfaceComposerClient::setMatrix( float dsdx, float dtdx, float dsdy, float dtdy ) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eMatrixChanged; layer_state_t::matrix22_t matrix; @@ -624,19 +530,20 @@ status_t SurfaceComposerClient::setMatrix( matrix.dsdy = dsdy; matrix.dtdy = dtdy; s->matrix = matrix; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint) { - layer_state_t* s = _lockLayerState(id); + layer_state_t* s = lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eFreezeTintChanged; s->tint = tint; - _unlockLayerState(); + unlockLayerState(); return NO_ERROR; } +// ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/surfaceflinger_client/tests/Android.mk b/libs/surfaceflinger_client/tests/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/libs/surfaceflinger_client/tests/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk b/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk new file mode 100644 index 0000000..d3dfe04 --- /dev/null +++ b/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + SharedBufferStackTest.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libui \ + libsurfaceflinger_client + +LOCAL_MODULE:= test-sharedbufferstack + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_EXECUTABLE) diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp new file mode 100644 index 0000000..f409f48 --- /dev/null +++ b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp @@ -0,0 +1,279 @@ +/* + * 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. + */ + +#undef NDEBUG + +#include <assert.h> +#include <cutils/memory.h> +#include <cutils/log.h> +#include <utils/Errors.h> +#include <private/surfaceflinger/SharedBufferStack.h> + +using namespace android; + +void log(const char* prefix, int *b, size_t num); +void test0(SharedBufferServer& s, SharedBufferClient& c, size_t num, int* list); + +// ---------------------------------------------------------------------------- + +int main(int argc, char** argv) +{ + SharedClient client; + SharedBufferServer s(&client, 0, 4, 0); + SharedBufferClient c(&client, 0, 4, 0); + + printf("basic test 0\n"); + int list0[4] = {0, 1, 2, 3}; + test0(s, c, 4, list0); + + printf("basic test 1\n"); + int list1[4] = {2, 1, 0, 3}; + test0(s, c, 4, list1); + + int b = c.dequeue(); + c.lock(b); + c.queue(b); + s.retireAndLock(); + + printf("basic test 2\n"); + int list2[4] = {1, 2, 3, 0}; + test0(s, c, 4, list2); + + + printf("resize test\n"); + class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback { + SharedBufferServer& s; + virtual status_t operator()(int bufferCount) const { + return s.resize(bufferCount); + } + public: + SetBufferCountIPC(SharedBufferServer& s) : s(s) { } + } resize(s); + + c.setBufferCount(6, resize); + int list3[6] = {3, 2, 1, 4, 5, 0}; + test0(s, c, 6, list3); + + return 0; +} + +void log(const char* prefix, int *b, size_t num) +{ + printf("%s: ", prefix); + for (size_t i=0 ; i<num ; i++) { + printf("%d ", b[i]); + } + printf("\n"); +} + +// ---------------------------------------------------------------------------- + +void test0( + SharedBufferServer& s, + SharedBufferClient& c, + size_t num, + int* list) +{ + status_t err; + int b[num], u[num], r[num]; + + for (size_t i=0 ; i<num ; i++) { + b[i] = c.dequeue(); + assert(b[i]==list[i]); + } + log("DQ", b, num); + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.lock(b[i]); + assert(err==0); + } + log("LK", b, num-1); + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.queue(b[i]); + assert(err==0); + } + log(" Q", b, num-1); + + + for (size_t i=0 ; i<num-1 ; i++) { + r[i] = s.retireAndLock(); + assert(r[i]==list[i]); + err = s.unlock(r[i]); + assert(err == 0); + } + log("RT", r, num-1); + + err = c.lock(b[num-1]); + assert(err == 0); + log("LK", b+num-1, 1); + + err = c.queue(b[num-1]); + assert(err == 0); + log(" Q", b+num-1, 1); + + r[num-1] = s.retireAndLock(); + assert(r[num-1]==list[num-1]); + err = s.unlock(r[num-1]); + assert(err == 0); + log("RT", r+num-1, 1); + + // ------------------------------------ + printf("\n"); + + for (size_t i=0 ; i<num ; i++) { + b[i] = c.dequeue(); + assert(b[i]==list[i]); + } + log("DQ", b, num); + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.lock(b[i]); + assert(err==0); + } + log("LK", b, num-1); + + for (size_t i=0 ; i<num-1 ; i++) { + u[i] = b[num-2-i]; + } + u[num-1] = b[num-1]; + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.queue(u[i]); + assert(err==0); + } + log(" Q", u, num-1); + + for (size_t i=0 ; i<num-1 ; i++) { + r[i] = s.retireAndLock(); + assert(r[i]==u[i]); + err = s.unlock(r[i]); + assert(err == 0); + } + log("RT", r, num-1); + + err = c.lock(b[num-1]); + assert(err == 0); + log("LK", b+num-1, 1); + + err = c.queue(b[num-1]); + assert(err == 0); + log(" Q", b+num-1, 1); + + r[num-1] = s.retireAndLock(); + assert(r[num-1]==list[num-1]); + err = s.unlock(r[num-1]); + assert(err == 0); + log("RT", r+num-1, 1); + + // ------------------------------------ + printf("\n"); + + for (size_t i=0 ; i<num ; i++) { + b[i] = c.dequeue(); + assert(b[i]==u[i]); + } + log("DQ", b, num); + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.lock(b[i]); + assert(err==0); + } + log("LK", b, num-1); + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.queue(b[i]); + assert(err==0); + } + log(" Q", b, num-1); + + for (size_t i=0 ; i<num-1 ; i++) { + r[i] = s.retireAndLock(); + assert(r[i]==u[i]); + err = s.unlock(r[i]); + assert(err == 0); + } + log("RT", r, num-1); + + err = c.lock(u[num-1]); + assert(err == 0); + log("LK", u+num-1, 1); + + err = c.queue(u[num-1]); + assert(err == 0); + log(" Q", u+num-1, 1); + + r[num-1] = s.retireAndLock(); + assert(r[num-1]==u[num-1]); + err = s.unlock(r[num-1]); + assert(err == 0); + log("RT", r+num-1, 1); + + // ------------------------------------ + printf("\n"); + + b[0] = c.dequeue(); + assert(b[0]==u[0]); + log("DQ", b, 1); + + c.undoDequeue(b[0]); + assert(err == 0); + log("UDQ", b, 1); + + // ------------------------------------ + printf("\n"); + + for (size_t i=0 ; i<num ; i++) { + b[i] = c.dequeue(); + assert(b[i]==u[i]); + } + log("DQ", b, num); + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.lock(b[i]); + assert(err==0); + } + log("LK", b, num-1); + + for (size_t i=0 ; i<num-1 ; i++) { + err = c.queue(b[i]); + assert(err==0); + } + log(" Q", b, num-1); + + for (size_t i=0 ; i<num-1 ; i++) { + r[i] = s.retireAndLock(); + assert(r[i]==u[i]); + err = s.unlock(r[i]); + assert(err == 0); + } + log("RT", r, num-1); + + err = c.lock(u[num-1]); + assert(err == 0); + log("LK", u+num-1, 1); + + err = c.queue(u[num-1]); + assert(err == 0); + log(" Q", u+num-1, 1); + + r[num-1] = s.retireAndLock(); + assert(r[num-1]==u[num-1]); + err = s.unlock(r[num-1]); + assert(err == 0); + log("RT", r+num-1, 1); + printf("\n"); +} |