Bug 804852: Implement Composer2D for hwc. r=cjones
authorDiego Wilson <dwilson@codeaurora.org>
Mon, 19 Nov 2012 09:58:37 -0800
changeset 117014 7f142230d1776097161c7140058d2af042d04ffd
parent 117013 c141f818c5b3d7aad3ad445c39678ca469ac4fd4
child 117015 59e8632b391e0827725f6c152875eaa1d8e5c3e2
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs804852
milestone18.0a2
Bug 804852: Implement Composer2D for hwc. r=cjones
widget/gonk/HWComposer.h
widget/gonk/HwcComposer2D.cpp
widget/gonk/HwcComposer2D.h
widget/gonk/hardware/hwcomposer.h
--- a/widget/gonk/HWComposer.h
+++ b/widget/gonk/HWComposer.h
@@ -12,19 +12,20 @@
  * 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_HWCOMPOSER_H
 #define ANDROID_SF_HWCOMPOSER_H
 
-#include <hardware/hwcomposer.h>
 #include <utils/Vector.h>
 
+#include "hardware/hwcomposer.h"
+
 namespace android {
 // ---------------------------------------------------------------------------
 
 class String8;
 
 class HWComposer
 {
 public:
new file mode 100644
--- /dev/null
+++ b/widget/gonk/HwcComposer2D.cpp
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * 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 <android/log.h>
+#include <EGL/egl.h>
+#include <hardware/hardware.h>
+
+#include "Framebuffer.h"
+#include "HwcComposer2D.h"
+#include "LayerManagerOGL.h"
+#include "mozilla/layers/PLayers.h"
+#include "mozilla/layers/ShadowLayerUtilsGralloc.h"
+#include "mozilla/StaticPtr.h"
+#include "nsIScreenManager.h"
+#include "nsMathUtils.h"
+#include "nsServiceManagerUtils.h"
+
+#define LOG_TAG "HWComposer"
+
+#if (LOG_NDEBUG == 0)
+#define LOGD(args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, ## args)
+#else
+#define LOGD(args...) ((void)0)
+#endif
+
+#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, ## args)
+
+#define LAYER_COUNT_INCREMENTS 5
+
+using namespace android;
+using namespace mozilla::layers;
+
+enum {
+    HWC_USE_GPU = HWC_FRAMEBUFFER,
+    HWC_USE_OVERLAY = HWC_OVERLAY,
+    HWC_USE_COPYBIT
+};
+
+namespace mozilla {
+
+static StaticRefPtr<HwcComposer2D> sInstance;
+
+HwcComposer2D::HwcComposer2D()
+    : mMaxLayerCount(0)
+    , mList(nullptr)
+{
+}
+
+HwcComposer2D::~HwcComposer2D() {
+    free(mList);
+}
+
+int
+HwcComposer2D::Init(hwc_display_t dpy, hwc_surface_t sur)
+{
+    MOZ_ASSERT(!Initialized());
+
+    if (int err = init()) {
+        LOGE("Failed to initialize hwc");
+        return err;
+    }
+
+    nsIntSize screenSize;
+
+    mozilla::Framebuffer::GetSize(&screenSize);
+    mScreenWidth  = screenSize.width;
+    mScreenHeight = screenSize.height;
+
+    mDpy = dpy;
+    mSur = sur;
+
+    return 0;
+}
+
+HwcComposer2D*
+HwcComposer2D::GetInstance()
+{
+    if (!sInstance) {
+        LOGD("Creating new instance");
+        sInstance = new HwcComposer2D();
+    }
+    return sInstance;
+}
+
+bool
+HwcComposer2D::ReallocLayerList()
+{
+    int size = sizeof(hwc_layer_list_t) +
+        ((mMaxLayerCount + LAYER_COUNT_INCREMENTS) * sizeof(hwc_layer_t));
+
+    hwc_layer_list_t* listrealloc = (hwc_layer_list_t*)realloc(mList, size);
+
+    if (!listrealloc) {
+        return false;
+    }
+
+    if (!mList) {
+        //first alloc, initialize
+        listrealloc->numHwLayers = 0;
+        listrealloc->flags = 0;
+    }
+
+    mList = listrealloc;
+    mMaxLayerCount += LAYER_COUNT_INCREMENTS;
+    return true;
+}
+
+int
+HwcComposer2D::GetRotation()
+{
+    int halrotation = 0;
+    uint32_t screenrotation;
+
+    if (!mScreen) {
+        nsCOMPtr<nsIScreenManager> screenMgr =
+            do_GetService("@mozilla.org/gfx/screenmanager;1");
+        if (screenMgr) {
+            screenMgr->GetPrimaryScreen(getter_AddRefs(mScreen));
+        }
+    }
+
+    if (mScreen) {
+        if (NS_SUCCEEDED(mScreen->GetRotation(&screenrotation))) {
+            switch (screenrotation) {
+            case nsIScreen::ROTATION_0_DEG:
+                 halrotation = 0;
+                 break;
+
+            case nsIScreen::ROTATION_90_DEG:
+                 halrotation = HWC_TRANSFORM_ROT_90;
+                 break;
+
+            case nsIScreen::ROTATION_180_DEG:
+                 halrotation = HWC_TRANSFORM_ROT_180;
+                 break;
+
+            case nsIScreen::ROTATION_270_DEG:
+                 halrotation = HWC_TRANSFORM_ROT_270;
+                 break;
+            }
+        }
+    }
+
+    return halrotation;
+}
+
+/**
+ * Sets hwc layer rectangles required for hwc composition
+ *
+ * @param aVisible Input. Layer's unclipped visible rectangle
+ *        The origin is the layer's buffer
+ * @param aTransform Input. Layer's transformation matrix
+ *        It transforms from layer space to screen space
+ * @param aClip Input. A clipping rectangle.
+ *        The origin is the top-left corner of the screen
+ * @param aBufferRect Input. The layer's buffer bounds
+ *        The origin is the buffer itself and hence always (0,0)
+ * @param aSurceCrop Output. Area of the source to consider,
+ *        the origin is the top-left corner of the buffer
+ * @param aVisibleRegionScreen Output. Visible region in screen space.
+ *        The origin is the top-left corner of the screen
+ * @return true if the layer should be rendered.
+ *         false if the layer can be skipped
+ */
+static bool
+PrepareLayerRects(nsIntRect aVisible, const gfxMatrix& aTransform,
+                  nsIntRect aClip, nsIntRect aBufferRect,
+                  hwc_rect_t* aSourceCrop, hwc_rect_t* aVisibleRegionScreen) {
+
+    gfxRect visibleRect(aVisible);
+    gfxRect clip(aClip);
+    gfxRect visibleRectScreen = aTransform.TransformBounds(visibleRect);
+    // |clip| is guaranteed to be integer
+    visibleRectScreen.IntersectRect(visibleRectScreen, clip);
+
+    if (visibleRectScreen.IsEmpty()) {
+        LOGD("Skip layer");
+        return false;
+    }
+
+    gfxMatrix inverse(aTransform);
+    inverse.Invert();
+    gfxRect crop = inverse.TransformBounds(visibleRectScreen);
+    // Map to buffer space
+    crop -= visibleRect.TopLeft();
+    gfxRect bufferRect(aBufferRect);
+    //clip to buffer size
+    crop.IntersectRect(crop, aBufferRect);
+    crop.RoundOut();
+
+    if (crop.IsEmpty()) {
+        LOGD("Skip layer");
+        return false;
+    }
+
+
+    //propagate buffer clipping back to visible rect
+    visibleRectScreen = aTransform.TransformBounds(crop + visibleRect.TopLeft());
+    visibleRectScreen.RoundOut();
+
+    aSourceCrop->left = crop.x;
+    aSourceCrop->top  = crop.y;
+    aSourceCrop->right  = crop.x + crop.width;
+    aSourceCrop->bottom = crop.y + crop.height;
+
+    aVisibleRegionScreen->left = visibleRectScreen.x;
+    aVisibleRegionScreen->top  = visibleRectScreen.y;
+    aVisibleRegionScreen->right  = visibleRectScreen.x + visibleRectScreen.width;
+    aVisibleRegionScreen->bottom = visibleRectScreen.y + visibleRectScreen.height;
+
+    return true;
+}
+
+bool
+HwcComposer2D::PrepareLayerList(Layer* aLayer,
+                                const nsIntRect& aClip)
+{
+    // NB: we fall off this path whenever there are container layers
+    // that require intermediate surfaces.  That means all the
+    // GetEffective*() coordinates are relative to the framebuffer.
+
+    const bool TESTING = true;
+
+    const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
+    if (visibleRegion.IsEmpty()) {
+        return true;
+    }
+
+    float opacity = aLayer->GetEffectiveOpacity();
+    if (opacity <= 0) {
+        LOGD("Layer is fully transparent so skip rendering");
+        return true;
+    }
+    else if (opacity < 1) {
+        LOGD("Layer has planar semitransparency which is unsupported");
+        return false;
+    }
+
+    if (!TESTING &&
+        visibleRegion.GetNumRects() > 1) {
+        // FIXME/bug 808339
+        LOGD("Layer has nontrivial visible region");
+        return false;
+    }
+
+
+    if (ContainerLayer* container = aLayer->AsContainerLayer()) {
+        if (container->UseIntermediateSurface()) {
+            LOGD("Container layer needs intermediate surface");
+            return false;
+        }
+        nsAutoTArray<Layer*, 12> children;
+        container->SortChildrenBy3DZOrder(children);
+
+        //FIXME/bug 810334
+        for (PRUint32 i = 0; i < children.Length(); i++) {
+            if (!PrepareLayerList(children[i], aClip)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    LayerOGL* layerGL = static_cast<LayerOGL*>(aLayer->ImplData());
+    LayerRenderState state = layerGL->GetRenderState();
+
+    if (!state.mSurface ||
+        state.mSurface->type() != SurfaceDescriptor::TSurfaceDescriptorGralloc) {
+        LOGD("Layer doesn't have a gralloc buffer");
+        return false;
+    }
+    if (state.BufferRotated()) {
+        LOGD("Layer has a rotated buffer");
+        return false;
+    }
+
+    gfxMatrix transform;
+    const gfx3DMatrix& transform3D = aLayer->GetEffectiveTransform();
+    if (!transform3D.Is2D(&transform) || !transform.PreservesAxisAlignedRectangles()) {
+        LOGD("Layer has a 3D transform or a non-square angle rotation");
+        return false;
+    }
+
+    // OK!  We can compose this layer with hwc.
+
+    int current = mList ? mList->numHwLayers : 0;
+    if (!mList || current >= mMaxLayerCount) {
+        if (!ReallocLayerList() || current >= mMaxLayerCount) {
+            LOGE("PrepareLayerList failed! Could not increase the maximum layer count");
+            return false;
+        }
+    }
+
+    sp<GraphicBuffer> buffer = GrallocBufferActor::GetFrom(*state.mSurface);
+
+    nsIntRect visibleRect = visibleRegion.GetBounds();
+
+    nsIntRect bufferRect = nsIntRect(0, 0, int(buffer->getWidth()),
+        int(buffer->getHeight()));
+
+    hwc_layer_t& hwcLayer = mList->hwLayers[current];
+
+    //FIXME/bug 810334
+    if(!PrepareLayerRects(visibleRect, transform, aClip, bufferRect,
+                          &(hwcLayer.sourceCrop), &(hwcLayer.displayFrame))) {
+        return true;
+    }
+
+    buffer_handle_t handle = buffer->getNativeBuffer()->handle;
+    hwcLayer.handle = handle;
+
+    hwcLayer.blending = HWC_BLENDING_NONE;
+    hwcLayer.flags = 0;
+    hwcLayer.hints = 0;
+
+
+    hwcLayer.compositionType = HWC_USE_COPYBIT;
+
+    if (transform.xx == 0) {
+        if (transform.xy < 0) {
+            hwcLayer.transform = HWC_TRANSFORM_ROT_90;
+            LOGD("Layer buffer rotated 90 degrees");
+        }
+        else {
+            hwcLayer.transform = HWC_TRANSFORM_ROT_270;
+            LOGD("Layer buffer rotated 270 degrees");
+        }
+    }
+    else if (transform.xx < 0) {
+        hwcLayer.transform = HWC_TRANSFORM_ROT_180;
+        LOGD("Layer buffer rotated 180 degrees");
+    }
+    else {
+        hwcLayer.transform = 0;
+    }
+
+    hwcLayer.transform |= state.YFlipped() ? HWC_TRANSFORM_FLIP_V : 0;
+
+    hwc_region_t region;
+    region.numRects = 1;
+    region.rects = &(hwcLayer.displayFrame);
+    hwcLayer.visibleRegionScreen = region;
+
+    mList->numHwLayers++;
+
+    return true;
+}
+
+bool
+HwcComposer2D::TryRender(Layer* aRoot,
+                         const gfxMatrix& aGLWorldTransform)
+{
+    MOZ_ASSERT(Initialized());
+    if (mList) {
+        mList->numHwLayers = 0;
+    }
+    // XXX use GL world transform instead of GetRotation()
+    int rotation = GetRotation();
+
+    int fbHeight, fbWidth;
+
+    if (rotation == 0 || rotation == HWC_TRANSFORM_ROT_180) {
+        fbWidth = mScreenWidth;
+        fbHeight = mScreenHeight;
+    } else {
+        fbWidth = mScreenHeight;
+        fbHeight = mScreenWidth;
+    }
+
+    if (!PrepareLayerList(aRoot, nsIntRect(0, 0, fbWidth, fbHeight))) {
+        LOGD("Render aborted. Nothing was drawn to the screen");
+        return false;
+    }
+
+    if (mHwc->set(mHwc, mDpy, mSur, mList)) {
+        LOGE("Hardware device failed to render");
+        return false;
+    }
+
+    LOGD("Frame rendered");
+    return true;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/gonk/HwcComposer2D.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * 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 mozilla_HwcComposer2D
+#define mozilla_HwcComposer2D
+
+#include "Composer2D.h"
+#include "HWComposer.h"
+#include "Layers.h"
+#include "nsIScreen.h"
+
+namespace mozilla {
+
+namespace layers {
+class ContainerLayer;
+class Layer;
+}
+
+class HwcComposer2D : public android::HWComposer,
+                      public mozilla::layers::Composer2D {
+public:
+    HwcComposer2D();
+    virtual ~HwcComposer2D();
+
+    int Init(hwc_display_t aDisplay, hwc_surface_t aSurface);
+
+    bool Initialized() const { return mHwc; }
+
+    static HwcComposer2D* GetInstance();
+
+    // Returns TRUE if the container has been succesfully rendered
+    // Returns FALSE if the container cannot be fully rendered
+    // by this composer so nothing was rendered at all
+    bool TryRender(layers::Layer* aRoot, const gfxMatrix& aGLWorldTransform) MOZ_OVERRIDE;
+
+private:
+    bool ReallocLayerList();
+    bool PrepareLayerList(layers::Layer* aContainer, const nsIntRect& aClip);
+    int GetRotation();
+
+    hwc_layer_list_t*       mList;
+    nsCOMPtr<nsIScreen>     mScreen;
+    int                     mScreenWidth, mScreenHeight;
+    int                     mMaxLayerCount;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_HwcComposer2D
new file mode 100644
--- /dev/null
+++ b/widget/gonk/hardware/hwcomposer.h
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2010 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_INCLUDE_HARDWARE_HWCOMPOSER_H
+#define ANDROID_INCLUDE_HARDWARE_HWCOMPOSER_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+#include <hardware/gralloc.h>
+#include <hardware/hardware.h>
+#include <cutils/native_handle.h>
+
+__BEGIN_DECLS
+
+/*****************************************************************************/
+
+#define HWC_API_VERSION 1
+
+/**
+ * The id of this module
+ */
+#define HWC_HARDWARE_MODULE_ID "hwcomposer"
+
+/**
+ * Name of the sensors device to open
+ */
+#define HWC_HARDWARE_COMPOSER   "composer"
+
+
+enum {
+    /* hwc_composer_device_t::set failed in EGL */
+    HWC_EGL_ERROR = -1
+};
+
+/*
+ * hwc_layer_t::hints values
+ * Hints are set by the HAL and read by SurfaceFlinger
+ */
+enum {
+    /*
+     * HWC can set the HWC_HINT_TRIPLE_BUFFER hint to indicate to SurfaceFlinger
+     * that it should triple buffer this layer. Typically HWC does this when
+     * the layer will be unavailable for use for an extended period of time,
+     * e.g. if the display will be fetching data directly from the layer and
+     * the layer can not be modified until after the next set().
+     */
+    HWC_HINT_TRIPLE_BUFFER  = 0x00000001,
+
+    /*
+     * HWC sets HWC_HINT_CLEAR_FB to tell SurfaceFlinger that it should clear the
+     * framebuffer with transparent pixels where this layer would be.
+     * SurfaceFlinger will only honor this flag when the layer has no blending
+     *
+     */
+    HWC_HINT_CLEAR_FB       = 0x00000002
+};
+
+/*
+ * hwc_layer_t::flags values
+ * Flags are set by SurfaceFlinger and read by the HAL
+ */
+enum {
+    /*
+     * HWC_SKIP_LAYER is set by SurfaceFlnger to indicate that the HAL
+     * shall not consider this layer for composition as it will be handled
+     * by SurfaceFlinger (just as if compositionType was set to HWC_OVERLAY).
+     */
+    HWC_SKIP_LAYER = 0x00000001,
+};
+
+/*
+ * hwc_layer_t::compositionType values
+ */
+enum {
+    /* this layer is to be drawn into the framebuffer by SurfaceFlinger */
+    HWC_FRAMEBUFFER = 0,
+
+    /* this layer will be handled in the HWC */
+    HWC_OVERLAY = 1,
+};
+
+/*
+ * hwc_layer_t::blending values
+ */
+enum {
+    /* no blending */
+    HWC_BLENDING_NONE     = 0x0100,
+
+    /* ONE / ONE_MINUS_SRC_ALPHA */
+    HWC_BLENDING_PREMULT  = 0x0105,
+
+    /* SRC_ALPHA / ONE_MINUS_SRC_ALPHA */
+    HWC_BLENDING_COVERAGE = 0x0405
+};
+
+/*
+ * hwc_layer_t::transform values
+ */
+enum {
+    /* flip source image horizontally */
+    HWC_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H,
+    /* flip source image vertically */
+    HWC_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
+    /* rotate source image 90 degrees clock-wise */
+    HWC_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
+    /* rotate source image 180 degrees */
+    HWC_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
+    /* rotate source image 270 degrees clock-wise */
+    HWC_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
+};
+
+typedef struct hwc_rect {
+    int left;
+    int top;
+    int right;
+    int bottom;
+} hwc_rect_t;
+
+typedef struct hwc_region {
+    size_t numRects;
+    hwc_rect_t const* rects;
+} hwc_region_t;
+
+typedef struct hwc_layer {
+    /*
+     * initially set to HWC_FRAMEBUFFER, indicates the layer will
+     * be drawn into the framebuffer using OpenGL ES.
+     * The HWC can toggle this value to HWC_OVERLAY, to indicate
+     * it will handle the layer.
+     */
+    int32_t compositionType;
+
+    /* see hwc_layer_t::hints above */
+    uint32_t hints;
+
+    /* see hwc_layer_t::flags above */
+    uint32_t flags;
+
+    /* handle of buffer to compose. this handle is guaranteed to have been
+     * allocated with gralloc */
+    buffer_handle_t handle;
+
+    /* transformation to apply to the buffer during composition */
+    uint32_t transform;
+
+    /* blending to apply during composition */
+    int32_t blending;
+
+    /* area of the source to consider, the origin is the top-left corner of
+     * the buffer */
+    hwc_rect_t sourceCrop;
+
+    /* where to composite the sourceCrop onto the display. The sourceCrop
+     * is scaled using linear filtering to the displayFrame. The origin is the
+     * top-left corner of the screen.
+     */
+    hwc_rect_t displayFrame;
+
+    /* visible region in screen space. The origin is the
+     * top-left corner of the screen.
+     * The visible region INCLUDES areas overlapped by a translucent layer.
+     */
+    hwc_region_t visibleRegionScreen;
+} hwc_layer_t;
+
+
+/*
+ * hwc_layer_list_t::flags values
+ */
+enum {
+    /*
+     * HWC_GEOMETRY_CHANGED is set by SurfaceFlinger to indicate that the list
+     * passed to (*prepare)() has changed by more than just the buffer handles.
+     */
+    HWC_GEOMETRY_CHANGED = 0x00000001,
+};
+
+/*
+ * List of layers.
+ * The handle members of hwLayers elements must be unique.
+ */
+typedef struct hwc_layer_list {
+    uint32_t flags;
+    size_t numHwLayers;
+    hwc_layer_t hwLayers[0];
+} hwc_layer_list_t;
+
+/* This represents a display, typically an EGLDisplay object */
+typedef void* hwc_display_t;
+
+/* This represents a surface, typically an EGLSurface object  */
+typedef void* hwc_surface_t;
+
+
+/* see hwc_composer_device::registerProcs()
+ * Any of the callbacks can be NULL, in which case the corresponding
+ * functionality is not supported.
+ */
+typedef struct hwc_procs {
+    /*
+     * (*invalidate)() triggers a screen refresh, in particular prepare and set
+     * will be called shortly after this call is made. Note that there is
+     * NO GUARANTEE that the screen refresh will happen after invalidate()
+     * returns (in particular, it could happen before).
+     * invalidate() is GUARANTEED TO NOT CALL BACK into the h/w composer HAL and
+     * it is safe to call invalidate() from any of hwc_composer_device
+     * hooks, unless noted otherwise.
+     */
+    void (*invalidate)(struct hwc_procs* procs);
+} hwc_procs_t;
+
+
+/*****************************************************************************/
+
+typedef struct hwc_module {
+    struct hw_module_t common;
+} hwc_module_t;
+
+
+typedef struct hwc_composer_device {
+    struct hw_device_t common;
+
+    /*
+     * (*prepare)() is called for each frame before composition and is used by
+     * SurfaceFlinger to determine what composition steps the HWC can handle.
+     *
+     * (*prepare)() can be called more than once, the last call prevails.
+     *
+     * The HWC responds by setting the compositionType field to either
+     * HWC_FRAMEBUFFER or HWC_OVERLAY. In the former case, the composition for
+     * this layer is handled by SurfaceFlinger with OpenGL ES, in the later
+     * case, the HWC will have to handle this layer's composition.
+     *
+     * (*prepare)() is called with HWC_GEOMETRY_CHANGED to indicate that the
+     * list's geometry has changed, that is, when more than just the buffer's
+     * handles have been updated. Typically this happens (but is not limited to)
+     * when a window is added, removed, resized or moved.
+     *
+     * a NULL list parameter or a numHwLayers of zero indicates that the
+     * entire composition will be handled by SurfaceFlinger with OpenGL ES.
+     *
+     * returns: 0 on success. An negative error code on error. If an error is
+     * returned, SurfaceFlinger will assume that none of the layer will be
+     * handled by the HWC.
+     */
+    int (*prepare)(struct hwc_composer_device *dev, hwc_layer_list_t* list);
+
+
+    /*
+     * (*set)() is used in place of eglSwapBuffers(), and assumes the same
+     * functionality, except it also commits the work list atomically with
+     * the actual eglSwapBuffers().
+     *
+     * The list parameter is guaranteed to be the same as the one returned
+     * from the last call to (*prepare)().
+     *
+     * When this call returns the caller assumes that:
+     *
+     * - the display will be updated in the near future with the content
+     *   of the work list, without artifacts during the transition from the
+     *   previous frame.
+     *
+     * - all objects are available for immediate access or destruction, in
+     *   particular, hwc_region_t::rects data and hwc_layer_t::layer's buffer.
+     *   Note that this means that immediately accessing (potentially from a
+     *   different process) a buffer used in this call will not result in
+     *   screen corruption, the driver must apply proper synchronization or
+     *   scheduling (eg: block the caller, such as gralloc_module_t::lock(),
+     *   OpenGL ES, Camera, Codecs, etc..., or schedule the caller's work
+     *   after the buffer is freed from the actual composition).
+     *
+     * a NULL list parameter or a numHwLayers of zero indicates that the
+     * entire composition has been handled by SurfaceFlinger with OpenGL ES.
+     * In this case, (*set)() behaves just like eglSwapBuffers().
+     *
+     * dpy, sur, and list are set to NULL to indicate that the screen is
+     * turning off. This happens WITHOUT prepare() being called first.
+     * This is a good time to free h/w resources and/or power
+     * the relevant h/w blocks down.
+     *
+     * IMPORTANT NOTE: there is an implicit layer containing opaque black
+     * pixels behind all the layers in the list.
+     * It is the responsibility of the hwcomposer module to make
+     * sure black pixels are output (or blended from).
+     *
+     * returns: 0 on success. An negative error code on error:
+     *    HWC_EGL_ERROR: eglGetError() will provide the proper error code
+     *    Another code for non EGL errors.
+     *
+     */
+    int (*set)(struct hwc_composer_device *dev,
+                hwc_display_t dpy,
+                hwc_surface_t sur,
+                hwc_layer_list_t* list);
+    /*
+     * This hook is OPTIONAL.
+     *
+     * If non NULL it will be called by SurfaceFlinger on dumpsys
+     */
+    void (*dump)(struct hwc_composer_device* dev, char *buff, int buff_len);
+
+    /*
+     * This hook is OPTIONAL.
+     *
+     * (*registerProcs)() registers a set of callbacks the h/w composer HAL
+     * can later use. It is FORBIDDEN to call any of the callbacks from
+     * within registerProcs(). registerProcs() must save the hwc_procs_t pointer
+     * which is needed when calling a registered callback.
+     * Each call to registerProcs replaces the previous set of callbacks.
+     * registerProcs is called with NULL to unregister all callbacks.
+     *
+     * Any of the callbacks can be NULL, in which case the corresponding
+     * functionality is not supported.
+     */
+    void (*registerProcs)(struct hwc_composer_device* dev,
+            hwc_procs_t const* procs);
+
+    void* reserved_proc[6];
+
+} hwc_composer_device_t;
+
+
+/** convenience API for opening and closing a device */
+
+static inline int hwc_open(const struct hw_module_t* module,
+        hwc_composer_device_t** device) {
+    return module->methods->open(module,
+            HWC_HARDWARE_COMPOSER, (struct hw_device_t**)device);
+}
+
+static inline int hwc_close(hwc_composer_device_t* device) {
+    return device->common.close(&device->common);
+}
+
+
+/*****************************************************************************/
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_HARDWARE_HWCOMPOSER_H */