blob: 670186bfeab66893ff40d21f35515bda3721d74b [file] [log] [blame]
/*
* 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 gce from
// frameworks/native/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.*
#include <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>
#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 <GceFrameBuffer.h>
#include <GceFrameBufferControl.h>
#include <gralloc_gce_priv.h>
#include <remoter_framework_pkt.h>
#include <sync/sync.h>
#include "gce_composer.h"
#include "geometry_utils.h"
#include "hwcomposer_common.h"
#include "base_composer.h"
#include "stats_keeper.h"
#ifdef USE_OLD_HWCOMPOSER
typedef avd::BaseComposer InnerComposerType;
#else
typedef avd::GceComposer InnerComposerType;
#endif
#ifdef GATHER_STATS
typedef avd::StatsKeepingComposer<InnerComposerType> ComposerType;
#else
typedef InnerComposerType ComposerType;
#endif
struct gce_hwc_composer_device_1_t {
gce_hwc_device base;
const hwc_procs_t* procs;
pthread_t vsync_thread;
int64_t vsync_base_timestamp;
int32_t vsync_period_ns;
ComposerType* composer;
};
static void dump_layer(gce_hwc_layer const* l) {
ALOGI(
"\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, "
"{%d,%d,%d,%d}, {%d,%d,%d,%d}",
l->compositionType, l->flags, l->handle, l->transform, l->blending,
l->sourceCrop.left, l->sourceCrop.top, l->sourceCrop.right,
l->sourceCrop.bottom, l->displayFrame.left, l->displayFrame.top,
l->displayFrame.right, l->displayFrame.bottom);
}
#if GCE_PLATFORM_SDK_BEFORE(J_MR1)
static int gce_hwc_prepare(gce_hwc_device* dev, hwc_layer_list_t* list) {
#else
static int gce_hwc_prepare(gce_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
int composited_layers_count =
reinterpret_cast<gce_hwc_composer_device_1_t*>(dev)
->composer->PrepareLayers(list->numHwLayers, &list->hwLayers[0]);
return 0;
}
#if GCE_PLATFORM_SDK_BEFORE(J_MR1)
int gce_hwc_set(struct hwc_composer_device* dev, hwc_display_t dpy,
hwc_surface_t sur, hwc_layer_list_t* list) {
reinterpret_cast<gce_hwc_composer_device_1_t*>(dev)->composer->SetLayers(
list->numHwLayers, &list->hwLayers[0]);
return 0;
}
#else
static int gce_hwc_set(gce_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;
gce_hwc_layer* layers = &contents->hwLayers[0];
reinterpret_cast<gce_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 %d 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 0;
}
#endif
static void gce_hwc_register_procs(gce_hwc_device* dev,
const hwc_procs_t* procs) {
struct gce_hwc_composer_device_1_t* pdev =
(struct gce_hwc_composer_device_1_t*)dev;
pdev->procs = procs;
}
static int gce_hwc_query(gce_hwc_device* dev, int what, int* value) {
struct gce_hwc_composer_device_1_t* pdev =
(struct gce_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 gce_hwc_event_control(
#if GCE_PLATFORM_SDK_BEFORE(J_MR1)
gce_hwc_device* dev, int event, int /*enabled*/) {
#else
gce_hwc_device* dev, int /*dpy*/, int event, int /*enabled*/) {
#endif
struct gce_hwc_composer_device_1_t* pdev =
(struct gce_hwc_composer_device_1_t*)dev;
if (event == HWC_EVENT_VSYNC) {
return 0;
}
return -EINVAL;
}
static void* hwc_vsync_thread(void* data) {
struct gce_hwc_composer_device_1_t* pdev =
(struct gce_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;
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;
}
}
pdev->procs->vsync(const_cast<hwc_procs_t*>(pdev->procs), 0, timestamp);
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;
}
++sent;
}
return NULL;
}
static int gce_hwc_blank(gce_hwc_device* dev, int disp, int /*blank*/) {
struct gce_hwc_composer_device_1_t* pdev =
(struct gce_hwc_composer_device_1_t*)dev;
if (!IS_PRIMARY_DISPLAY(disp)) return -EINVAL;
return 0;
}
static void gce_hwc_dump(gce_hwc_device* dev, char* buff, int buff_len) {
reinterpret_cast<gce_hwc_composer_device_1_t*>(dev)->composer->Dump(buff,
buff_len);
}
static int gce_hwc_get_display_configs(gce_hwc_device* dev, int disp,
uint32_t* configs, size_t* numConfigs) {
struct gce_hwc_composer_device_1_t* pdev =
(struct gce_hwc_composer_device_1_t*)dev;
if (*numConfigs == 0) return 0;
if (IS_PRIMARY_DISPLAY(disp)) {
configs[0] = 0;
*numConfigs = 1;
return 0;
}
return -EINVAL;
}
#if GCE_PLATFORM_SDK_AFTER(J)
static int32_t gce_hwc_attribute(struct gce_hwc_composer_device_1_t* pdev,
const uint32_t attribute) {
const GceFrameBuffer& config = GceFrameBuffer::getInstance();
switch (attribute) {
case HWC_DISPLAY_VSYNC_PERIOD:
return pdev->vsync_period_ns;
case HWC_DISPLAY_WIDTH:
return config.x_res();
case HWC_DISPLAY_HEIGHT:
return config.y_res();
case HWC_DISPLAY_DPI_X:
ALOGI("Reporting DPI_X of %d", config.dpi());
return config.dpi() * 1000; // The number of pixels per thousand inches
case HWC_DISPLAY_DPI_Y:
ALOGI("Reporting DPI_Y of %d", config.dpi());
return config.dpi() * 1000; // The number of pixels per thousand inches
default:
ALOGE("unknown display attribute %u", attribute);
return -EINVAL;
}
}
static int gce_hwc_get_display_attributes(gce_hwc_device* dev, int disp,
uint32_t config __unused,
const uint32_t* attributes,
int32_t* values) {
struct gce_hwc_composer_device_1_t* pdev =
(struct gce_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] = gce_hwc_attribute(pdev, attributes[i]);
}
return 0;
}
#endif
static int gce_hwc_close(hw_device_t* device) {
struct gce_hwc_composer_device_1_t* dev =
(struct gce_hwc_composer_device_1_t*)device;
ALOGE("gce_hwc_close");
pthread_kill(dev->vsync_thread, SIGTERM);
pthread_join(dev->vsync_thread, NULL);
delete dev->composer;
delete dev;
return 0;
}
static int gce_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;
}
gce_hwc_composer_device_1_t* dev = new gce_hwc_composer_device_1_t();
if (!dev) {
ALOGE("%s failed to allocate dev", __FUNCTION__);
return -ENOMEM;
}
// TODO(ghartman): Read metadata here
int refreshRate = 60;
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 = GCE_HWC_DEVICE_API_VERSION;
dev->base.common.module = const_cast<hw_module_t*>(module);
dev->base.common.close = gce_hwc_close;
dev->base.prepare = gce_hwc_prepare;
dev->base.set = gce_hwc_set;
dev->base.query = gce_hwc_query;
dev->base.registerProcs = gce_hwc_register_procs;
dev->base.dump = gce_hwc_dump;
#if GCE_PLATFORM_SDK_BEFORE(J_MR1)
static hwc_methods_t hwc_methods = {gce_hwc_event_control};
dev->base.methods = &hwc_methods;
#else
dev->base.blank = gce_hwc_blank;
dev->base.eventControl = gce_hwc_event_control;
dev->base.getDisplayConfigs = gce_hwc_get_display_configs;
dev->base.getDisplayAttributes = gce_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 gce_hwc_module_methods = {
gce_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,
"GCE hwcomposer module",
"Google",
&gce_hwc_module_methods,
NULL,
{0}}};