|  | /* | 
|  | * 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 <math.h> | 
|  | #include <sys/types.h> | 
|  |  | 
|  | #include <utils/Errors.h> | 
|  | #include <utils/Log.h> | 
|  | #include <utils/StopWatch.h> | 
|  |  | 
|  | #include <ui/GraphicBuffer.h> | 
|  | #include <ui/PixelFormat.h> | 
|  | #include <ui/FramebufferNativeWindow.h> | 
|  | #include <ui/Rect.h> | 
|  | #include <ui/Region.h> | 
|  |  | 
|  | #include <hardware/copybit.h> | 
|  |  | 
|  | #include "LayerBuffer.h" | 
|  | #include "SurfaceFlinger.h" | 
|  | #include "DisplayHardware/DisplayHardware.h" | 
|  |  | 
|  | namespace android { | 
|  |  | 
|  | // --------------------------------------------------------------------------- | 
|  |  | 
|  | gralloc_module_t const* LayerBuffer::sGrallocModule = 0; | 
|  |  | 
|  | // --------------------------------------------------------------------------- | 
|  |  | 
|  | LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display, | 
|  | const sp<Client>& client) | 
|  | : LayerBaseClient(flinger, display, client), | 
|  | mNeedsBlending(false), mBlitEngine(0) | 
|  | { | 
|  | } | 
|  |  | 
|  | LayerBuffer::~LayerBuffer() | 
|  | { | 
|  | if (mBlitEngine) { | 
|  | copybit_close(mBlitEngine); | 
|  | } | 
|  | } | 
|  |  | 
|  | void LayerBuffer::onFirstRef() | 
|  | { | 
|  | LayerBaseClient::onFirstRef(); | 
|  | mSurface = new SurfaceLayerBuffer(mFlinger, this); | 
|  |  | 
|  | hw_module_t const* module = (hw_module_t const*)sGrallocModule; | 
|  | if (!module) { | 
|  | // NOTE: technically there is a race here, but it shouldn't | 
|  | // cause any problem since hw_get_module() always returns | 
|  | // the same value. | 
|  | if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { | 
|  | sGrallocModule = (gralloc_module_t const *)module; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) { | 
|  | copybit_open(module, &mBlitEngine); | 
|  | } | 
|  | } | 
|  |  | 
|  | sp<LayerBaseClient::Surface> LayerBuffer::createSurface() const | 
|  | { | 
|  | return mSurface; | 
|  | } | 
|  |  | 
|  | status_t LayerBuffer::ditch() | 
|  | { | 
|  | mSurface.clear(); | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | bool LayerBuffer::needsBlending() const { | 
|  | return mNeedsBlending; | 
|  | } | 
|  |  | 
|  | void LayerBuffer::setNeedsBlending(bool blending) { | 
|  | mNeedsBlending = blending; | 
|  | } | 
|  |  | 
|  | void LayerBuffer::postBuffer(ssize_t offset) | 
|  | { | 
|  | sp<Source> source(getSource()); | 
|  | if (source != 0) | 
|  | source->postBuffer(offset); | 
|  | } | 
|  |  | 
|  | void LayerBuffer::unregisterBuffers() | 
|  | { | 
|  | sp<Source> source(clearSource()); | 
|  | if (source != 0) | 
|  | source->unregisterBuffers(); | 
|  | } | 
|  |  | 
|  | uint32_t LayerBuffer::doTransaction(uint32_t flags) | 
|  | { | 
|  | sp<Source> source(getSource()); | 
|  | if (source != 0) | 
|  | source->onTransaction(flags); | 
|  | uint32_t res = LayerBase::doTransaction(flags); | 
|  | // we always want filtering for these surfaces | 
|  | mNeedsFiltering = !(mFlags & DisplayHardware::SLOW_CONFIG); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | void LayerBuffer::unlockPageFlip(const Transform& planeTransform, | 
|  | Region& outDirtyRegion) | 
|  | { | 
|  | // this code-path must be as tight as possible, it's called each time | 
|  | // the screen is composited. | 
|  | sp<Source> source(getSource()); | 
|  | if (source != 0) | 
|  | source->onVisibilityResolved(planeTransform); | 
|  | LayerBase::unlockPageFlip(planeTransform, outDirtyRegion); | 
|  | } | 
|  |  | 
|  | void LayerBuffer::onDraw(const Region& clip) const | 
|  | { | 
|  | sp<Source> source(getSource()); | 
|  | if (LIKELY(source != 0)) { | 
|  | source->onDraw(clip); | 
|  | } else { | 
|  | clearWithOpenGL(clip); | 
|  | } | 
|  | } | 
|  |  | 
|  | void LayerBuffer::serverDestroy() | 
|  | { | 
|  | sp<Source> source(clearSource()); | 
|  | if (source != 0) { | 
|  | source->destroy(); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This creates a "buffer" source for this surface | 
|  | */ | 
|  | status_t LayerBuffer::registerBuffers(const ISurface::BufferHeap& buffers) | 
|  | { | 
|  | Mutex::Autolock _l(mLock); | 
|  | if (mSource != 0) | 
|  | return INVALID_OPERATION; | 
|  |  | 
|  | sp<BufferSource> source = new BufferSource(*this, buffers); | 
|  |  | 
|  | status_t result = source->getStatus(); | 
|  | if (result == NO_ERROR) { | 
|  | mSource = source; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This creates an "overlay" source for this surface | 
|  | */ | 
|  | sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f, | 
|  | int32_t orientation) | 
|  | { | 
|  | sp<OverlayRef> result; | 
|  | Mutex::Autolock _l(mLock); | 
|  | if (mSource != 0) | 
|  | return result; | 
|  |  | 
|  | sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f, orientation); | 
|  | if (result != 0) { | 
|  | mSource = source; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | sp<LayerBuffer::Source> LayerBuffer::getSource() const { | 
|  | Mutex::Autolock _l(mLock); | 
|  | return mSource; | 
|  | } | 
|  |  | 
|  | sp<LayerBuffer::Source> LayerBuffer::clearSource() { | 
|  | sp<Source> source; | 
|  | Mutex::Autolock _l(mLock); | 
|  | source = mSource; | 
|  | mSource.clear(); | 
|  | return source; | 
|  | } | 
|  |  | 
|  | // ============================================================================ | 
|  | // LayerBuffer::SurfaceLayerBuffer | 
|  | // ============================================================================ | 
|  |  | 
|  | LayerBuffer::SurfaceLayerBuffer::SurfaceLayerBuffer( | 
|  | const sp<SurfaceFlinger>& flinger, const sp<LayerBuffer>& owner) | 
|  | : LayerBaseClient::Surface(flinger, owner->getIdentity(), owner) | 
|  | { | 
|  | } | 
|  |  | 
|  | LayerBuffer::SurfaceLayerBuffer::~SurfaceLayerBuffer() | 
|  | { | 
|  | unregisterBuffers(); | 
|  | } | 
|  |  | 
|  | status_t LayerBuffer::SurfaceLayerBuffer::registerBuffers( | 
|  | const ISurface::BufferHeap& buffers) | 
|  | { | 
|  | sp<LayerBuffer> owner(getOwner()); | 
|  | if (owner != 0) | 
|  | return owner->registerBuffers(buffers); | 
|  | return NO_INIT; | 
|  | } | 
|  |  | 
|  | void LayerBuffer::SurfaceLayerBuffer::postBuffer(ssize_t offset) | 
|  | { | 
|  | sp<LayerBuffer> owner(getOwner()); | 
|  | if (owner != 0) | 
|  | owner->postBuffer(offset); | 
|  | } | 
|  |  | 
|  | void LayerBuffer::SurfaceLayerBuffer::unregisterBuffers() | 
|  | { | 
|  | sp<LayerBuffer> owner(getOwner()); | 
|  | if (owner != 0) | 
|  | owner->unregisterBuffers(); | 
|  | } | 
|  |  | 
|  | sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::createOverlay( | 
|  | uint32_t w, uint32_t h, int32_t format, int32_t orientation) { | 
|  | sp<OverlayRef> result; | 
|  | sp<LayerBuffer> owner(getOwner()); | 
|  | if (owner != 0) | 
|  | result = owner->createOverlay(w, h, format, orientation); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // ============================================================================ | 
|  | // LayerBuffer::Buffer | 
|  | // ============================================================================ | 
|  |  | 
|  | LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, | 
|  | ssize_t offset, size_t bufferSize) | 
|  | : mBufferHeap(buffers), mSupportsCopybit(false) | 
|  | { | 
|  | NativeBuffer& src(mNativeBuffer); | 
|  | src.crop.l = 0; | 
|  | src.crop.t = 0; | 
|  | src.crop.r = buffers.w; | 
|  | src.crop.b = buffers.h; | 
|  |  | 
|  | src.img.w       = buffers.hor_stride ?: buffers.w; | 
|  | src.img.h       = buffers.ver_stride ?: buffers.h; | 
|  | src.img.format  = buffers.format; | 
|  | src.img.base    = (void*)(intptr_t(buffers.heap->base()) + offset); | 
|  | src.img.handle  = 0; | 
|  |  | 
|  | gralloc_module_t const * module = LayerBuffer::getGrallocModule(); | 
|  | if (module && module->perform) { | 
|  | int err = module->perform(module, | 
|  | GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER, | 
|  | buffers.heap->heapID(), bufferSize, | 
|  | offset, buffers.heap->base(), | 
|  | &src.img.handle); | 
|  |  | 
|  | // we can fail here is the passed buffer is purely software | 
|  | mSupportsCopybit = (err == NO_ERROR); | 
|  | } | 
|  | } | 
|  |  | 
|  | LayerBuffer::Buffer::~Buffer() | 
|  | { | 
|  | NativeBuffer& src(mNativeBuffer); | 
|  | if (src.img.handle) { | 
|  | native_handle_delete(src.img.handle); | 
|  | } | 
|  | } | 
|  |  | 
|  | // ============================================================================ | 
|  | // LayerBuffer::Source | 
|  | // LayerBuffer::BufferSource | 
|  | // LayerBuffer::OverlaySource | 
|  | // ============================================================================ | 
|  |  | 
|  | LayerBuffer::Source::Source(LayerBuffer& layer) | 
|  | : mLayer(layer) | 
|  | { | 
|  | } | 
|  | LayerBuffer::Source::~Source() { | 
|  | } | 
|  | void LayerBuffer::Source::onDraw(const Region& clip) const { | 
|  | } | 
|  | void LayerBuffer::Source::onTransaction(uint32_t flags) { | 
|  | } | 
|  | void LayerBuffer::Source::onVisibilityResolved( | 
|  | const Transform& planeTransform) { | 
|  | } | 
|  | void LayerBuffer::Source::postBuffer(ssize_t offset) { | 
|  | } | 
|  | void LayerBuffer::Source::unregisterBuffers() { | 
|  | } | 
|  |  | 
|  | // --------------------------------------------------------------------------- | 
|  |  | 
|  | LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer, | 
|  | const ISurface::BufferHeap& buffers) | 
|  | : Source(layer), mStatus(NO_ERROR), mBufferSize(0) | 
|  | { | 
|  | if (buffers.heap == NULL) { | 
|  | // this is allowed, but in this case, it is illegal to receive | 
|  | // postBuffer(). The surface just erases the framebuffer with | 
|  | // fully transparent pixels. | 
|  | mBufferHeap = buffers; | 
|  | mLayer.setNeedsBlending(false); | 
|  | return; | 
|  | } | 
|  |  | 
|  | status_t err = (buffers.heap->heapID() >= 0) ? NO_ERROR : NO_INIT; | 
|  | if (err != NO_ERROR) { | 
|  | LOGE("LayerBuffer::BufferSource: invalid heap (%s)", strerror(err)); | 
|  | mStatus = err; | 
|  | return; | 
|  | } | 
|  |  | 
|  | PixelFormatInfo info; | 
|  | err = getPixelFormatInfo(buffers.format, &info); | 
|  | if (err != NO_ERROR) { | 
|  | LOGE("LayerBuffer::BufferSource: invalid format %d (%s)", | 
|  | buffers.format, strerror(err)); | 
|  | mStatus = err; | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (buffers.hor_stride<0 || buffers.ver_stride<0) { | 
|  | LOGE("LayerBuffer::BufferSource: invalid parameters " | 
|  | "(w=%d, h=%d, xs=%d, ys=%d)", | 
|  | buffers.w, buffers.h, buffers.hor_stride, buffers.ver_stride); | 
|  | mStatus = BAD_VALUE; | 
|  | return; | 
|  | } | 
|  |  | 
|  | mBufferHeap = buffers; | 
|  | mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0); | 
|  | mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride; | 
|  | mLayer.forceVisibilityTransaction(); | 
|  | } | 
|  |  | 
|  | LayerBuffer::BufferSource::~BufferSource() | 
|  | { | 
|  | class MessageDestroyTexture : public MessageBase { | 
|  | SurfaceFlinger* flinger; | 
|  | GLuint name; | 
|  | public: | 
|  | MessageDestroyTexture( | 
|  | SurfaceFlinger* flinger, GLuint name) | 
|  | : flinger(flinger), name(name) { } | 
|  | virtual bool handler() { | 
|  | glDeleteTextures(1, &name); | 
|  | return true; | 
|  | } | 
|  | }; | 
|  |  | 
|  | if (mTexture.name != -1U) { | 
|  | // GL textures can only be destroyed from the GL thread | 
|  | getFlinger()->mEventQueue.postMessage( | 
|  | new MessageDestroyTexture(getFlinger(), mTexture.name) ); | 
|  | } | 
|  | if (mTexture.image != EGL_NO_IMAGE_KHR) { | 
|  | EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay()); | 
|  | eglDestroyImageKHR(dpy, mTexture.image); | 
|  | } | 
|  | } | 
|  |  | 
|  | void LayerBuffer::BufferSource::postBuffer(ssize_t offset) | 
|  | { | 
|  | ISurface::BufferHeap buffers; | 
|  | { // scope for the lock | 
|  | Mutex::Autolock _l(mBufferSourceLock); | 
|  | buffers = mBufferHeap; | 
|  | if (buffers.heap != 0) { | 
|  | const size_t memorySize = buffers.heap->getSize(); | 
|  | if ((size_t(offset) + mBufferSize) > memorySize) { | 
|  | LOGE("LayerBuffer::BufferSource::postBuffer() " | 
|  | "invalid buffer (offset=%d, size=%d, heap-size=%d", | 
|  | int(offset), int(mBufferSize), int(memorySize)); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | sp<Buffer> buffer; | 
|  | if (buffers.heap != 0) { | 
|  | buffer = new LayerBuffer::Buffer(buffers, offset, mBufferSize); | 
|  | if (buffer->getStatus() != NO_ERROR) | 
|  | buffer.clear(); | 
|  | setBuffer(buffer); | 
|  | mLayer.invalidate(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void LayerBuffer::BufferSource::unregisterBuffers() | 
|  | { | 
|  | Mutex::Autolock _l(mBufferSourceLock); | 
|  | mBufferHeap.heap.clear(); | 
|  | mBuffer.clear(); | 
|  | mLayer.invalidate(); | 
|  | } | 
|  |  | 
|  | sp<LayerBuffer::Buffer> LayerBuffer::BufferSource::getBuffer() const | 
|  | { | 
|  | Mutex::Autolock _l(mBufferSourceLock); | 
|  | return mBuffer; | 
|  | } | 
|  |  | 
|  | void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer) | 
|  | { | 
|  | Mutex::Autolock _l(mBufferSourceLock); | 
|  | mBuffer = buffer; | 
|  | } | 
|  |  | 
|  | void LayerBuffer::BufferSource::onDraw(const Region& clip) const | 
|  | { | 
|  | sp<Buffer> ourBuffer(getBuffer()); | 
|  | if (UNLIKELY(ourBuffer == 0))  { | 
|  | // nothing to do, we don't have a buffer | 
|  | mLayer.clearWithOpenGL(clip); | 
|  | return; | 
|  | } | 
|  |  | 
|  | status_t err = NO_ERROR; | 
|  | NativeBuffer src(ourBuffer->getBuffer()); | 
|  | const Rect transformedBounds(mLayer.getTransformedBounds()); | 
|  |  | 
|  | #if defined(EGL_ANDROID_image_native_buffer) | 
|  | if (GLExtensions::getInstance().haveDirectTexture()) { | 
|  | err = INVALID_OPERATION; | 
|  | if (ourBuffer->supportsCopybit()) { | 
|  | copybit_device_t* copybit = mLayer.mBlitEngine; | 
|  | if (copybit && err != NO_ERROR) { | 
|  | // create our EGLImageKHR the first time | 
|  | err = initTempBuffer(); | 
|  | if (err == NO_ERROR) { | 
|  | // NOTE: Assume the buffer is allocated with the proper USAGE flags | 
|  | const NativeBuffer& dst(mTempBuffer); | 
|  | region_iterator clip(Region(Rect(dst.crop.r, dst.crop.b))); | 
|  | copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); | 
|  | copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF); | 
|  | copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE); | 
|  | err = copybit->stretch(copybit, &dst.img, &src.img, | 
|  | &dst.crop, &src.crop, &clip); | 
|  | if (err != NO_ERROR) { | 
|  | clearTempBufferImage(); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | #endif | 
|  | else { | 
|  | err = INVALID_OPERATION; | 
|  | } | 
|  |  | 
|  | if (err != NO_ERROR) { | 
|  | // slower fallback | 
|  | GGLSurface t; | 
|  | t.version = sizeof(GGLSurface); | 
|  | t.width  = src.crop.r; | 
|  | t.height = src.crop.b; | 
|  | t.stride = src.img.w; | 
|  | t.vstride= src.img.h; | 
|  | t.format = src.img.format; | 
|  | t.data = (GGLubyte*)src.img.base; | 
|  | const Region dirty(Rect(t.width, t.height)); | 
|  | mTextureManager.loadTexture(&mTexture, dirty, t); | 
|  | } | 
|  |  | 
|  | mTexture.transform = mBufferHeap.transform; | 
|  | mLayer.drawWithOpenGL(clip, mTexture); | 
|  | } | 
|  |  | 
|  | status_t LayerBuffer::BufferSource::initTempBuffer() const | 
|  | { | 
|  | // figure out the size we need now | 
|  | const ISurface::BufferHeap& buffers(mBufferHeap); | 
|  | uint32_t w = mLayer.mTransformedBounds.width(); | 
|  | uint32_t h = mLayer.mTransformedBounds.height(); | 
|  | if (buffers.w * h != buffers.h * w) { | 
|  | int t = w; w = h; h = t; | 
|  | } | 
|  |  | 
|  | // we're in the copybit case, so make sure we can handle this blit | 
|  | // we don't have to keep the aspect ratio here | 
|  | copybit_device_t* copybit = mLayer.mBlitEngine; | 
|  | const int down = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT); | 
|  | const int up = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT); | 
|  | if (buffers.w > w*down)     w = buffers.w / down; | 
|  | else if (w > buffers.w*up)  w = buffers.w*up; | 
|  | if (buffers.h > h*down)     h = buffers.h / down; | 
|  | else if (h > buffers.h*up)  h = buffers.h*up; | 
|  |  | 
|  | if (mTexture.image != EGL_NO_IMAGE_KHR) { | 
|  | // we have an EGLImage, make sure the needed size didn't change | 
|  | if (w!=mTexture.width || h!= mTexture.height) { | 
|  | // delete the EGLImage and texture | 
|  | clearTempBufferImage(); | 
|  | } else { | 
|  | // we're good, we have an EGLImageKHR and it's (still) the | 
|  | // right size | 
|  | return NO_ERROR; | 
|  | } | 
|  | } | 
|  |  | 
|  | // figure out if we need linear filtering | 
|  | if (buffers.w * h == buffers.h * w) { | 
|  | // same pixel area, don't use filtering | 
|  | mLayer.mNeedsFiltering = false; | 
|  | } | 
|  |  | 
|  | // Allocate a temporary buffer and create the corresponding EGLImageKHR | 
|  | // once the EGLImage has been created we don't need the | 
|  | // graphic buffer reference anymore. | 
|  | sp<GraphicBuffer> buffer = new GraphicBuffer( | 
|  | w, h, HAL_PIXEL_FORMAT_RGB_565, | 
|  | GraphicBuffer::USAGE_HW_TEXTURE | | 
|  | GraphicBuffer::USAGE_HW_2D); | 
|  |  | 
|  | status_t err = buffer->initCheck(); | 
|  | if (err == NO_ERROR) { | 
|  | NativeBuffer& dst(mTempBuffer); | 
|  | dst.img.w = buffer->getStride(); | 
|  | dst.img.h = h; | 
|  | dst.img.format = buffer->getPixelFormat(); | 
|  | dst.img.handle = (native_handle_t *)buffer->handle; | 
|  | dst.img.base = 0; | 
|  | dst.crop.l = 0; | 
|  | dst.crop.t = 0; | 
|  | dst.crop.r = w; | 
|  | dst.crop.b = h; | 
|  |  | 
|  | EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay()); | 
|  | err = mTextureManager.initEglImage(&mTexture, dpy, buffer); | 
|  | } | 
|  |  | 
|  | return err; | 
|  | } | 
|  |  | 
|  | void LayerBuffer::BufferSource::clearTempBufferImage() const | 
|  | { | 
|  | // delete the image | 
|  | EGLDisplay dpy(getFlinger()->graphicPlane(0).getEGLDisplay()); | 
|  | eglDestroyImageKHR(dpy, mTexture.image); | 
|  |  | 
|  | // and the associated texture (recreate a name) | 
|  | glDeleteTextures(1, &mTexture.name); | 
|  | Texture defaultTexture; | 
|  | mTexture = defaultTexture; | 
|  | } | 
|  |  | 
|  | // --------------------------------------------------------------------------- | 
|  |  | 
|  | LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer, | 
|  | sp<OverlayRef>* overlayRef, | 
|  | uint32_t w, uint32_t h, int32_t format, int32_t orientation) | 
|  | : Source(layer), mVisibilityChanged(false), | 
|  | mOverlay(0), mOverlayHandle(0), mOverlayDevice(0), mOrientation(orientation) | 
|  | { | 
|  | overlay_control_device_t* overlay_dev = getFlinger()->getOverlayEngine(); | 
|  | if (overlay_dev == NULL) { | 
|  | // overlays not supported | 
|  | return; | 
|  | } | 
|  |  | 
|  | mOverlayDevice = overlay_dev; | 
|  | overlay_t* overlay = overlay_dev->createOverlay(overlay_dev, w, h, format); | 
|  | if (overlay == NULL) { | 
|  | // couldn't create the overlay (no memory? no more overlays?) | 
|  | return; | 
|  | } | 
|  |  | 
|  | // enable dithering... | 
|  | overlay_dev->setParameter(overlay_dev, overlay, | 
|  | OVERLAY_DITHER, OVERLAY_ENABLE); | 
|  |  | 
|  | mOverlay = overlay; | 
|  | mWidth = overlay->w; | 
|  | mHeight = overlay->h; | 
|  | mFormat = overlay->format; | 
|  | mWidthStride = overlay->w_stride; | 
|  | mHeightStride = overlay->h_stride; | 
|  | mInitialized = false; | 
|  |  | 
|  | mOverlayHandle = overlay->getHandleRef(overlay); | 
|  |  | 
|  | sp<OverlayChannel> channel = new OverlayChannel( &layer ); | 
|  |  | 
|  | *overlayRef = new OverlayRef(mOverlayHandle, channel, | 
|  | mWidth, mHeight, mFormat, mWidthStride, mHeightStride); | 
|  | getFlinger()->signalEvent(); | 
|  | } | 
|  |  | 
|  | LayerBuffer::OverlaySource::~OverlaySource() | 
|  | { | 
|  | if (mOverlay && mOverlayDevice) { | 
|  | overlay_control_device_t* overlay_dev = mOverlayDevice; | 
|  | overlay_dev->destroyOverlay(overlay_dev, mOverlay); | 
|  | } | 
|  | } | 
|  |  | 
|  | void LayerBuffer::OverlaySource::onDraw(const Region& clip) const | 
|  | { | 
|  | // this would be where the color-key would be set, should we need it. | 
|  | GLclampf red = 0; | 
|  | GLclampf green = 0; | 
|  | GLclampf blue = 0; | 
|  | mLayer.clearWithOpenGL(clip, red, green, blue, 0); | 
|  | } | 
|  |  | 
|  | void LayerBuffer::OverlaySource::onTransaction(uint32_t flags) | 
|  | { | 
|  | const Layer::State& front(mLayer.drawingState()); | 
|  | const Layer::State& temp(mLayer.currentState()); | 
|  | if (temp.sequence != front.sequence) { | 
|  | mVisibilityChanged = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | void LayerBuffer::OverlaySource::onVisibilityResolved( | 
|  | const Transform& planeTransform) | 
|  | { | 
|  | // this code-path must be as tight as possible, it's called each time | 
|  | // the screen is composited. | 
|  | if (UNLIKELY(mOverlay != 0)) { | 
|  | if (mVisibilityChanged || !mInitialized) { | 
|  | mVisibilityChanged = false; | 
|  | mInitialized = true; | 
|  | const Rect bounds(mLayer.getTransformedBounds()); | 
|  | int x = bounds.left; | 
|  | int y = bounds.top; | 
|  | int w = bounds.width(); | 
|  | int h = bounds.height(); | 
|  |  | 
|  | // we need a lock here to protect "destroy" | 
|  | Mutex::Autolock _l(mOverlaySourceLock); | 
|  | if (mOverlay) { | 
|  | overlay_control_device_t* overlay_dev = mOverlayDevice; | 
|  | overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h); | 
|  | // we need to combine the layer orientation and the | 
|  | // user-requested orientation. | 
|  | Transform finalTransform = Transform(mOrientation) * | 
|  | Transform(mLayer.getOrientation()); | 
|  | overlay_dev->setParameter(overlay_dev, mOverlay, | 
|  | OVERLAY_TRANSFORM, finalTransform.getOrientation()); | 
|  | overlay_dev->commit(overlay_dev, mOverlay); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void LayerBuffer::OverlaySource::destroy() | 
|  | { | 
|  | // we need a lock here to protect "onVisibilityResolved" | 
|  | Mutex::Autolock _l(mOverlaySourceLock); | 
|  | if (mOverlay && mOverlayDevice) { | 
|  | overlay_control_device_t* overlay_dev = mOverlayDevice; | 
|  | overlay_dev->destroyOverlay(overlay_dev, mOverlay); | 
|  | mOverlay = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | // --------------------------------------------------------------------------- | 
|  | }; // namespace android |