/* * 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. */ #define LOG_TAG "SurfaceComposerClient" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 { // --------------------------------------------------------------------------- // Must not be holding SurfaceComposerClient::mLock when acquiring gLock here. static Mutex gLock; static sp gSurfaceManager; static DefaultKeyedVector< sp, sp > gActiveConnections; static SortedVector > gOpenTransactions; static sp gServerCblkMemory; static volatile surface_flinger_cblk_t* gServerCblk; const sp& _get_surface_manager() { if (gSurfaceManager != 0) { return gSurfaceManager; } sp binder; sp sm = defaultServiceManager(); do { binder = sm->getService(String16("SurfaceFlinger")); if (binder == 0) { LOGW("SurfaceFlinger not published, waiting..."); usleep(500000); // 0.5 s } } while(binder == 0); sp sc(interface_cast(binder)); Mutex::Autolock _l(gLock); if (gSurfaceManager == 0) { gSurfaceManager = sc; } return gSurfaceManager; } static volatile surface_flinger_cblk_t const * get_cblk() { if (gServerCblk == 0) { const sp& sm(_get_surface_manager()); 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->pointer(); LOGE_IF(gServerCblk==0, "Can't get server control block address"); } } return gServerCblk; } // --------------------------------------------------------------------------- static void copyBlt(const GGLSurface& dst, const GGLSurface& src, const Region& reg) { Region::iterator iterator(reg); if (iterator) { // NOTE: dst and src must be the same format Rect r; const size_t bpp = bytesPerPixel(src.format); const size_t dbpr = dst.stride * bpp; const size_t sbpr = src.stride * bpp; while (iterator.iterate(&r)) { ssize_t h = r.bottom - r.top; if (h) { size_t size = (r.right - r.left) * bpp; uint8_t* s = src.data + (r.left + src.stride * r.top) * bpp; uint8_t* d = dst.data + (r.left + dst.stride * r.top) * bpp; if (dbpr==sbpr && size==sbpr) { size *= h; h = 1; } do { memcpy(d, s, size); d += dbpr; s += sbpr; } while (--h > 0); } } } } // --------------------------------------------------------------------------- surface_flinger_cblk_t::surface_flinger_cblk_t() { } // --------------------------------------------------------------------------- per_client_cblk_t::per_client_cblk_t() { } // these functions are used by the clients inline status_t per_client_cblk_t::validate(size_t i) const { if (uint32_t(i) >= NUM_LAYERS_MAX) return BAD_INDEX; if (layers[i].swapState & eInvalidSurface) return NO_MEMORY; return NO_ERROR; } int32_t per_client_cblk_t::lock_layer(size_t i, uint32_t flags) { int32_t index; uint32_t state; int timeout = 0; status_t result; layer_cblk_t * const layer = layers + i; const bool blocking = flags & BLOCKING; const bool inspect = flags & INSPECT; do { state = layer->swapState; if (UNLIKELY((state&(eFlipRequested|eNextFlipPending)) == eNextFlipPending)) { LOGE("eNextFlipPending set but eFlipRequested not set, " "layer=%d (lcblk=%p), state=%08x", int(i), layer, int(state)); return INVALID_OPERATION; } if (UNLIKELY(state&eLocked)) { LOGE("eLocked set when entering lock_layer(), " "layer=%d (lcblk=%p), state=%08x", int(i), layer, int(state)); return WOULD_BLOCK; } if (state & (eFlipRequested | eNextFlipPending | eResizeRequested | eInvalidSurface)) { int32_t resizeIndex; Mutex::Autolock _l(lock); // might block for a very short amount of time // will never cause the server to block (trylock()) goto start_loop_here; // We block the client if: // eNextFlipPending: we've used both buffers already, so we need to // wait for one to become availlable. // eResizeRequested: the buffer we're going to acquire is being // resized. Block until it is done. // eFlipRequested && eBusy: the buffer we're going to acquire is // currently in use by the server. // eInvalidSurface: this is a special case, we don't block in this // case, we just return an error. while((state & (eNextFlipPending|eInvalidSurface)) || (state & ((resizeIndex) ? eResizeBuffer1 : eResizeBuffer0)) || ((state & (eFlipRequested|eBusy)) == (eFlipRequested|eBusy)) ) { if (state & eInvalidSurface) return NO_MEMORY; if (!blocking) return WOULD_BLOCK; timeout = 0; result = cv.waitRelative(lock, seconds(1)); if (__builtin_expect(result!=NO_ERROR, false)) { const int newState = layer->swapState; LOGW( "lock_layer timed out (is the CPU pegged?) " "layer=%d, lcblk=%p, state=%08x (was %08x)", int(i), layer, newState, int(state)); timeout = newState != int(state); } start_loop_here: state = layer->swapState; resizeIndex = (state&eIndex) ^ ((state&eFlipRequested)>>1); } LOGW_IF(timeout, "lock_layer() timed out but didn't appear to need " "to be locked and we recovered " "(layer=%d, lcblk=%p, state=%08x)", int(i), layer, int(state)); } // eFlipRequested is not set and cannot be set by another thread: it's // safe to use the first buffer without synchronization. // Choose the index depending on eFlipRequested. // When it's set, choose the 'other' buffer. index = (state&eIndex) ^ ((state&eFlipRequested)>>1); // make sure this buffer is valid if (layer->surface[index].bits_offset < 0) { return status_t(layer->surface[index].bits_offset); } if (inspect) { // we just want to inspect this layer. don't lock it. goto done; } // last thing before we're done, we need to atomically lock the state } while (android_atomic_cmpxchg(state, state|eLocked, &(layer->swapState))); VERBOSE("locked layer=%d (lcblk=%p), buffer=%d, state=0x%08x", int(i), layer, int(index), int(state)); // store the index of the locked buffer (for client use only) layer->flags &= ~eBufferIndex; layer->flags |= ((index << eBufferIndexShift) & eBufferIndex); done: return index; } uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i) { // atomically set eFlipRequested and clear eLocked and optionnaly // set eNextFlipPending if eFlipRequested was already set layer_cblk_t * const layer = layers + i; int32_t oldvalue, newvalue; do { oldvalue = layer->swapState; // get current value newvalue = oldvalue & ~eLocked; // clear eLocked newvalue |= eFlipRequested; // set eFlipRequested if (oldvalue & eFlipRequested) newvalue |= eNextFlipPending; // if eFlipRequested was alread set, set eNextFlipPending } while (android_atomic_cmpxchg(oldvalue, newvalue, &(layer->swapState))); VERBOSE("request pageflip for layer=%d, buffer=%d, state=0x%08x", int(i), int((layer->flags & eBufferIndex) >> eBufferIndexShift), int(newvalue)); // from this point, the server can kick in at anytime and use the first // buffer, so we cannot use it anymore, and we must use the 'other' // buffer instead (or wait if it is not availlable yet, see lock_layer). return newvalue; } void per_client_cblk_t::unlock_layer(size_t i) { layer_cblk_t * const layer = layers + i; android_atomic_and(~eLocked, &layer->swapState); } // --------------------------------------------------------------------------- static inline int compare_type( const layer_state_t& lhs, const layer_state_t& rhs) { if (lhs.surface < rhs.surface) return -1; if (lhs.surface > rhs.surface) return 1; return 0; } SurfaceComposerClient::SurfaceComposerClient() { const sp& sm(_get_surface_manager()); 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& sm, const sp& conn) { _init(sm, interface_cast(conn)); } void SurfaceComposerClient::_init( const sp& sm, const sp& conn) { VERBOSE("Creating client %p, conn %p", this, conn.get()); mSignalServer = 0; mPrebuiltLayerState = 0; mTransactionOpen = 0; mStatus = NO_ERROR; mControl = 0; mClient = conn; if (mClient == 0) { mStatus = NO_INIT; return; } mClient->getControlBlocks(&mControlMemory); mSignalServer = new SurfaceFlingerSynchro(sm); mControl = static_cast(mControlMemory->pointer()); } SurfaceComposerClient::~SurfaceComposerClient() { VERBOSE("Destroying client %p, conn %p", this, mClient.get()); dispose(); } status_t SurfaceComposerClient::initCheck() const { return mStatus; } status_t SurfaceComposerClient::validateSurface( per_client_cblk_t const* cblk, Surface const * surface) { SurfaceID index = surface->ID(); if (cblk == 0) { LOGE("cblk is null (surface id=%d, identity=%u)", index, surface->getIdentity()); return NO_INIT; } status_t err = cblk->validate(index); if (err != NO_ERROR) { LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)", index, surface->getIdentity(), err, strerror(-err)); return err; } if (surface->getIdentity() != uint32_t(cblk->layers[index].identity)) { LOGE("using an invalid surface id=%d, identity=%u should be %d", index, surface->getIdentity(), cblk->layers[index].identity); return NO_INIT; } return NO_ERROR; } sp SurfaceComposerClient::connection() const { return (mClient != 0) ? mClient->asBinder() : 0; } sp SurfaceComposerClient::clientForConnection(const sp& conn) { sp client; { // scope for lock Mutex::Autolock _l(gLock); client = gActiveConnections.valueFor(conn); } if (client == 0) { // Need to make a new client. const sp& sm(_get_surface_manager()); 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; } void SurfaceComposerClient::dispose() { // this can be called more than once. sp controlMemory; sp client; sp surfaceHeap; { Mutex::Autolock _lg(gLock); Mutex::Autolock _lm(mLock); delete mSignalServer; 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; surfaceHeap = mSurfaceHeap; mControlMemory.clear(); mSurfaceHeap.clear(); mControl = 0; mStatus = NO_INIT; } } status_t SurfaceComposerClient::getDisplayInfo( DisplayID dpy, DisplayInfo* info) { if (uint32_t(dpy)>=NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); volatile display_cblk_t const * dcblk = cblk->displays + dpy; info->w = dcblk->w; info->h = dcblk->h; info->orientation = dcblk->orientation; info->xdpi = dcblk->xdpi; info->ydpi = dcblk->ydpi; info->fps = dcblk->fps; info->density = dcblk->density; return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo)); } ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy) { if (uint32_t(dpy)>=NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); volatile display_cblk_t const * dcblk = cblk->displays + dpy; return dcblk->w; } ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy) { if (uint32_t(dpy)>=NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); volatile display_cblk_t const * dcblk = cblk->displays + dpy; return dcblk->h; } ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy) { if (uint32_t(dpy)>=NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); volatile display_cblk_t const * dcblk = cblk->displays + dpy; return dcblk->orientation; } ssize_t SurfaceComposerClient::getNumberOfDisplays() { volatile surface_flinger_cblk_t const * cblk = get_cblk(); uint32_t connected = cblk->connected; int n = 0; while (connected) { if (connected&1) n++; connected >>= 1; } return n; } sp SurfaceComposerClient::createSurface( int pid, DisplayID display, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { sp result; if (mStatus == NO_ERROR) { ISurfaceFlingerClient::surface_data_t data; sp surface = mClient->createSurface(&data, pid, display, w, h, format, flags); if (surface != 0) { if (uint32_t(data.token) < NUM_LAYERS_MAX) { result = new Surface(this, surface, data, w, h, format, flags); } } } return result; } status_t SurfaceComposerClient::destroySurface(SurfaceID sid) { if (mStatus != NO_ERROR) return mStatus; // it's okay to destroy a surface while a transaction is open, // (transactions really are a client-side concept) // however, this indicates probably a misuse of the API or a bug // in the client code. LOGW_IF(mTransactionOpen, "Destroying surface while a transaction is open. " "Client %p: destroying surface %d, mTransactionOpen=%d", this, sid, mTransactionOpen); status_t err = mClient->destroySurface(sid); return err; } status_t SurfaceComposerClient::nextBuffer(Surface* surface, Surface::SurfaceInfo* info) { SurfaceID index = surface->ID(); per_client_cblk_t* const cblk = mControl; status_t err = validateSurface(cblk, surface); if (err != NO_ERROR) return err; int32_t backIdx = surface->mBackbufferIndex; layer_cblk_t* const lcblk = &(cblk->layers[index]); const surface_info_t* const front = lcblk->surface + (1-backIdx); info->w = front->w; info->h = front->h; info->format = front->format; info->base = surface->heapBase(1-backIdx); info->bits = reinterpret_cast(intptr_t(info->base) + front->bits_offset); info->bpr = front->bpr; return 0; } status_t SurfaceComposerClient::lockSurface( Surface* surface, Surface::SurfaceInfo* other, Region* dirty, bool blocking) { Mutex::Autolock _l(surface->getLock()); SurfaceID index = surface->ID(); per_client_cblk_t* const cblk = mControl; status_t err = validateSurface(cblk, surface); if (err != NO_ERROR) return err; int32_t backIdx = cblk->lock_layer(size_t(index), per_client_cblk_t::BLOCKING); if (backIdx >= 0) { surface->mBackbufferIndex = backIdx; layer_cblk_t* const lcblk = &(cblk->layers[index]); const surface_info_t* const back = lcblk->surface + backIdx; const surface_info_t* const front = lcblk->surface + (1-backIdx); other->w = back->w; other->h = back->h; other->format = back->format; other->base = surface->heapBase(backIdx); other->bits = reinterpret_cast(intptr_t(other->base) + back->bits_offset); other->bpr = back->bpr; const Rect bounds(other->w, other->h); Region newDirtyRegion; if (back->flags & surface_info_t::eBufferDirty) { /* it is safe to write *back here, because we're guaranteed * SurfaceFlinger is not touching it (since it just granted * access to us) */ const_cast(back)->flags &= ~surface_info_t::eBufferDirty; // content is meaningless in this case and the whole surface // needs to be redrawn. newDirtyRegion.set(bounds); if (dirty) { *dirty = newDirtyRegion; } //if (bytesPerPixel(other->format) == 4) { // android_memset32( // (uint32_t*)other->bits, 0xFF00FF00, other->h * other->bpr); //} else { // android_memset16( // fill with green // (uint16_t*)other->bits, 0x7E0, other->h * other->bpr); //} } else { if (dirty) { dirty->andSelf(Region(bounds)); newDirtyRegion = *dirty; } else { newDirtyRegion.set(bounds); } Region copyback; if (!(lcblk->flags & eNoCopyBack)) { const Region previousDirtyRegion(surface->dirtyRegion()); copyback = previousDirtyRegion.subtract(newDirtyRegion); } if (!copyback.isEmpty()) { // copy front to back GGLSurface cb; cb.version = sizeof(GGLSurface); cb.width = back->w; cb.height = back->h; cb.stride = back->stride; cb.data = (GGLubyte*)surface->heapBase(backIdx); cb.data += back->bits_offset; cb.format = back->format; GGLSurface t; t.version = sizeof(GGLSurface); t.width = front->w; t.height = front->h; t.stride = front->stride; t.data = (GGLubyte*)surface->heapBase(1-backIdx); t.data += front->bits_offset; t.format = front->format; //const Region copyback(lcblk->region + 1-backIdx); copyBlt(cb, t, copyback); } } // update dirty region surface->setDirtyRegion(newDirtyRegion); } return (backIdx < 0) ? status_t(backIdx) : status_t(NO_ERROR); } void SurfaceComposerClient::_signal_server() { mSignalServer->signal(); } void SurfaceComposerClient::_send_dirty_region( layer_cblk_t* lcblk, const Region& dirty) { const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift; flat_region_t* flat_region = lcblk->region + index; status_t err = dirty.write(flat_region, sizeof(flat_region_t)); if (err < NO_ERROR) { // region doesn't fit, use the bounds const Region reg(dirty.bounds()); reg.write(flat_region, sizeof(flat_region_t)); } } status_t SurfaceComposerClient::unlockAndPostSurface(Surface* surface) { Mutex::Autolock _l(surface->getLock()); SurfaceID index = surface->ID(); per_client_cblk_t* const cblk = mControl; status_t err = validateSurface(cblk, surface); if (err != NO_ERROR) return err; Region dirty(surface->dirtyRegion()); const Rect& swapRect(surface->swapRectangle()); if (swapRect.isValid()) { dirty.set(swapRect); } // transmit the dirty region layer_cblk_t* const lcblk = &(cblk->layers[index]); _send_dirty_region(lcblk, dirty); uint32_t newstate = cblk->unlock_layer_and_post(size_t(index)); if (!(newstate & eNextFlipPending)) _signal_server(); return NO_ERROR; } status_t SurfaceComposerClient::unlockSurface(Surface* surface) { Mutex::Autolock _l(surface->getLock()); SurfaceID index = surface->ID(); per_client_cblk_t* const cblk = mControl; status_t err = validateSurface(cblk, surface); if (err != NO_ERROR) return err; layer_cblk_t* const lcblk = &(cblk->layers[index]); cblk->unlock_layer(size_t(index)); return NO_ERROR; } 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 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 } } } } void SurfaceComposerClient::closeGlobalTransaction() { gLock.lock(); SortedVector< sp > clients(gOpenTransactions); gOpenTransactions.clear(); gLock.unlock(); const size_t N = clients.size(); VERBOSE("closeGlobalTransaction (%ld clients)", N); if (N == 1) { clients[0]->closeTransaction(); } else { const sp& sm(_get_surface_manager()); sm->openGlobalTransaction(); for (size_t i=0; icloseTransaction(); } sm->closeGlobalTransaction(); } } status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags) { const sp& sm(_get_surface_manager()); return sm->freezeDisplay(dpy, flags); } status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags) { const sp& sm(_get_surface_manager()); return sm->unfreezeDisplay(dpy, flags); } int SurfaceComposerClient::setOrientation(DisplayID dpy, int orientation, uint32_t flags) { const sp& sm(_get_surface_manager()); return sm->setOrientation(dpy, orientation, flags); } 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()", this, mTransactionOpen); return INVALID_OPERATION; } if (mTransactionOpen >= 2) { mTransactionOpen--; return NO_ERROR; } mTransactionOpen = 0; const ssize_t count = mStates.size(); if (count) { mClient->setState(count, mStates.array()); mStates.clear(); } return NO_ERROR; } layer_state_t* SurfaceComposerClient::_get_state_l(const sp& surface) { SurfaceID index = surface->ID(); per_client_cblk_t* const cblk = mControl; status_t err = validateSurface(cblk, surface.get()); if (err != NO_ERROR) return 0; // API usage error, do nothing. if (mTransactionOpen<=0) { LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d", this, int(index), mTransactionOpen); return 0; } // use mPrebuiltLayerState just to find out if we already have it layer_state_t& dummy = *mPrebuiltLayerState; dummy.surface = index; ssize_t i = mStates.indexOf(dummy); if (i < 0) { // we don't have it, add an initialized layer_state to our list i = mStates.add(dummy); } return mStates.editArray() + i; } layer_state_t* SurfaceComposerClient::_lockLayerState(const sp& surface) { layer_state_t* s; mLock.lock(); s = _get_state_l(surface); if (!s) mLock.unlock(); return s; } void SurfaceComposerClient::_unlockLayerState() { mLock.unlock(); } status_t SurfaceComposerClient::setPosition(Surface* surface, int32_t x, int32_t y) { layer_state_t* s = _lockLayerState(surface); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::ePositionChanged; s->x = x; s->y = y; _unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setSize(Surface* surface, uint32_t w, uint32_t h) { layer_state_t* s = _lockLayerState(surface); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eSizeChanged; s->w = w; s->h = h; _unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setLayer(Surface* surface, int32_t z) { layer_state_t* s = _lockLayerState(surface); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eLayerChanged; s->z = z; _unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::hide(Surface* surface) { return setFlags(surface, ISurfaceComposer::eLayerHidden, ISurfaceComposer::eLayerHidden); } status_t SurfaceComposerClient::show(Surface* surface, int32_t) { return setFlags(surface, 0, ISurfaceComposer::eLayerHidden); } status_t SurfaceComposerClient::freeze(Surface* surface) { return setFlags(surface, ISurfaceComposer::eLayerFrozen, ISurfaceComposer::eLayerFrozen); } status_t SurfaceComposerClient::unfreeze(Surface* surface) { return setFlags(surface, 0, ISurfaceComposer::eLayerFrozen); } status_t SurfaceComposerClient::setFlags(Surface* surface, uint32_t flags, uint32_t mask) { layer_state_t* s = _lockLayerState(surface); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eVisibilityChanged; s->flags &= ~mask; s->flags |= (flags & mask); s->mask |= mask; _unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setTransparentRegionHint( Surface* surface, const Region& transparentRegion) { layer_state_t* s = _lockLayerState(surface); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eTransparentRegionChanged; s->transparentRegion = transparentRegion; _unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setAlpha(Surface* surface, float alpha) { layer_state_t* s = _lockLayerState(surface); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eAlphaChanged; s->alpha = alpha; _unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setMatrix( Surface* surface, float dsdx, float dtdx, float dsdy, float dtdy ) { layer_state_t* s = _lockLayerState(surface); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eMatrixChanged; layer_state_t::matrix22_t matrix; matrix.dsdx = dsdx; matrix.dtdx = dtdx; matrix.dsdy = dsdy; matrix.dtdy = dtdy; s->matrix = matrix; _unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setFreezeTint(Surface* surface, uint32_t tint) { layer_state_t* s = _lockLayerState(surface); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eFreezeTintChanged; s->tint = tint; _unlockLayerState(); return NO_ERROR; } }; // namespace android