diff options
Diffstat (limited to 'libs/surfaceflinger/Layer.cpp')
| -rw-r--r-- | libs/surfaceflinger/Layer.cpp | 630 |
1 files changed, 0 insertions, 630 deletions
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp deleted file mode 100644 index ce7e9aa..0000000 --- a/libs/surfaceflinger/Layer.cpp +++ /dev/null @@ -1,630 +0,0 @@ -/* - * 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. - */ - -#include <stdlib.h> -#include <stdint.h> -#include <sys/types.h> - -#include <cutils/properties.h> -#include <cutils/native_handle.h> - -#include <utils/Errors.h> -#include <utils/Log.h> -#include <utils/StopWatch.h> - -#include <ui/GraphicBuffer.h> -#include <ui/PixelFormat.h> - -#include <surfaceflinger/Surface.h> - -#include "clz.h" -#include "Layer.h" -#include "SurfaceFlinger.h" -#include "DisplayHardware/DisplayHardware.h" - - -#define DEBUG_RESIZE 0 - - -namespace android { - -template <typename T> inline T min(T a, T b) { - return a<b ? a : b; -} - -// --------------------------------------------------------------------------- - -const uint32_t Layer::typeInfo = LayerBaseClient::typeInfo | 4; -const char* const Layer::typeID = "Layer"; - -// --------------------------------------------------------------------------- - -Layer::Layer(SurfaceFlinger* flinger, DisplayID display, - const sp<Client>& c, int32_t i) - : LayerBaseClient(flinger, display, c, i), - mSecure(false), - mNoEGLImageForSwBuffers(false), - mNeedsBlending(true), - mNeedsDithering(false) -{ - // no OpenGL operation is possible here, since we might not be - // in the OpenGL thread. - mFrontBufferIndex = lcblk->getFrontBuffer(); -} - -Layer::~Layer() -{ - destroy(); - // the actual buffers will be destroyed here -} - -void Layer::destroy() -{ - for (size_t i=0 ; i<NUM_BUFFERS ; i++) { - if (mTextures[i].name != -1U) { - glDeleteTextures(1, &mTextures[i].name); - mTextures[i].name = -1U; - } - if (mTextures[i].image != EGL_NO_IMAGE_KHR) { - EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); - eglDestroyImageKHR(dpy, mTextures[i].image); - mTextures[i].image = EGL_NO_IMAGE_KHR; - } - Mutex::Autolock _l(mLock); - mBuffers[i].clear(); - mWidth = mHeight = 0; - } - mSurface.clear(); -} - -sp<LayerBaseClient::Surface> Layer::createSurface() const -{ - return mSurface; -} - -status_t Layer::ditch() -{ - // the layer is not on screen anymore. free as much resources as possible - mFreezeLock.clear(); - destroy(); - return NO_ERROR; -} - -status_t Layer::setBuffers( uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags) -{ - // this surfaces pixel format - PixelFormatInfo info; - status_t err = getPixelFormatInfo(format, &info); - if (err) return err; - - // the display's pixel format - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - uint32_t const maxSurfaceDims = min( - hw.getMaxTextureSize(), hw.getMaxViewportDims()); - - // never allow a surface larger than what our underlying GL implementation - // can handle. - if ((uint32_t(w)>maxSurfaceDims) || (uint32_t(h)>maxSurfaceDims)) { - return BAD_VALUE; - } - - PixelFormatInfo displayInfo; - getPixelFormatInfo(hw.getFormat(), &displayInfo); - const uint32_t hwFlags = hw.getFlags(); - - mFormat = format; - mWidth = w; - mHeight = h; - mSecure = (flags & ISurfaceComposer::eSecure) ? true : false; - mNeedsBlending = (info.h_alpha - info.l_alpha) > 0; - mNoEGLImageForSwBuffers = !(hwFlags & DisplayHardware::CACHED_BUFFERS); - - // we use the red index - int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED); - int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED); - mNeedsDithering = layerRedsize > displayRedSize; - - for (size_t i=0 ; i<NUM_BUFFERS ; i++) { - mBuffers[i] = new GraphicBuffer(); - } - mSurface = new SurfaceLayer(mFlinger, clientIndex(), this); - return NO_ERROR; -} - -void Layer::reloadTexture(const Region& dirty) -{ - Mutex::Autolock _l(mLock); - sp<GraphicBuffer> buffer(getFrontBufferLocked()); - if (buffer == NULL) { - // this situation can happen if we ran out of memory for instance. - // not much we can do. continue to use whatever texture was bound - // to this context. - return; - } - - const int index = mFrontBufferIndex; - - // create the new texture name if needed - if (UNLIKELY(mTextures[index].name == -1U)) { - mTextures[index].name = createTexture(); - mTextures[index].width = 0; - mTextures[index].height = 0; - } - -#ifdef EGL_ANDROID_image_native_buffer - if (mFlags & DisplayHardware::DIRECT_TEXTURE) { - if (buffer->usage & GraphicBuffer::USAGE_HW_TEXTURE) { - if (mTextures[index].dirty) { - if (initializeEglImage(buffer, &mTextures[index]) != NO_ERROR) { - // not sure what we can do here... - mFlags &= ~DisplayHardware::DIRECT_TEXTURE; - goto slowpath; - } - } - } else { - if (mHybridBuffer==0 || (mHybridBuffer->width != buffer->width || - mHybridBuffer->height != buffer->height)) { - mHybridBuffer.clear(); - mHybridBuffer = new GraphicBuffer( - buffer->width, buffer->height, buffer->format, - GraphicBuffer::USAGE_SW_WRITE_OFTEN | - GraphicBuffer::USAGE_HW_TEXTURE); - if (initializeEglImage( - mHybridBuffer, &mTextures[0]) != NO_ERROR) { - // not sure what we can do here... - mFlags &= ~DisplayHardware::DIRECT_TEXTURE; - mHybridBuffer.clear(); - goto slowpath; - } - } - - GGLSurface t; - status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN); - LOGE_IF(res, "error %d (%s) locking buffer %p", - res, strerror(res), buffer.get()); - if (res == NO_ERROR) { - Texture* const texture(&mTextures[0]); - - glBindTexture(GL_TEXTURE_2D, texture->name); - - sp<GraphicBuffer> buf(mHybridBuffer); - void* vaddr; - res = buf->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, &vaddr); - if (res == NO_ERROR) { - int bpp = 0; - switch (t.format) { - case HAL_PIXEL_FORMAT_RGB_565: - case HAL_PIXEL_FORMAT_RGBA_4444: - bpp = 2; - break; - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - bpp = 4; - break; - default: - if (isSupportedYuvFormat(t.format)) { - // just show the Y plane of YUV buffers - bpp = 1; - break; - } - // oops, we don't handle this format! - LOGE("layer %p, texture=%d, using format %d, which is not " - "supported by the GL", this, texture->name, t.format); - } - if (bpp) { - const Rect bounds(dirty.getBounds()); - size_t src_stride = t.stride; - size_t dst_stride = buf->stride; - if (src_stride == dst_stride && - bounds.width() == t.width && - bounds.height() == t.height) - { - memcpy(vaddr, t.data, t.height * t.stride * bpp); - } else { - GLubyte const * src = t.data + - (bounds.left + bounds.top * src_stride) * bpp; - GLubyte * dst = (GLubyte *)vaddr + - (bounds.left + bounds.top * dst_stride) * bpp; - const size_t length = bounds.width() * bpp; - size_t h = bounds.height(); - src_stride *= bpp; - dst_stride *= bpp; - while (h--) { - memcpy(dst, src, length); - dst += dst_stride; - src += src_stride; - } - } - } - buf->unlock(); - } - buffer->unlock(); - } - } - } else -#endif - { -slowpath: - for (size_t i=0 ; i<NUM_BUFFERS ; i++) { - mTextures[i].image = EGL_NO_IMAGE_KHR; - } - GGLSurface t; - status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN); - LOGE_IF(res, "error %d (%s) locking buffer %p", - res, strerror(res), buffer.get()); - if (res == NO_ERROR) { - loadTexture(&mTextures[0], dirty, t); - buffer->unlock(); - } - } -} - -void Layer::onDraw(const Region& clip) const -{ - int index = mFrontBufferIndex; - if (mTextures[index].image == EGL_NO_IMAGE_KHR) - index = 0; - GLuint textureName = mTextures[index].name; - if (UNLIKELY(textureName == -1LU)) { - // the texture has not been created yet, this Layer has - // in fact never been drawn into. This happens frequently with - // SurfaceView because the WindowManager can't know when the client - // has drawn the first time. - - // If there is nothing under us, we paint the screen in black, otherwise - // we just skip this update. - - // figure out if there is something below us - Region under; - const SurfaceFlinger::LayerVector& drawingLayers(mFlinger->mDrawingState.layersSortedByZ); - const size_t count = drawingLayers.size(); - for (size_t i=0 ; i<count ; ++i) { - const sp<LayerBase>& layer(drawingLayers[i]); - if (layer.get() == static_cast<LayerBase const*>(this)) - break; - under.orSelf(layer->visibleRegionScreen); - } - // if not everything below us is covered, we plug the holes! - Region holes(clip.subtract(under)); - if (!holes.isEmpty()) { - clearWithOpenGL(holes); - } - return; - } - drawWithOpenGL(clip, mTextures[index]); -} - -sp<GraphicBuffer> Layer::requestBuffer(int index, int usage) -{ - sp<GraphicBuffer> buffer; - - // this ensures our client doesn't go away while we're accessing - // the shared area. - sp<Client> ourClient(client.promote()); - if (ourClient == 0) { - // oops, the client is already gone - return buffer; - } - - /* - * This is called from the client's Surface::dequeue(). This can happen - * at any time, especially while we're in the middle of using the - * buffer 'index' as our front buffer. - * - * Make sure the buffer we're resizing is not the front buffer and has been - * dequeued. Once this condition is asserted, we are guaranteed that this - * buffer cannot become the front buffer under our feet, since we're called - * from Surface::dequeue() - */ - status_t err = lcblk->assertReallocate(index); - LOGE_IF(err, "assertReallocate(%d) failed (%s)", index, strerror(-err)); - if (err != NO_ERROR) { - // the surface may have died - return buffer; - } - - uint32_t w, h; - { // scope for the lock - Mutex::Autolock _l(mLock); - w = mWidth; - h = mHeight; - buffer = mBuffers[index]; - - // destroy() could have been called before we get here, we log it - // because it's uncommon, and the code below should handle it - LOGW_IF(buffer==0, - "mBuffers[%d] is null (mWidth=%d, mHeight=%d)", - index, w, h); - - mBuffers[index].clear(); - } - - const uint32_t effectiveUsage = getEffectiveUsage(usage); - if (buffer!=0 && buffer->getStrongCount() == 1) { - err = buffer->reallocate(w, h, mFormat, effectiveUsage); - } else { - // here we have to reallocate a new buffer because we could have a - // client in our process with a reference to it (eg: status bar), - // and we can't release the handle under its feet. - buffer.clear(); - buffer = new GraphicBuffer(w, h, mFormat, effectiveUsage); - err = buffer->initCheck(); - } - - if (err || buffer->handle == 0) { - LOGE_IF(err || buffer->handle == 0, - "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d failed (%s)", - this, index, w, h, strerror(-err)); - } else { - LOGD_IF(DEBUG_RESIZE, - "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d, handle=%p", - this, index, w, h, buffer->handle); - } - - if (err == NO_ERROR && buffer->handle != 0) { - Mutex::Autolock _l(mLock); - if (mWidth && mHeight) { - // and we have new buffer - mBuffers[index] = buffer; - // texture is now dirty... - mTextures[index].dirty = true; - } else { - // oops we got killed while we were allocating the buffer - buffer.clear(); - } - } - return buffer; -} - -uint32_t Layer::getEffectiveUsage(uint32_t usage) const -{ - /* - * buffers used for software rendering, but h/w composition - * are allocated with SW_READ_OFTEN | SW_WRITE_OFTEN | HW_TEXTURE - * - * buffers used for h/w rendering and h/w composition - * are allocated with HW_RENDER | HW_TEXTURE - * - * buffers used with h/w rendering and either NPOT or no egl_image_ext - * are allocated with SW_READ_RARELY | HW_RENDER - * - */ - - if (mSecure) { - // secure buffer, don't store it into the GPU - usage = GraphicBuffer::USAGE_SW_READ_OFTEN | - GraphicBuffer::USAGE_SW_WRITE_OFTEN; - } else { - // it's allowed to modify the usage flags here, but generally - // the requested flags should be honored. - if (mNoEGLImageForSwBuffers) { - if (usage & GraphicBuffer::USAGE_HW_MASK) { - // request EGLImage for h/w buffers only - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - } - } else { - // request EGLImage for all buffers - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - } - } - return usage; -} - -uint32_t Layer::doTransaction(uint32_t flags) -{ - const Layer::State& front(drawingState()); - const Layer::State& temp(currentState()); - - if ((front.requested_w != temp.requested_w) || - (front.requested_h != temp.requested_h)) { - // the size changed, we need to ask our client to request a new buffer - LOGD_IF(DEBUG_RESIZE, - "resize (layer=%p), requested (%dx%d), " - "drawing (%d,%d), (%dx%d), (%dx%d)", - this, - int(temp.requested_w), int(temp.requested_h), - int(front.requested_w), int(front.requested_h), - int(mBuffers[0]->getWidth()), int(mBuffers[0]->getHeight()), - int(mBuffers[1]->getWidth()), int(mBuffers[1]->getHeight())); - - // we're being resized and there is a freeze display request, - // acquire a freeze lock, so that the screen stays put - // until we've redrawn at the new size; this is to avoid - // glitches upon orientation changes. - if (mFlinger->hasFreezeRequest()) { - // if the surface is hidden, don't try to acquire the - // freeze lock, since hidden surfaces may never redraw - if (!(front.flags & ISurfaceComposer::eLayerHidden)) { - mFreezeLock = mFlinger->getFreezeLock(); - } - } - - // this will make sure LayerBase::doTransaction doesn't update - // the drawing state's size - Layer::State& editDraw(mDrawingState); - editDraw.requested_w = temp.requested_w; - editDraw.requested_h = temp.requested_h; - - // record the new size, form this point on, when the client request a - // buffer, it'll get the new size. - setDrawingSize(temp.requested_w, temp.requested_h); - - // all buffers need reallocation - lcblk->reallocate(); - } - - if (temp.sequence != front.sequence) { - if (temp.flags & ISurfaceComposer::eLayerHidden || temp.alpha == 0) { - // this surface is now hidden, so it shouldn't hold a freeze lock - // (it may never redraw, which is fine if it is hidden) - mFreezeLock.clear(); - } - } - - return LayerBase::doTransaction(flags); -} - -void Layer::setDrawingSize(uint32_t w, uint32_t h) { - Mutex::Autolock _l(mLock); - mWidth = w; - mHeight = h; -} - -// ---------------------------------------------------------------------------- -// pageflip handling... -// ---------------------------------------------------------------------------- - -void Layer::lockPageFlip(bool& recomputeVisibleRegions) -{ - ssize_t buf = lcblk->retireAndLock(); - if (buf < NO_ERROR) { - //LOGW("nothing to retire (%s)", strerror(-buf)); - // NOTE: here the buffer is locked because we will used - // for composition later in the loop - return; - } - - // ouch, this really should never happen - if (uint32_t(buf)>=NUM_BUFFERS) { - LOGE("retireAndLock() buffer index (%d) out of range", buf); - mPostedDirtyRegion.clear(); - return; - } - - // we retired a buffer, which becomes the new front buffer - mFrontBufferIndex = buf; - - // get the dirty region - sp<GraphicBuffer> newFrontBuffer(getBuffer(buf)); - if (newFrontBuffer != NULL) { - // compute the posted region - const Region dirty(lcblk->getDirtyRegion(buf)); - mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() ); - - // update the layer size and release freeze-lock - const Layer::State& front(drawingState()); - if (newFrontBuffer->getWidth() == front.requested_w && - newFrontBuffer->getHeight() == front.requested_h) - { - if ((front.w != front.requested_w) || - (front.h != front.requested_h)) - { - // Here we pretend the transaction happened by updating the - // current and drawing states. Drawing state is only accessed - // in this thread, no need to have it locked - Layer::State& editDraw(mDrawingState); - editDraw.w = editDraw.requested_w; - editDraw.h = editDraw.requested_h; - - // We also need to update the current state so that we don't - // end-up doing too much work during the next transaction. - // NOTE: We actually don't need hold the transaction lock here - // because State::w and State::h are only accessed from - // this thread - Layer::State& editTemp(currentState()); - editTemp.w = editDraw.w; - editTemp.h = editDraw.h; - - // recompute visible region - recomputeVisibleRegions = true; - } - - // we now have the correct size, unfreeze the screen - mFreezeLock.clear(); - } - } else { - // this should not happen unless we ran out of memory while - // allocating the buffer. we're hoping that things will get back - // to normal the next time the app tries to draw into this buffer. - // meanwhile, pretend the screen didn't update. - mPostedDirtyRegion.clear(); - } - - if (lcblk->getQueuedCount()) { - // signal an event if we have more buffers waiting - mFlinger->signalEvent(); - } - - if (!mPostedDirtyRegion.isEmpty()) { - reloadTexture( mPostedDirtyRegion ); - } -} - -void Layer::unlockPageFlip( - const Transform& planeTransform, Region& outDirtyRegion) -{ - Region dirtyRegion(mPostedDirtyRegion); - if (!dirtyRegion.isEmpty()) { - mPostedDirtyRegion.clear(); - // The dirty region is given in the layer's coordinate space - // transform the dirty region by the surface's transformation - // and the global transformation. - const Layer::State& s(drawingState()); - const Transform tr(planeTransform * s.transform); - dirtyRegion = tr.transform(dirtyRegion); - - // At this point, the dirty region is in screen space. - // Make sure it's constrained by the visible region (which - // is in screen space as well). - dirtyRegion.andSelf(visibleRegionScreen); - outDirtyRegion.orSelf(dirtyRegion); - } - if (visibleRegionScreen.isEmpty()) { - // an invisible layer should not hold a freeze-lock - // (because it may never be updated and thereore never release it) - mFreezeLock.clear(); - } -} - -void Layer::finishPageFlip() -{ - status_t err = lcblk->unlock( mFrontBufferIndex ); - LOGE_IF(err!=NO_ERROR, - "layer %p, buffer=%d wasn't locked!", - this, mFrontBufferIndex); -} - -// --------------------------------------------------------------------------- - -Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger, - SurfaceID id, const sp<Layer>& owner) - : Surface(flinger, id, owner->getIdentity(), owner) -{ -} - -Layer::SurfaceLayer::~SurfaceLayer() -{ -} - -sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, int usage) -{ - sp<GraphicBuffer> buffer; - sp<Layer> owner(getOwner()); - if (owner != 0) { - LOGE_IF(uint32_t(index)>=NUM_BUFFERS, - "getBuffer() index (%d) out of range", index); - if (uint32_t(index) < NUM_BUFFERS) { - buffer = owner->requestBuffer(index, usage); - } - } - return buffer; -} - -// --------------------------------------------------------------------------- - - -}; // namespace android |
