diff options
author | Joonas Kylmälä <joonas.kylmala@iki.fi> | 2019-07-19 14:06:59 -0400 |
---|---|---|
committer | Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org> | 2020-02-10 18:10:05 +0100 |
commit | 2f70ec169e9a554e32ada8f477bdccdd2c76e08a (patch) | |
tree | 3dc8040502aace08d3f12f0b0f686dac625a8209 | |
parent | aef5eacc40d977564a5d144d19c2e5e81607fa2f (diff) | |
download | device_samsung_i9305-2f70ec169e9a554e32ada8f477bdccdd2c76e08a.tar.gz device_samsung_i9305-2f70ec169e9a554e32ada8f477bdccdd2c76e08a.tar.bz2 device_samsung_i9305-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.mk | 1 | ||||
-rw-r--r-- | hwcomposer/Android.mk | 68 | ||||
-rw-r--r-- | hwcomposer/hwcomposer.cpp | 362 |
3 files changed, 431 insertions, 0 deletions
@@ -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, + } +}; |