diff options
Diffstat (limited to 'services/surfaceflinger/Layer.cpp')
-rw-r--r-- | services/surfaceflinger/Layer.cpp | 286 |
1 files changed, 169 insertions, 117 deletions
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index c9dcef3..3730739 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -35,6 +35,7 @@ #include "Layer.h" #include "SurfaceFlinger.h" #include "DisplayHardware/DisplayHardware.h" +#include "DisplayHardware/HWComposer.h" #define DEBUG_RESIZE 0 @@ -57,8 +58,7 @@ Layer::Layer(SurfaceFlinger* flinger, mSecure(false), mTextureManager(), mBufferManager(mTextureManager), - mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false), - mBypassState(false) + mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false) { } @@ -83,8 +83,28 @@ status_t Layer::setToken(const sp<UserClient>& userClient, sharedClient, token, mBufferManager.getDefaultBufferCount(), getIdentity()); - status_t err = mUserClientRef.setToken(userClient, lcblk, token); + sp<UserClient> ourClient(mUserClientRef.getClient()); + + /* + * Here it is guaranteed that userClient != ourClient + * (see UserClient::getTokenForSurface()). + * + * We release the token used by this surface in ourClient below. + * This should be safe to do so now, since this layer won't be attached + * to this client, it should be okay to reuse that id. + * + * If this causes problems, an other solution would be to keep a list + * of all the {UserClient, token} ever used and release them when the + * Layer is destroyed. + * + */ + + if (ourClient != 0) { + ourClient->detachLayer(this); + } + + status_t err = mUserClientRef.setToken(userClient, lcblk, token); LOGE_IF(err != NO_ERROR, "ClientRef::setToken(%p, %p, %u) failed", userClient.get(), lcblk.get(), token); @@ -171,7 +191,8 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, mReqHeight = h; mSecure = (flags & ISurfaceComposer::eSecure) ? true : false; - mNeedsBlending = (info.h_alpha - info.l_alpha) > 0; + mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 && + (flags & ISurfaceComposer::eOpaque) == 0; // we use the red index int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED); @@ -182,6 +203,71 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, return NO_ERROR; } +void Layer::setGeometry(hwc_layer_t* hwcl) +{ + hwcl->compositionType = HWC_FRAMEBUFFER; + hwcl->hints = 0; + hwcl->flags = 0; + hwcl->transform = 0; + hwcl->blending = HWC_BLENDING_NONE; + + // we can't do alpha-fade with the hwc HAL + const State& s(drawingState()); + if (s.alpha < 0xFF) { + hwcl->flags = HWC_SKIP_LAYER; + return; + } + + // we can only handle simple transformation + if (mOrientation & Transform::ROT_INVALID) { + hwcl->flags = HWC_SKIP_LAYER; + return; + } + + Transform tr(Transform(mOrientation) * Transform(mBufferTransform)); + hwcl->transform = tr.getOrientation(); + + if (needsBlending()) { + hwcl->blending = mPremultipliedAlpha ? + HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE; + } + + hwcl->displayFrame.left = mTransformedBounds.left; + hwcl->displayFrame.top = mTransformedBounds.top; + hwcl->displayFrame.right = mTransformedBounds.right; + hwcl->displayFrame.bottom = mTransformedBounds.bottom; + + hwcl->visibleRegionScreen.rects = + reinterpret_cast<hwc_rect_t const *>( + visibleRegionScreen.getArray( + &hwcl->visibleRegionScreen.numRects)); +} + +void Layer::setPerFrameData(hwc_layer_t* hwcl) { + sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer()); + if (buffer == NULL) { + // this can happen if the client never drew into this layer yet, + // or if we ran out of memory. In that case, don't let + // HWC handle it. + hwcl->flags |= HWC_SKIP_LAYER; + hwcl->handle = NULL; + return; + } + hwcl->handle = buffer->handle; + + if (!mBufferCrop.isEmpty()) { + hwcl->sourceCrop.left = mBufferCrop.left; + hwcl->sourceCrop.top = mBufferCrop.top; + hwcl->sourceCrop.right = mBufferCrop.right; + hwcl->sourceCrop.bottom = mBufferCrop.bottom; + } else { + hwcl->sourceCrop.left = 0; + hwcl->sourceCrop.top = 0; + hwcl->sourceCrop.right = buffer->width; + hwcl->sourceCrop.bottom = buffer->height; + } +} + void Layer::reloadTexture(const Region& dirty) { sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer()); @@ -252,29 +338,6 @@ void Layer::onDraw(const Region& clip) const } return; } - -#ifdef USE_COMPOSITION_BYPASS - sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer()); - if ((buffer != NULL) && (buffer->transform)) { - // Here we have a "bypass" buffer, but we need to composite it - // most likely because it's not fullscreen anymore. - // Since the buffer may have a transformation applied by the client - // we need to inverse this transformation here. - - // calculate the inverse of the buffer transform - const uint32_t mask = HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H; - const uint32_t bufferTransformInverse = buffer->transform ^ mask; - - // To accomplish the inverse transform, we use "mBufferTransform" - // which is not used by Layer.cpp - const_cast<Layer*>(this)->mBufferTransform = bufferTransformInverse; - drawWithOpenGL(clip, tex); - // reset to "no transfrom" - const_cast<Layer*>(this)->mBufferTransform = 0; - return; - } -#endif - drawWithOpenGL(clip, tex); } @@ -302,8 +365,10 @@ status_t Layer::setBufferCount(int bufferCount) // NOTE: lcblk->resize() is protected by an internal lock status_t err = lcblk->resize(bufferCount); - if (err == NO_ERROR) - mBufferManager.resize(bufferCount); + if (err == NO_ERROR) { + EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); + mBufferManager.resize(bufferCount, mFlinger, dpy); + } return err; } @@ -335,14 +400,13 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, * buffer 'index' as our front buffer. */ - uint32_t w, h, f, bypass; + status_t err = NO_ERROR; + uint32_t w, h, f; { // scope for the lock Mutex::Autolock _l(mLock); - bypass = mBypassState; - // zero means default - mFixedSize = reqWidth && reqHeight; + const bool fixedSize = reqWidth && reqHeight; if (!reqFormat) reqFormat = mFormat; if (!reqWidth) reqWidth = mWidth; if (!reqHeight) reqHeight = mHeight; @@ -356,6 +420,7 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, mReqWidth = reqWidth; mReqHeight = reqHeight; mReqFormat = reqFormat; + mFixedSize = fixedSize; mNeedsScaling = mWidth != mReqWidth || mHeight != mReqHeight; lcblk->reallocateAllExcept(index); @@ -365,40 +430,9 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, // here we have to reallocate a new buffer because the buffer could be // used as the front buffer, or by a client in our process // (eg: status bar), and we can't release the handle under its feet. - uint32_t effectiveUsage = getEffectiveUsage(usage); - - status_t err = NO_MEMORY; - -#ifdef USE_COMPOSITION_BYPASS - if (!mSecure && bypass && (effectiveUsage & GRALLOC_USAGE_HW_RENDER)) { - // always allocate a buffer matching the screen size. the size - // may be different from (w,h) if the buffer is rotated. - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - int32_t w = hw.getWidth(); - int32_t h = hw.getHeight(); - int32_t f = hw.getFormat(); - - buffer = new GraphicBuffer(w, h, f, effectiveUsage | GRALLOC_USAGE_HW_FB); - err = buffer->initCheck(); - buffer->transform = uint8_t(getOrientation()); - - if (err != NO_ERROR) { - // allocation didn't succeed, probably because an older bypass - // window hasn't released all its resources yet. - ClientRef::Access sharedClient(mUserClientRef); - SharedBufferServer* lcblk(sharedClient.get()); - if (lcblk) { - // all buffers need reallocation - lcblk->reallocateAll(); - } - } - } -#endif - - if (err != NO_ERROR) { - buffer = new GraphicBuffer(w, h, f, effectiveUsage); - err = buffer->initCheck(); - } + const uint32_t effectiveUsage = getEffectiveUsage(usage); + buffer = new GraphicBuffer(w, h, f, effectiveUsage); + err = buffer->initCheck(); if (err || buffer->handle == 0) { GraphicBuffer::dumpAllocationsToSystemLog(); @@ -445,39 +479,6 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const return usage; } -bool Layer::setBypass(bool enable) -{ - Mutex::Autolock _l(mLock); - - if (mNeedsScaling || mNeedsFiltering) { - return false; - } - - if (mBypassState != enable) { - mBypassState = enable; - ClientRef::Access sharedClient(mUserClientRef); - SharedBufferServer* lcblk(sharedClient.get()); - if (lcblk) { - // all buffers need reallocation - lcblk->reallocateAll(); - } - } - - return true; -} - -void Layer::updateBuffersOrientation() -{ - sp<GraphicBuffer> buffer(getBypassBuffer()); - if (buffer != NULL && mOrientation != buffer->transform) { - ClientRef::Access sharedClient(mUserClientRef); - SharedBufferServer* lcblk(sharedClient.get()); - if (lcblk) { // all buffers need reallocation - lcblk->reallocateAll(); - } - } -} - uint32_t Layer::doTransaction(uint32_t flags) { const Layer::State& front(drawingState()); @@ -581,12 +582,20 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) } // we retired a buffer, which becomes the new front buffer + + const bool noActiveBuffer = !mBufferManager.hasActiveBuffer(); if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) { LOGE("retireAndLock() buffer index (%d) out of range", int(buf)); mPostedDirtyRegion.clear(); return; } + if (noActiveBuffer) { + // we didn't have an active buffer, we need to recompute + // our visible region + recomputeVisibleRegions = true; + } + sp<GraphicBuffer> newFrontBuffer(getBuffer(buf)); if (newFrontBuffer != NULL) { // get the dirty region @@ -712,9 +721,9 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const snprintf(buffer, SIZE, " " "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u]," - " freezeLock=%p, bypass=%d, dq-q-time=%u us\n", + " freezeLock=%p, dq-q-time=%u us\n", mFormat, w0, h0, s0, w1, h1, s1, - getFreezeLock().get(), mBypassState, totalTime); + getFreezeLock().get(), totalTime); result.append(buffer); } @@ -779,7 +788,7 @@ Layer::ClientRef::Access::~Access() Layer::BufferManager::BufferManager(TextureManager& tm) : mNumBuffers(NUM_BUFFERS), mTextureManager(tm), - mActiveBuffer(-1), mFailover(false) + mActiveBufferIndex(-1), mFailover(false) { } @@ -787,9 +796,52 @@ Layer::BufferManager::~BufferManager() { } -status_t Layer::BufferManager::resize(size_t size) +status_t Layer::BufferManager::resize(size_t size, + const sp<SurfaceFlinger>& flinger, EGLDisplay dpy) { Mutex::Autolock _l(mLock); + + if (size < mNumBuffers) { + // Move the active texture into slot 0 + BufferData activeBufferData = mBufferData[mActiveBufferIndex]; + mBufferData[mActiveBufferIndex] = mBufferData[0]; + mBufferData[0] = activeBufferData; + mActiveBufferIndex = 0; + + // Free the buffers that are no longer needed. + for (size_t i = size; i < mNumBuffers; i++) { + mBufferData[i].buffer = 0; + + // Create a message to destroy the textures on SurfaceFlinger's GL + // thread. + class MessageDestroyTexture : public MessageBase { + Image mTexture; + EGLDisplay mDpy; + public: + MessageDestroyTexture(const Image& texture, EGLDisplay dpy) + : mTexture(texture), mDpy(dpy) { } + virtual bool handler() { + status_t err = Layer::BufferManager::destroyTexture( + &mTexture, mDpy); + LOGE_IF(err<0, "error destroying texture: %d (%s)", + mTexture.name, strerror(-err)); + return true; // XXX: err == 0; ???? + } + }; + + MessageDestroyTexture *msg = new MessageDestroyTexture( + mBufferData[i].texture, dpy); + + // Don't allow this texture to be cleaned up by + // BufferManager::destroy. + mBufferData[i].texture.name = -1U; + mBufferData[i].texture.image = EGL_NO_IMAGE_KHR; + + // Post the message to the SurfaceFlinger object. + flinger->postMessageAsync(msg); + } + } + mNumBuffers = size; return NO_ERROR; } @@ -800,33 +852,33 @@ sp<GraphicBuffer> Layer::BufferManager::getBuffer(size_t index) const { } status_t Layer::BufferManager::setActiveBufferIndex(size_t index) { - mActiveBuffer = index; + BufferData const * const buffers = mBufferData; + Mutex::Autolock _l(mLock); + mActiveBuffer = buffers[index].buffer; + mActiveBufferIndex = index; return NO_ERROR; } size_t Layer::BufferManager::getActiveBufferIndex() const { - return mActiveBuffer; + return mActiveBufferIndex; } Texture Layer::BufferManager::getActiveTexture() const { Texture res; - if (mFailover || mActiveBuffer<0) { + if (mFailover || mActiveBufferIndex<0) { res = mFailoverTexture; } else { - static_cast<Image&>(res) = mBufferData[mActiveBuffer].texture; + static_cast<Image&>(res) = mBufferData[mActiveBufferIndex].texture; } return res; } sp<GraphicBuffer> Layer::BufferManager::getActiveBuffer() const { - sp<GraphicBuffer> result; - const ssize_t activeBuffer = mActiveBuffer; - if (activeBuffer >= 0) { - BufferData const * const buffers = mBufferData; - Mutex::Autolock _l(mLock); - result = buffers[activeBuffer].buffer; - } - return result; + return mActiveBuffer; +} + +bool Layer::BufferManager::hasActiveBuffer() const { + return mActiveBufferIndex >= 0; } sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index) @@ -871,7 +923,7 @@ status_t Layer::BufferManager::initEglImage(EGLDisplay dpy, const sp<GraphicBuffer>& buffer) { status_t err = NO_INIT; - ssize_t index = mActiveBuffer; + ssize_t index = mActiveBufferIndex; if (index >= 0) { if (!mFailover) { Image& texture(mBufferData[index].texture); |