Initial Contribution
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
new file mode 100644
index 0000000..d871fc3
--- /dev/null
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -0,0 +1,366 @@
+/*
+ * 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 "SurfaceFlinger"
+
+#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/PixelFormat.h>
+#include <ui/EGLDisplaySurface.h>
+
+#include "LayerBuffer.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+#include "DisplayHardware/DisplayHardware.h"
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerBuffer::typeInfo = LayerBaseClient::typeInfo | 0x20;
+const char* const LayerBuffer::typeID = "LayerBuffer";
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
+        Client* client, int32_t i)
+    : LayerBaseClient(flinger, display, client, i),
+    mBuffer(0), mTextureName(-1U), mInvalidate(false), mNeedsBlending(false)
+{
+}
+
+LayerBuffer::~LayerBuffer()
+{
+    sp<SurfaceBuffer> s(getClientSurface());
+    if (s != 0) {
+        s->disown();
+        mClientSurface.clear();
+    }
+
+    // this should always be called from the OpenGL thread
+    if (mTextureName != -1U) {
+        //glDeleteTextures(1, &mTextureName);
+        deletedTextures.add(mTextureName);
+    }
+    // to help debugging we set those to zero
+    mWidth = mHeight = 0;
+}
+
+bool LayerBuffer::needsBlending() const
+{
+    Mutex::Autolock _l(mLock);
+    return mNeedsBlending;
+}
+
+void LayerBuffer::onDraw(const Region& clip) const
+{
+    sp<Buffer> buffer(getBuffer());
+    if (UNLIKELY(buffer == 0))  {
+        // nothing to do, we don't have a buffer
+        clearWithOpenGL(clip);
+        return;
+    }
+
+    status_t err = NO_ERROR;
+    NativeBuffer src(buffer->getBuffer());
+    const int can_use_copybit = canUseCopybit();
+
+    if (can_use_copybit)  {
+        //StopWatch watch("MDP");
+
+        const int src_width  = src.crop.r - src.crop.l;
+        const int src_height = src.crop.b - src.crop.t;
+        int W = mTransformedBounds.width();
+        int H = mTransformedBounds.height();
+        if (getOrientation() & Transform::ROT_90) {
+            int t(W); W=H; H=t;
+        }
+
+        /* With LayerBuffer, it is likely that we'll have to rescale the
+         * surface, because this is often used for video playback or
+         * camera-preview. Since we want these operation as fast as possible
+         * we make sure we can use the 2D H/W even if it doesn't support
+         * the requested scale factor, in which case we perform the scaling
+         * in several passes. */
+
+        copybit_t* copybit = mFlinger->getBlitEngine();
+        const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
+        const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
+
+        float xscale = 1.0f;
+        if (src_width > W*min)          xscale = 1.0f / min;
+        else if (src_width*mag < W)     xscale = mag;
+
+        float yscale = 1.0f;
+        if (src_height > H*min)         yscale = 1.0f / min;
+        else if (src_height*mag < H)    yscale = mag;
+
+        if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) {
+            //LOGD("MDP scaling hack w=%d, h=%d, ww=%d, wh=%d, xs=%f, ys=%f",
+            //        src_width, src_height, W, H, xscale, yscale);
+
+            if (UNLIKELY(mTemporaryDealer == 0)) {
+                // allocate a memory-dealer for this the first time
+                mTemporaryDealer = mFlinger->getSurfaceHeapManager()
+                        ->createHeap(NATIVE_MEMORY_TYPE_PMEM);
+                mTempBitmap.init(mTemporaryDealer);
+            }
+
+            const int tmp_w = floorf(src_width  * xscale);
+            const int tmp_h = floorf(src_height * yscale);
+            err = mTempBitmap.setBits(tmp_w, tmp_h, 1, src.img.format);
+
+            if (LIKELY(err == NO_ERROR)) {
+                NativeBuffer tmp;
+                mTempBitmap.getBitmapSurface(&tmp.img);
+                tmp.crop.l = 0;
+                tmp.crop.t = 0;
+                tmp.crop.r = tmp.img.w;
+                tmp.crop.b = tmp.img.h;
+
+                region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b)));
+                copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+                copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+                copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+                err = copybit->stretch(copybit,
+                        &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it);
+                src = tmp;
+            }
+        }
+
+        const DisplayHardware& hw(graphicPlane(0).displayHardware());
+        copybit_image_t dst;
+        hw.getDisplaySurface(&dst);
+        const copybit_rect_t& drect
+                = reinterpret_cast<const copybit_rect_t&>(mTransformedBounds);
+        const State& s(drawingState());
+        region_iterator it(clip);
+        copybit->set_parameter(copybit, COPYBIT_TRANSFORM, getOrientation());
+        copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
+        copybit->set_parameter(copybit, COPYBIT_DITHER,
+                s.flags & ISurfaceComposer::eLayerDither ?
+                        COPYBIT_ENABLE : COPYBIT_DISABLE);
+        err = copybit->stretch(copybit,
+                &dst, &src.img, &drect, &src.crop, &it);
+    }
+
+    if (!can_use_copybit || err) {
+        if (UNLIKELY(mTextureName == -1LU)) {
+            mTextureName = createTexture();
+        }
+        GLuint w = 0;
+        GLuint h = 0;
+        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*)(intptr_t(src.img.base) + src.img.offset);
+        const Region dirty(Rect(t.width, t.height));
+        loadTexture(dirty, mTextureName, t, w, h);
+        drawWithOpenGL(clip, mTextureName, t);
+    }
+}
+
+void LayerBuffer::invalidateLocked()
+{
+    mInvalidate = true;
+    mFlinger->signalEvent();
+}
+
+void LayerBuffer::invalidate()
+{
+    Mutex::Autolock _l(mLock);
+    invalidateLocked();
+}
+
+void LayerBuffer::unlockPageFlip(const Transform& planeTransform,
+        Region& outDirtyRegion)
+{
+    Mutex::Autolock _l(mLock);
+    if (mInvalidate) {
+        mInvalidate = false;
+        outDirtyRegion.orSelf(visibleRegionScreen);
+    }
+}
+
+sp<LayerBuffer::SurfaceBuffer> LayerBuffer::getClientSurface() const
+{
+    Mutex::Autolock _l(mLock);
+    return mClientSurface.promote();
+}
+
+sp<LayerBaseClient::Surface> LayerBuffer::getSurface() const
+{
+    sp<SurfaceBuffer> s;
+    Mutex::Autolock _l(mLock);
+    s = mClientSurface.promote();
+    if (s == 0) {
+        s = new SurfaceBuffer(clientIndex(),
+                const_cast<LayerBuffer *>(this));
+        mClientSurface = s;
+    }
+    return s;
+}
+
+
+status_t LayerBuffer::registerBuffers(int w, int h, int hstride, int vstride,
+            PixelFormat format, const sp<IMemoryHeap>& memoryHeap)
+{
+    status_t err = (memoryHeap!=0 && memoryHeap->heapID() >= 0) ? NO_ERROR : NO_INIT;
+    if (err != NO_ERROR)
+        return err;
+
+    // TODO: validate format/parameters
+
+    Mutex::Autolock _l(mLock);
+    mHeap = memoryHeap;
+    mWidth = w;
+    mHeight = h;
+    mHStride = hstride;
+    mVStride = vstride;
+    mFormat = format;
+    PixelFormatInfo info;
+    getPixelFormatInfo(format, &info);
+    mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
+    return NO_ERROR;
+}
+
+void LayerBuffer::postBuffer(ssize_t offset)
+{
+    sp<IMemoryHeap> heap;
+    int w, h, hs, vs, f;
+    { // scope for the lock
+        Mutex::Autolock _l(mLock);
+        w = mWidth;
+        h = mHeight;
+        hs= mHStride;
+        vs= mVStride;
+        f = mFormat;
+        heap = mHeap;
+    }
+
+    sp<Buffer> buffer;
+    if (heap != 0) {
+        buffer = new Buffer(heap, offset, w, h, hs, vs, f);
+        if (buffer->getStatus() != NO_ERROR)
+            buffer.clear();
+        setBuffer(buffer);
+        invalidate();
+    }
+}
+
+void LayerBuffer::unregisterBuffers()
+{
+    Mutex::Autolock _l(mLock);
+    mHeap.clear();
+    mBuffer.clear();
+    invalidateLocked();
+}
+
+sp<LayerBuffer::Buffer> LayerBuffer::getBuffer() const
+{
+    Mutex::Autolock _l(mLock);
+    return mBuffer;
+}
+
+void LayerBuffer::setBuffer(const sp<LayerBuffer::Buffer>& buffer)
+{
+    Mutex::Autolock _l(mLock);
+    mBuffer = buffer;
+}
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::SurfaceBuffer::SurfaceBuffer(SurfaceID id, LayerBuffer* owner)
+    : LayerBaseClient::Surface(id, owner->getIdentity()), mOwner(owner)
+{
+}
+
+LayerBuffer::SurfaceBuffer::~SurfaceBuffer()
+{
+    unregisterBuffers();
+    mOwner = 0;
+}
+
+status_t LayerBuffer::SurfaceBuffer::registerBuffers(
+        int w, int h, int hs, int vs,
+        PixelFormat format, const sp<IMemoryHeap>& heap)
+{
+    LayerBuffer* owner(getOwner());
+    if (owner)
+        return owner->registerBuffers(w, h, hs, vs, format, heap);
+    return NO_INIT;
+}
+
+void LayerBuffer::SurfaceBuffer::postBuffer(ssize_t offset)
+{
+    LayerBuffer* owner(getOwner());
+    if (owner)
+        owner->postBuffer(offset);
+}
+
+void LayerBuffer::SurfaceBuffer::unregisterBuffers()
+{
+    LayerBuffer* owner(getOwner());
+    if (owner)
+        owner->unregisterBuffers();
+}
+
+void LayerBuffer::SurfaceBuffer::disown()
+{
+    Mutex::Autolock _l(mLock);
+    mOwner = 0;
+}
+
+
+// ---------------------------------------------------------------------------
+
+LayerBuffer::Buffer::Buffer(const sp<IMemoryHeap>& heap, ssize_t offset,
+        int w, int h, int hs, int vs, int f)
+    : mCount(0), mHeap(heap)
+{
+    NativeBuffer& src(mNativeBuffer);
+    src.crop.l = 0;
+    src.crop.t = 0;
+    src.crop.r = w;
+    src.crop.b = h;
+    src.img.w = hs ?: w;
+    src.img.h = vs ?: h;
+    src.img.format = f;
+    src.img.offset = offset;
+    src.img.base   = heap->base();
+    src.img.fd     = heap->heapID();
+    // FIXME: make sure this buffer lies within the heap, in which case, set
+    // mHeap to null
+}
+
+LayerBuffer::Buffer::~Buffer()
+{
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android