Merge "Implement SurfaceFlinger's ANW on top of BufferQueue"
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 0539a1b..04a2f52 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -96,7 +96,9 @@
     // allowSynchronousMode specifies whether or not synchronous mode can be
     // enabled.
     // bufferCount sets the minimum number of undequeued buffers for this queue
-    BufferQueue(  bool allowSynchronousMode = true, int bufferCount = MIN_UNDEQUEUED_BUFFERS);
+    BufferQueue(bool allowSynchronousMode = true,
+            int bufferCount = MIN_UNDEQUEUED_BUFFERS,
+            const sp<IGraphicBufferAlloc>& allocator = NULL);
     virtual ~BufferQueue();
 
     virtual int query(int what, int* value);
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index a0774cf..a2e08c0 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -81,7 +81,8 @@
     }
 }
 
-BufferQueue::BufferQueue(  bool allowSynchronousMode, int bufferCount ) :
+BufferQueue::BufferQueue(bool allowSynchronousMode, int bufferCount,
+        const sp<IGraphicBufferAlloc>& allocator) :
     mDefaultWidth(1),
     mDefaultHeight(1),
     mPixelFormat(PIXEL_FORMAT_RGBA_8888),
@@ -105,10 +106,14 @@
     mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
 
     ST_LOGV("BufferQueue");
-    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
-    mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
-    if (mGraphicBufferAlloc == 0) {
-        ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()");
+    if (allocator == NULL) {
+        sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+        mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
+        if (mGraphicBufferAlloc == 0) {
+            ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()");
+        }
+    } else {
+        mGraphicBufferAlloc = allocator;
     }
 }
 
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 6f7a7e1..7d2b75a 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -9,6 +9,7 @@
     LayerScreenshot.cpp                     \
     DisplayHardware/DisplayHardware.cpp     \
     DisplayHardware/DisplayHardwareBase.cpp \
+    DisplayHardware/FramebufferSurface.cpp  \
     DisplayHardware/HWComposer.cpp          \
     DisplayHardware/PowerHAL.cpp            \
     GLExtensions.cpp                        \
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index bb93215..e1c4f62 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -25,13 +25,13 @@
 #include <utils/Log.h>
 
 #include <ui/PixelFormat.h>
-#include <ui/FramebufferNativeWindow.h>
 
 #include <GLES/gl.h>
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 
 #include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware/FramebufferSurface.h"
 
 #include <hardware/gralloc.h>
 
@@ -148,7 +148,7 @@
 
 void DisplayHardware::init(uint32_t dpy)
 {
-    mNativeWindow = new FramebufferNativeWindow();
+    mNativeWindow = new FramebufferSurface();
     framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
     if (!fbDev) {
         ALOGE("Display subsystem failed to initialize. check logs. exiting...");
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 0604031..f029a0a 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -35,7 +35,7 @@
 
 namespace android {
 
-class FramebufferNativeWindow;
+class FramebufferSurface;
 
 class DisplayHardware :
     public DisplayHardwareBase,
@@ -144,7 +144,7 @@
     // protected by mLock
     wp<VSyncHandler>    mVSyncHandler;
 
-    sp<FramebufferNativeWindow> mNativeWindow;
+    sp<FramebufferSurface> mNativeWindow;
 };
 
 }; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
new file mode 100644
index 0000000..02ec86e
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -0,0 +1,188 @@
+/*
+ **
+ ** Copyright 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 <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+
+#include <utils/String8.h>
+
+#include <ui/Rect.h>
+
+#include <EGL/egl.h>
+
+#include <hardware/hardware.h>
+#include <gui/SurfaceTextureClient.h>
+#include <ui/GraphicBuffer.h>
+
+#include "DisplayHardware/FramebufferSurface.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+
+/*
+ * This implements the (main) framebuffer management. This class is used
+ * mostly by SurfaceFlinger, but also by command line GL application.
+ *
+ */
+
+FramebufferSurface::FramebufferSurface()
+    : SurfaceTextureClient(),
+      fbDev(0), mCurrentBufferIndex(-1), mUpdateOnDemand(false)
+{
+    hw_module_t const* module;
+    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
+        int stride;
+        int err;
+        int i;
+        err = framebuffer_open(module, &fbDev);
+        ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
+
+        // bail out if we can't initialize the modules
+        if (!fbDev)
+            return;
+
+        mUpdateOnDemand = (fbDev->setUpdateRect != 0);
+
+        const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
+        const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
+        const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
+        const_cast<int&>(ANativeWindow::minSwapInterval) =  fbDev->minSwapInterval;
+        const_cast<int&>(ANativeWindow::maxSwapInterval) =  fbDev->maxSwapInterval;
+    } else {
+        ALOGE("Couldn't get gralloc module");
+    }
+
+    class GraphicBufferAlloc : public BnGraphicBufferAlloc {
+    public:
+        GraphicBufferAlloc() { };
+        virtual ~GraphicBufferAlloc() { };
+        virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+                PixelFormat format, uint32_t usage, status_t* error) {
+            sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
+            return graphicBuffer;
+        }
+    };
+
+    mBufferQueue = new BufferQueue(true, NUM_FRAME_BUFFERS, new GraphicBufferAlloc());
+    mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB|GRALLOC_USAGE_HW_RENDER|GRALLOC_USAGE_HW_COMPOSER);
+    mBufferQueue->setDefaultBufferFormat(fbDev->format);
+    mBufferQueue->setDefaultBufferSize(fbDev->width, fbDev->height);
+    mBufferQueue->setSynchronousMode(true);
+    mBufferQueue->setBufferCountServer(NUM_FRAME_BUFFERS);
+    setISurfaceTexture(mBufferQueue);
+}
+
+void FramebufferSurface::onFirstRef() {
+    class Listener : public BufferQueue::ConsumerListener {
+        const wp<FramebufferSurface> that;
+        virtual ~Listener() { }
+        virtual void onBuffersReleased() { }
+        void onFrameAvailable() {
+            sp<FramebufferSurface> self = that.promote();
+            if (self != NULL) {
+                BufferQueue::BufferItem item;
+                status_t err = self->mBufferQueue->acquireBuffer(&item);
+                if (err == 0) {
+                    if (item.mGraphicBuffer != 0) {
+                        self->mBuffers[item.mBuf] = item.mGraphicBuffer;
+                    }
+                    self->fbDev->post(self->fbDev, self->mBuffers[item.mBuf]->handle);
+                    if (self->mCurrentBufferIndex >= 0) {
+                        self->mBufferQueue->releaseBuffer(self->mCurrentBufferIndex,
+                                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+                    }
+                    self->mCurrentBufferIndex = item.mBuf;
+                }
+            }
+        }
+    public:
+        Listener(const sp<FramebufferSurface>& that) : that(that) { }
+    };
+
+    mBufferQueue->setConsumerName(String8("FramebufferSurface"));
+    mBufferQueue->consumerConnect(new Listener(this));
+}
+
+FramebufferSurface::~FramebufferSurface() {
+    if (fbDev) {
+        framebuffer_close(fbDev);
+    }
+}
+
+status_t FramebufferSurface::setUpdateRectangle(const Rect& r)
+{
+    if (!mUpdateOnDemand) {
+        return INVALID_OPERATION;
+    }
+    return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height());
+}
+
+status_t FramebufferSurface::compositionComplete()
+{
+    if (fbDev->compositionComplete) {
+        return fbDev->compositionComplete(fbDev);
+    }
+    return INVALID_OPERATION;
+}
+
+void FramebufferSurface::dump(String8& result) {
+    if (fbDev->common.version >= 1 && fbDev->dump) {
+        const size_t SIZE = 4096;
+        char buffer[SIZE];
+
+        fbDev->dump(fbDev, buffer, SIZE);
+        result.append(buffer);
+    }
+}
+
+int FramebufferSurface::query(int what, int* value) const {
+    Mutex::Autolock _l(mLock);
+    framebuffer_device_t* fb = fbDev;
+    switch (what) {
+        case NATIVE_WINDOW_DEFAULT_WIDTH:
+        case NATIVE_WINDOW_WIDTH:
+            *value = fb->width;
+            return NO_ERROR;
+        case NATIVE_WINDOW_DEFAULT_HEIGHT:
+        case NATIVE_WINDOW_HEIGHT:
+            *value = fb->height;
+            return NO_ERROR;
+        case NATIVE_WINDOW_FORMAT:
+            *value = fb->format;
+            return NO_ERROR;
+        case NATIVE_WINDOW_CONCRETE_TYPE:
+            *value = NATIVE_WINDOW_FRAMEBUFFER;
+            return NO_ERROR;
+        case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+            *value = 0;
+            return NO_ERROR;
+        case NATIVE_WINDOW_TRANSFORM_HINT:
+            *value = 0;
+            return NO_ERROR;
+    }
+    return SurfaceTextureClient::query(what, value);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
new file mode 100644
index 0000000..5b4fd01
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SF_FRAMEBUFFER_SURFACE_H
+#define ANDROID_SF_FRAMEBUFFER_SURFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+
+#include <gui/SurfaceTextureClient.h>
+
+#define NUM_FRAME_BUFFERS  2
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Rect;
+class String8;
+
+// ---------------------------------------------------------------------------
+
+class FramebufferSurface : public SurfaceTextureClient {
+public:
+    FramebufferSurface();
+
+    virtual void onFirstRef();
+
+    framebuffer_device_t const * getDevice() const { return fbDev; }
+
+    bool isUpdateOnDemand() const { return mUpdateOnDemand; }
+    status_t setUpdateRectangle(const Rect& updateRect);
+    status_t compositionComplete();
+
+    void dump(String8& result);
+
+private:
+    virtual ~FramebufferSurface(); // this class cannot be overloaded
+    virtual int query(int what, int* value) const;
+
+    framebuffer_device_t* fbDev;
+
+    sp<BufferQueue> mBufferQueue;
+    int mCurrentBufferIndex;
+    sp<GraphicBuffer> mBuffers[NUM_FRAME_BUFFERS];
+
+    mutable Mutex mLock;
+    bool mUpdateOnDemand;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_SF_FRAMEBUFFER_SURFACE_H
+