/* * Copyright (C) 2016 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. */ // Versions of hwcomposer we implement: // JB: 0.3 // JB-MR1 to N : 1.1 // N-MR1 to ... : We report 1.1 but SurfaceFlinger has the option to use an // adapter to treat our 1.1 hwcomposer as a 2.0. If SF stops using that adapter // to support 1.1 implementations it can be copied into cuttlefish from // frameworks/native/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.* #define LOG_TAG "hwc.cf_x86" #include <guest/libs/platform_support/api_level_fixes.h> #include <errno.h> #include <fcntl.h> #include <math.h> #include <poll.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/resource.h> #include <sys/time.h> #include <string> #define HWC_REMOVE_DEPRECATED_VERSIONS 1 #include <cutils/compiler.h> #include <cutils/log.h> #include <cutils/properties.h> #include <hardware/gralloc.h> #include <hardware/hardware.h> #include <hardware/hwcomposer.h> #include <hardware/hwcomposer_defs.h> #include <utils/String8.h> #include <utils/Vector.h> #include "common/vsoc/lib/screen_region_view.h" #include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h" #include <sync/sync.h> #include "base_composer.h" #include "geometry_utils.h" #include "hwcomposer_common.h" #include "stats_keeper.h" #include "vsoc_composer.h" using vsoc::screen::ScreenRegionView; #ifdef USE_OLD_HWCOMPOSER typedef cvd::BaseComposer InnerComposerType; #else typedef cvd::VSoCComposer InnerComposerType; #endif #ifdef GATHER_STATS typedef cvd::StatsKeepingComposer<InnerComposerType> ComposerType; #else typedef InnerComposerType ComposerType; #endif struct vsoc_hwc_composer_device_1_t { vsoc_hwc_device base; const hwc_procs_t* procs; pthread_t vsync_thread; int64_t vsync_base_timestamp; int32_t vsync_period_ns; ComposerType* composer; }; namespace { std::string CompositionString(int type) { switch (type) { case HWC_FRAMEBUFFER: return "Framebuffer"; case HWC_OVERLAY: return "Overlay"; case HWC_BACKGROUND: return "Background"; case HWC_FRAMEBUFFER_TARGET: return "FramebufferTarget"; #if VSOC_PLATFORM_SDK_AFTER(K) case HWC_SIDEBAND: return "Sideband"; case HWC_CURSOR_OVERLAY: return "CursorOverlay"; #endif default: return std::string("Unknown (") + std::to_string(type) + ")"; } } void LogLayers(int num_layers, vsoc_hwc_layer* layers, int invalid) { ALOGE("Layers:"); for (int idx = 0; idx < num_layers; ++idx) { std::string log_line; if (idx == invalid) { log_line = "Invalid layer: "; } log_line += "Composition Type: " + CompositionString(layers[idx].compositionType); ALOGE("%s", log_line.c_str()); } } // Ensures that the layer does not include any inconsistencies bool IsValidLayer(const vsoc_hwc_layer& layer) { if (layer.flags & HWC_SKIP_LAYER) { // A layer we are asked to skip validate should not be marked as skip ALOGE("%s: Layer is marked as skip", __FUNCTION__); return false; } // Check displayFrame if (layer.displayFrame.left > layer.displayFrame.right || layer.displayFrame.top > layer.displayFrame.bottom) { ALOGE( "%s: Malformed rectangle (displayFrame): [left = %d, right = %d, top = " "%d, bottom = %d]", __FUNCTION__, layer.displayFrame.left, layer.displayFrame.right, layer.displayFrame.top, layer.displayFrame.bottom); return false; } // Validate the handle if (private_handle_t::validate(layer.handle) != 0) { ALOGE("%s: Layer contains an invalid gralloc handle.", __FUNCTION__); return false; } const private_handle_t* p_handle = reinterpret_cast<const private_handle_t*>(layer.handle); // Check sourceCrop if (layer.sourceCrop.left > layer.sourceCrop.right || layer.sourceCrop.top > layer.sourceCrop.bottom) { ALOGE( "%s: Malformed rectangle (sourceCrop): [left = %d, right = %d, top = " "%d, bottom = %d]", __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right, layer.sourceCrop.top, layer.sourceCrop.bottom); return false; } if (layer.sourceCrop.left < 0 || layer.sourceCrop.top < 0 || layer.sourceCrop.right > p_handle->x_res || layer.sourceCrop.bottom > p_handle->y_res) { ALOGE( "%s: Invalid sourceCrop for buffer handle: sourceCrop = [left = %d, " "right = %d, top = %d, bottom = %d], handle = [width = %d, height = " "%d]", __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right, layer.sourceCrop.top, layer.sourceCrop.bottom, p_handle->x_res, p_handle->y_res); return false; } return true; } bool IsValidComposition(int num_layers, vsoc_hwc_layer* layers, bool on_set) { if (num_layers == 0) { ALOGE("Composition requested with 0 layers"); return false; } // Sometimes the hwcomposer receives a prepare and set calls with no other // layer than the FRAMEBUFFER_TARGET with a null handler. We treat this case // independently as a valid composition, but issue a warning about it. if (num_layers == 1 && layers[0].compositionType == HWC_FRAMEBUFFER_TARGET && layers[0].handle == NULL) { ALOGW("Received request for empty composition, treating as valid noop"); return true; } // The FRAMEBUFFER_TARGET layer needs to be sane only if // there is at least one layer marked HWC_FRAMEBUFFER or if there is no layer // marked HWC_OVERLAY (i.e some layers where composed with OpenGL, no layer // marked overlay or framebuffer means that surfaceflinger decided to go for // OpenGL without asking the hwcomposer first) bool check_fb_target = true; for (int idx = 0; idx < num_layers; ++idx) { if (layers[idx].compositionType == HWC_FRAMEBUFFER) { // There is at least one, so it needs to be checked. // It may have been set to false before, so ensure it's set to true. check_fb_target = true; break; } if (layers[idx].compositionType == HWC_OVERLAY) { // At least one overlay, we may not need to. check_fb_target = false; } } for (int idx = 0; idx < num_layers; ++idx) { switch (layers[idx].compositionType) { case HWC_FRAMEBUFFER_TARGET: // In the call to prepare() the framebuffer target does not have a valid // buffer_handle, so we don't validate it yet. if (on_set && check_fb_target && !IsValidLayer(layers[idx])) { ALOGE("%s: Invalid layer found", __FUNCTION__); LogLayers(num_layers, layers, idx); return false; } break; case HWC_OVERLAY: if (!(layers[idx].flags & HWC_SKIP_LAYER) && !IsValidLayer(layers[idx])) { ALOGE("%s: Invalid layer found", __FUNCTION__); LogLayers(num_layers, layers, idx); return false; } break; } } return true; } } #if VSOC_PLATFORM_SDK_BEFORE(J_MR1) static int vsoc_hwc_prepare(vsoc_hwc_device* dev, hwc_layer_list_t* list) { #else static int vsoc_hwc_prepare(vsoc_hwc_device* dev, size_t numDisplays, hwc_display_contents_1_t** displays) { if (!numDisplays || !displays) return 0; hwc_display_contents_1_t* list = displays[HWC_DISPLAY_PRIMARY]; if (!list) return 0; #endif if (!IsValidComposition(list->numHwLayers, &list->hwLayers[0], false)) { LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__); return -1; } reinterpret_cast<vsoc_hwc_composer_device_1_t*>(dev)->composer->PrepareLayers( list->numHwLayers, &list->hwLayers[0]); return 0; } #if VSOC_PLATFORM_SDK_BEFORE(J_MR1) int vsoc_hwc_set(struct hwc_composer_device* dev, hwc_display_t dpy, hwc_surface_t sur, hwc_layer_list_t* list) { if (list->numHwLayers == 1 && layers[0].compositionType == HWC_FRAMEBUFFER_TARGET) { ALOGW("Received request for empty composition, treating as valid noop"); return 0; } if (!IsValidComposition(list->numHwLayers, &list->hwLayers[0], true)) { LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__); return -1; } return reinterpret_cast<vsoc_hwc_composer_device_1_t*>(dev) ->composer->SetLayers(list->numHwLayers, &list->hwLayers[0]); } #else static int vsoc_hwc_set(vsoc_hwc_device* dev, 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; vsoc_hwc_layer* layers = &contents->hwLayers[0]; if (contents->numHwLayers == 1 && layers[0].compositionType == HWC_FRAMEBUFFER_TARGET) { ALOGW("Received request for empty composition, treating as valid noop"); return 0; } if (!IsValidComposition(contents->numHwLayers, layers, true)) { LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__); return -1; } int retval = reinterpret_cast<vsoc_hwc_composer_device_1_t*>(dev)->composer->SetLayers( contents->numHwLayers, layers); int closedFds = 0; for (size_t index = 0; index < contents->numHwLayers; ++index) { if (layers[index].acquireFenceFd != -1) { close(layers[index].acquireFenceFd); layers[index].acquireFenceFd = -1; ++closedFds; } } if (closedFds) { ALOGI("Saw %zu layers, closed=%d", contents->numHwLayers, closedFds); } // TODO(ghartman): This should be set before returning. On the next set it // should be signalled when we load the new frame. contents->retireFenceFd = -1; return retval; } #endif static void vsoc_hwc_register_procs(vsoc_hwc_device* dev, const hwc_procs_t* procs) { struct vsoc_hwc_composer_device_1_t* pdev = (struct vsoc_hwc_composer_device_1_t*)dev; pdev->procs = procs; } static int vsoc_hwc_query(vsoc_hwc_device* dev, int what, int* value) { struct vsoc_hwc_composer_device_1_t* pdev = (struct vsoc_hwc_composer_device_1_t*)dev; switch (what) { case HWC_BACKGROUND_LAYER_SUPPORTED: // we 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 vsoc_hwc_event_control( #if VSOC_PLATFORM_SDK_BEFORE(J_MR1) vsoc_hwc_device* /*dev*/, int event, int /*enabled*/) { #else vsoc_hwc_device* /*dev*/, int /*dpy*/, int event, int /*enabled*/) { #endif if (event == HWC_EVENT_VSYNC) { return 0; } return -EINVAL; } static void* hwc_vsync_thread(void* data) { struct vsoc_hwc_composer_device_1_t* pdev = (struct vsoc_hwc_composer_device_1_t*)data; setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); int64_t base_timestamp = pdev->vsync_base_timestamp; int64_t last_logged = base_timestamp / 1e9; int sent = 0; int last_sent = 0; static const int log_interval = 60; void (*vsync_proc)(const struct hwc_procs*, int, int64_t) = nullptr; bool log_no_procs = true, log_no_vsync = true; while (true) { struct timespec rt; 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; // Given now's timestamp calculate the time of the next timestamp. timestamp += pdev->vsync_period_ns - (timestamp - base_timestamp) % pdev->vsync_period_ns; rt.tv_sec = timestamp / 1e9; rt.tv_nsec = timestamp % static_cast<int32_t>(1e9); int err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &rt, NULL); if (err == -1) { ALOGE("error in vsync thread: %s", strerror(errno)); if (errno == EINTR) { continue; } } // The vsync thread is started on device open, it may run before the // registerProcs callback has a chance to be called, so we need to make sure // procs is not NULL before dereferencing it. if (pdev && pdev->procs) { vsync_proc = pdev->procs->vsync; } else if (log_no_procs) { log_no_procs = false; ALOGI("procs is not set yet, unable to deliver vsync event"); } if (vsync_proc) { vsync_proc(const_cast<hwc_procs_t*>(pdev->procs), 0, timestamp); ++sent; } else if (log_no_vsync) { log_no_vsync = false; ALOGE("vsync callback is null (but procs was already set)"); } if (rt.tv_sec - last_logged > log_interval) { ALOGI("Sent %d syncs in %ds", sent - last_sent, log_interval); last_logged = rt.tv_sec; last_sent = sent; } } return NULL; } static int vsoc_hwc_blank(vsoc_hwc_device* /*dev*/, int disp, int /*blank*/) { if (!IS_PRIMARY_DISPLAY(disp)) return -EINVAL; return 0; } static void vsoc_hwc_dump(vsoc_hwc_device* dev, char* buff, int buff_len) { reinterpret_cast<vsoc_hwc_composer_device_1_t*>(dev)->composer->Dump( buff, buff_len); } static int vsoc_hwc_get_display_configs(vsoc_hwc_device* /*dev*/, int disp, uint32_t* configs, size_t* numConfigs) { if (*numConfigs == 0) return 0; if (IS_PRIMARY_DISPLAY(disp)) { configs[0] = 0; *numConfigs = 1; return 0; } return -EINVAL; } #if VSOC_PLATFORM_SDK_AFTER(J) static int32_t vsoc_hwc_attribute(struct vsoc_hwc_composer_device_1_t* pdev, const uint32_t attribute) { auto screen_view = ScreenRegionView::GetInstance(); switch (attribute) { case HWC_DISPLAY_VSYNC_PERIOD: return pdev->vsync_period_ns; case HWC_DISPLAY_WIDTH: return screen_view->x_res(); case HWC_DISPLAY_HEIGHT: return screen_view->y_res(); case HWC_DISPLAY_DPI_X: ALOGI("Reporting DPI_X of %d", screen_view->dpi()); // The number of pixels per thousand inches return screen_view->dpi() * 1000; case HWC_DISPLAY_DPI_Y: ALOGI("Reporting DPI_Y of %d", screen_view->dpi()); // The number of pixels per thousand inches return screen_view->dpi() * 1000; default: ALOGE("unknown display attribute %u", attribute); return -EINVAL; } } static int vsoc_hwc_get_display_attributes(vsoc_hwc_device* dev, int disp, uint32_t config __unused, const uint32_t* attributes, int32_t* values) { struct vsoc_hwc_composer_device_1_t* pdev = (struct vsoc_hwc_composer_device_1_t*)dev; if (!IS_PRIMARY_DISPLAY(disp)) { ALOGE("unknown display type %u", disp); return -EINVAL; } for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) { values[i] = vsoc_hwc_attribute(pdev, attributes[i]); } return 0; } #endif static int vsoc_hwc_close(hw_device_t* device) { struct vsoc_hwc_composer_device_1_t* dev = (struct vsoc_hwc_composer_device_1_t*)device; ALOGE("vsoc_hwc_close"); pthread_kill(dev->vsync_thread, SIGTERM); pthread_join(dev->vsync_thread, NULL); delete dev->composer; delete dev; return 0; } static int vsoc_hwc_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) { ALOGI("%s", __FUNCTION__); if (strcmp(name, HWC_HARDWARE_COMPOSER)) { ALOGE("%s called with bad name %s", __FUNCTION__, name); return -EINVAL; } vsoc_hwc_composer_device_1_t* dev = new vsoc_hwc_composer_device_1_t(); if (!dev) { ALOGE("%s failed to allocate dev", __FUNCTION__); return -ENOMEM; } int refreshRate = ScreenRegionView::GetInstance()->refresh_rate_hz(); dev->vsync_period_ns = 1000000000 / refreshRate; struct timespec rt; if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) { ALOGE("%s:%d error in vsync thread clock_gettime: %s", __FILE__, __LINE__, strerror(errno)); } dev->vsync_base_timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec; dev->base.common.tag = HARDWARE_DEVICE_TAG; dev->base.common.version = VSOC_HWC_DEVICE_API_VERSION; dev->base.common.module = const_cast<hw_module_t*>(module); dev->base.common.close = vsoc_hwc_close; dev->base.prepare = vsoc_hwc_prepare; dev->base.set = vsoc_hwc_set; dev->base.query = vsoc_hwc_query; dev->base.registerProcs = vsoc_hwc_register_procs; dev->base.dump = vsoc_hwc_dump; #if VSOC_PLATFORM_SDK_BEFORE(J_MR1) static hwc_methods_t hwc_methods = {vsoc_hwc_event_control}; dev->base.methods = &hwc_methods; #else dev->base.blank = vsoc_hwc_blank; dev->base.eventControl = vsoc_hwc_event_control; dev->base.getDisplayConfigs = vsoc_hwc_get_display_configs; dev->base.getDisplayAttributes = vsoc_hwc_get_display_attributes; #endif dev->composer = new ComposerType(dev->vsync_base_timestamp, dev->vsync_period_ns); int ret = pthread_create(&dev->vsync_thread, NULL, hwc_vsync_thread, dev); if (ret) { ALOGE("failed to start vsync thread: %s", strerror(ret)); ret = -ret; delete dev; } else { *device = &dev->base.common; } return ret; } static struct hw_module_methods_t vsoc_hwc_module_methods = { vsoc_hwc_open, }; hwc_module_t HAL_MODULE_INFO_SYM = {{HARDWARE_MODULE_TAG, HWC_MODULE_API_VERSION_0_1, HARDWARE_HAL_API_VERSION, HWC_HARDWARE_MODULE_ID, "VSOC hwcomposer module", "Google", &vsoc_hwc_module_methods, NULL, {0}}};