aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoonas Kylmälä <joonas.kylmala@iki.fi>2019-07-19 14:06:59 -0400
committerDenis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>2020-02-10 18:10:05 +0100
commit2f70ec169e9a554e32ada8f477bdccdd2c76e08a (patch)
tree3dc8040502aace08d3f12f0b0f686dac625a8209
parentaef5eacc40d977564a5d144d19c2e5e81607fa2f (diff)
downloaddevice_samsung_i9300-2f70ec169e9a554e32ada8f477bdccdd2c76e08a.tar.gz
device_samsung_i9300-2f70ec169e9a554e32ada8f477bdccdd2c76e08a.tar.bz2
device_samsung_i9300-2f70ec169e9a554e32ada8f477bdccdd2c76e08a.zip
Add hwcomposer.ranchu
This is used for testing SwiftShader Signed-off-by: Joonas Kylmälä <joonas.kylmala@iki.fi>
-rw-r--r--device.mk1
-rw-r--r--hwcomposer/Android.mk68
-rw-r--r--hwcomposer/hwcomposer.cpp362
3 files changed, 431 insertions, 0 deletions
diff --git a/device.mk b/device.mk
index bf27f92..1230ccd 100644
--- a/device.mk
+++ b/device.mk
@@ -26,6 +26,7 @@ PRODUCT_PACKAGES += \
gralloc.gbm \
hwcomposer.drm \
libGLES_mesa \
+ hwcomposer.ranchu \
android.hardware.graphics.composer@2.1-impl \
android.hardware.graphics.composer@2.1-service \
diff --git a/hwcomposer/Android.mk b/hwcomposer/Android.mk
new file mode 100644
index 0000000..55c66bb
--- /dev/null
+++ b/hwcomposer/Android.mk
@@ -0,0 +1,68 @@
+#
+# 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)
+LOCAL_VENDOR_MODULE := true
+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_VENDOR_MODULE := true
+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..cc0dc66
--- /dev/null
+++ b/hwcomposer/hwcomposer.cpp
@@ -0,0 +1,362 @@
+/*
+ * 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 <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+#include <log/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]);
+ if (values[i] == -EINVAL) {
+ return -EINVAL;
+ }
+ } 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", (uint32_t)(sent - last_sent),
+ (uint32_t)(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,
+ }
+};