Passthrough hwcomposer for emulator devices

Basic hw composer implementation that directs surface flinger to do all
compositing.

Change-Id: I98e39985ae996db74b655cd4f726680f7066b236
(cherry picked from commit 2d87e1074b72acb859e5b37555266d108af748dd)
diff --git a/hwcomposer/Android.mk b/hwcomposer/Android.mk
new file mode 100644
index 0000000..5f20c58
--- /dev/null
+++ b/hwcomposer/Android.mk
@@ -0,0 +1,66 @@
+#
+# Copyright 2015 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+emulator_hwcomposer_shared_libraries := \
+    liblog \
+    libutils \
+    libcutils \
+    libEGL \
+    libutils \
+    libhardware \
+    libsync \
+    libui \
+
+emulator_hwcomposer_src_files := \
+    hwcomposer.cpp
+
+emulator_hwcomposer_cflags += \
+    -DLOG_TAG=\"hwcomposer\"
+
+emulator_hwcomposer_c_includes += \
+    system/core/libsync \
+    system/core/libsync/include
+
+emulator_hwcomposer_relative_path := hw
+
+# GOLDFISH BUILD
+LOCAL_SHARED_LIBRARIES := $(emulator_hwcomposer_shared_libraries)
+LOCAL_SRC_FILES := $(emulator_hwcomposer_src_files)
+LOCAL_CFLAGS := $(emulator_hwcomposer_cflags)
+LOCAL_C_INCLUDES := $(emulator_hwcomposer_c_includes)
+LOCAL_MODULE_RELATIVE_PATH := $(emulator_hwcomposer_relative_path)
+
+LOCAL_MODULE := hwcomposer.goldfish
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
+# RANCHU BUILD
+include $(CLEAR_VARS)
+
+LOCAL_SHARED_LIBRARIES := $(emulator_hwcomposer_shared_libraries)
+LOCAL_SRC_FILES := $(emulator_hwcomposer_src_files)
+LOCAL_CFLAGS := $(emulator_hwcomposer_cflags)
+LOCAL_C_INCLUDES := $(emulator_hwcomposer_c_includes)
+LOCAL_MODULE_RELATIVE_PATH := $(emulator_hwcomposer_relative_path)
+
+LOCAL_MODULE := hwcomposer.ranchu
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/hwcomposer/hwcomposer.cpp b/hwcomposer/hwcomposer.cpp
new file mode 100644
index 0000000..61a3c46
--- /dev/null
+++ b/hwcomposer/hwcomposer.cpp
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2012 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 <pthread.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <cutils/log.h>
+#include <hardware/hwcomposer.h>
+#include <sync/sync.h>
+
+struct ranchu_hwc_composer_device_1 {
+    hwc_composer_device_1_t base; // constant after init
+    const hwc_procs_t *procs;     // constant after init
+    pthread_t vsync_thread;       // constant after init
+    int32_t vsync_period_ns;      // constant after init
+    framebuffer_device_t* fbdev;  // constant after init
+
+    pthread_mutex_t vsync_lock;
+    bool vsync_callback_enabled; // protected by this->vsync_lock
+};
+
+static int hwc_prepare(hwc_composer_device_1_t* dev __unused,
+                       size_t numDisplays, hwc_display_contents_1_t** displays) {
+
+    if (!numDisplays || !displays) return 0;
+
+    hwc_display_contents_1_t* contents = displays[HWC_DISPLAY_PRIMARY];
+
+    if (!contents) return 0;
+
+    for (size_t i = 0; i < contents->numHwLayers; i++) {
+    // We do not handle any layers, so set composition type of any non
+    // HWC_FRAMEBUFFER_TARGET layer to to HWC_FRAMEBUFFER.
+        if (contents->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
+            continue;
+        }
+        contents->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
+    }
+    return 0;
+}
+
+static int hwc_set(struct hwc_composer_device_1* dev,size_t numDisplays,
+                   hwc_display_contents_1_t** displays) {
+    struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev;
+    if (!numDisplays || !displays) {
+        return 0;
+    }
+
+    hwc_display_contents_1_t* contents = displays[HWC_DISPLAY_PRIMARY];
+
+    int retireFenceFd = -1;
+    int err = 0;
+    for (size_t layer = 0; layer < contents->numHwLayers; layer++) {
+            hwc_layer_1_t* fb_layer = &contents->hwLayers[layer];
+
+        int releaseFenceFd = -1;
+        if (fb_layer->acquireFenceFd > 0) {
+            const int kAcquireWarningMS= 3000;
+            err = sync_wait(fb_layer->acquireFenceFd, kAcquireWarningMS);
+            if (err < 0 && errno == ETIME) {
+                ALOGE("hwcomposer waited on fence %d for %d ms",
+                      fb_layer->acquireFenceFd, kAcquireWarningMS);
+            }
+            close(fb_layer->acquireFenceFd);
+
+            if (fb_layer->compositionType != HWC_FRAMEBUFFER_TARGET) {
+                ALOGE("hwcomposer found acquire fence on layer %d which is not an"
+                      "HWC_FRAMEBUFFER_TARGET layer", layer);
+            }
+
+            releaseFenceFd = dup(fb_layer->acquireFenceFd);
+            fb_layer->acquireFenceFd = -1;
+        }
+
+        if (fb_layer->compositionType != HWC_FRAMEBUFFER_TARGET) {
+            continue;
+        }
+
+        pdev->fbdev->post(pdev->fbdev, fb_layer->handle);
+        fb_layer->releaseFenceFd = releaseFenceFd;
+
+        if (releaseFenceFd > 0) {
+            if (retireFenceFd == -1) {
+                retireFenceFd = dup(releaseFenceFd);
+            } else {
+                int mergedFenceFd = sync_merge("hwc_set retireFence",
+                                               releaseFenceFd, retireFenceFd);
+                close(retireFenceFd);
+                retireFenceFd = mergedFenceFd;
+            }
+        }
+    }
+
+    contents->retireFenceFd = retireFenceFd;
+    return err;
+}
+
+static int hwc_query(struct hwc_composer_device_1* dev, int what, int* value) {
+    struct ranchu_hwc_composer_device_1* pdev =
+            (struct ranchu_hwc_composer_device_1*)dev;
+
+    switch (what) {
+        case HWC_BACKGROUND_LAYER_SUPPORTED:
+            // we do not support the background layer
+            value[0] = 0;
+            break;
+        case HWC_VSYNC_PERIOD:
+            value[0] = pdev->vsync_period_ns;
+            break;
+        default:
+            // unsupported query
+            ALOGE("%s badness unsupported query what=%d", __FUNCTION__, what);
+            return -EINVAL;
+    }
+    return 0;
+}
+
+static int hwc_event_control(struct hwc_composer_device_1* dev, int dpy __unused,
+                             int event, int enabled) {
+    struct ranchu_hwc_composer_device_1* pdev =
+            (struct ranchu_hwc_composer_device_1*)dev;
+    int ret = -EINVAL;
+
+    // enabled can only be 0 or 1
+    if (!(enabled & ~1)) {
+        if (event == HWC_EVENT_VSYNC) {
+            pthread_mutex_lock(&pdev->vsync_lock);
+            pdev->vsync_callback_enabled=enabled;
+            pthread_mutex_unlock(&pdev->vsync_lock);
+            ret = 0;
+        }
+    }
+    return ret;
+}
+
+static int hwc_blank(struct hwc_composer_device_1* dev __unused, int disp,
+                     int blank __unused) {
+    if (disp != HWC_DISPLAY_PRIMARY) {
+        return -EINVAL;
+    }
+    return 0;
+}
+
+static void hwc_dump(hwc_composer_device_1* dev __unused, char* buff __unused,
+                     int buff_len __unused) {
+    // This is run when running dumpsys.
+    // No-op for now.
+}
+
+
+static int hwc_get_display_configs(struct hwc_composer_device_1* dev __unused,
+                                   int disp, uint32_t* configs, size_t* numConfigs) {
+    if (*numConfigs == 0) {
+        return 0;
+    }
+
+    if (disp == HWC_DISPLAY_PRIMARY) {
+        configs[0] = 0;
+        *numConfigs = 1;
+        return 0;
+    }
+
+    return -EINVAL;
+}
+
+
+static int32_t hwc_attribute(struct ranchu_hwc_composer_device_1* pdev,
+                             const uint32_t attribute) {
+    switch(attribute) {
+        case HWC_DISPLAY_VSYNC_PERIOD:
+            return pdev->vsync_period_ns;
+        case HWC_DISPLAY_WIDTH:
+            return pdev->fbdev->width;
+        case HWC_DISPLAY_HEIGHT:
+            return pdev->fbdev->height;
+        case HWC_DISPLAY_DPI_X:
+            return pdev->fbdev->xdpi*1000;
+        case HWC_DISPLAY_DPI_Y:
+            return pdev->fbdev->ydpi*1000;
+        default:
+            ALOGE("unknown display attribute %u", attribute);
+            return -EINVAL;
+    }
+}
+
+static int hwc_get_display_attributes(struct hwc_composer_device_1* dev __unused,
+                                      int disp, uint32_t config __unused,
+                                      const uint32_t* attributes, int32_t* values) {
+
+    struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev;
+    for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
+        if (disp == HWC_DISPLAY_PRIMARY) {
+            values[i] = hwc_attribute(pdev, attributes[i]);
+        } else {
+            ALOGE("unknown display type %u", disp);
+            return -EINVAL;
+        }
+    }
+
+    return 0;
+}
+
+static int hwc_close(hw_device_t* dev) {
+    struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev;
+    pthread_kill(pdev->vsync_thread, SIGTERM);
+    pthread_join(pdev->vsync_thread, NULL);
+    free(dev);
+    return 0;
+}
+
+static void* hwc_vsync_thread(void* data) {
+    struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)data;
+    setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+
+    struct timespec rt;
+    if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
+        ALOGE("%s:%d error in vsync thread clock_gettime: %s",
+              __FILE__, __LINE__, strerror(errno));
+    }
+    const int log_interval = 60;
+    int64_t last_logged = rt.tv_sec;
+    int sent = 0;
+    int last_sent = 0;
+    bool vsync_enabled = false;
+    struct timespec wait_time;
+    wait_time.tv_sec = 0;
+    wait_time.tv_nsec = pdev->vsync_period_ns;
+
+    while (true) {
+        int err = nanosleep(&wait_time, NULL);
+        if (err == -1) {
+            if (errno == EINTR) {
+                break;
+            }
+            ALOGE("error in vsync thread: %s", strerror(errno));
+        }
+
+        pthread_mutex_lock(&pdev->vsync_lock);
+        vsync_enabled = pdev->vsync_callback_enabled;
+        pthread_mutex_unlock(&pdev->vsync_lock);
+
+        if (!vsync_enabled) {
+            continue;
+        }
+
+        if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
+            ALOGE("%s:%d error in vsync thread clock_gettime: %s",
+                  __FILE__, __LINE__, strerror(errno));
+        }
+
+        int64_t timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec;
+        pdev->procs->vsync(pdev->procs, 0, timestamp);
+        if (rt.tv_sec - last_logged >= log_interval) {
+            ALOGD("hw_composer sent %d syncs in %ds", sent - last_sent, rt.tv_sec - last_logged);
+            last_logged = rt.tv_sec;
+            last_sent = sent;
+        }
+        ++sent;
+    }
+
+    return NULL;
+}
+
+static void hwc_register_procs(struct hwc_composer_device_1* dev,
+                               hwc_procs_t const* procs) {
+    struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev;
+    pdev->procs = procs;
+}
+
+static int hwc_open(const struct hw_module_t* module, const char* name,
+                    struct hw_device_t** device) {
+    int ret = 0;
+
+    if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
+        ALOGE("%s called with bad name %s", __FUNCTION__, name);
+        return -EINVAL;
+    }
+
+    ranchu_hwc_composer_device_1 *pdev = new ranchu_hwc_composer_device_1();
+    if (!pdev) {
+        ALOGE("%s failed to allocate dev", __FUNCTION__);
+        return -ENOMEM;
+    }
+
+    pdev->base.common.tag = HARDWARE_DEVICE_TAG;
+    pdev->base.common.version = HWC_DEVICE_API_VERSION_1_1;
+    pdev->base.common.module = const_cast<hw_module_t *>(module);
+    pdev->base.common.close = hwc_close;
+
+    pdev->base.prepare = hwc_prepare;
+    pdev->base.set = hwc_set;
+    pdev->base.eventControl = hwc_event_control;
+    pdev->base.blank = hwc_blank;
+    pdev->base.query = hwc_query;
+    pdev->base.registerProcs = hwc_register_procs;
+    pdev->base.dump = hwc_dump;
+    pdev->base.getDisplayConfigs = hwc_get_display_configs;
+    pdev->base.getDisplayAttributes = hwc_get_display_attributes;
+
+    pdev->vsync_period_ns = 1000*1000*1000/60; // vsync is 60 hz
+
+    hw_module_t const* hw_module;
+    ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &hw_module);
+    if (ret != 0) {
+        ALOGE("ranchu_hw_composer hwc_open %s module not found", GRALLOC_HARDWARE_MODULE_ID);
+        return ret;
+    }
+    ret = framebuffer_open(hw_module, &pdev->fbdev);
+    if (ret != 0) {
+        ALOGE("ranchu_hw_composer hwc_open could not open framebuffer");
+    }
+
+    pthread_mutex_init(&pdev->vsync_lock, NULL);
+    pdev->vsync_callback_enabled = false;
+
+    ret = pthread_create (&pdev->vsync_thread, NULL, hwc_vsync_thread, pdev);
+    if (ret) {
+        ALOGE("ranchu_hw_composer could not start vsync_thread\n");
+    }
+
+    *device = &pdev->base.common;
+
+    return ret;
+}
+
+
+static struct hw_module_methods_t hwc_module_methods = {
+    open: hwc_open,
+};
+
+hwc_module_t HAL_MODULE_INFO_SYM = {
+    common: {
+        tag: HARDWARE_MODULE_TAG,
+        module_api_version: HWC_MODULE_API_VERSION_0_1,
+        hal_api_version: HARDWARE_HAL_API_VERSION,
+        id: HWC_HARDWARE_MODULE_ID,
+        name: "Android Emulator hwcomposer module",
+        author: "The Android Open Source Project",
+        methods: &hwc_module_methods,
+    }
+};