Home | History | Annotate | Download | only in hwcomposer
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 #include <errno.h>
     17 #include <pthread.h>
     18 #include <stdlib.h>
     19 #include <string.h>
     20 #include <sys/time.h>
     21 #include <sys/resource.h>
     22 #include <unistd.h>
     23 
     24 #include <log/log.h>
     25 #include <hardware/hwcomposer.h>
     26 #include <sync/sync.h>
     27 
     28 struct ranchu_hwc_composer_device_1 {
     29     hwc_composer_device_1_t base; // constant after init
     30     const hwc_procs_t *procs;     // constant after init
     31     pthread_t vsync_thread;       // constant after init
     32     int32_t vsync_period_ns;      // constant after init
     33     framebuffer_device_t* fbdev;  // constant after init
     34 
     35     pthread_mutex_t vsync_lock;
     36     bool vsync_callback_enabled; // protected by this->vsync_lock
     37 };
     38 
     39 static int hwc_prepare(hwc_composer_device_1_t* dev __unused,
     40                        size_t numDisplays, hwc_display_contents_1_t** displays) {
     41 
     42     if (!numDisplays || !displays) return 0;
     43 
     44     hwc_display_contents_1_t* contents = displays[HWC_DISPLAY_PRIMARY];
     45 
     46     if (!contents) return 0;
     47 
     48     for (size_t i = 0; i < contents->numHwLayers; i++) {
     49     // We do not handle any layers, so set composition type of any non
     50     // HWC_FRAMEBUFFER_TARGET layer to to HWC_FRAMEBUFFER.
     51         if (contents->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
     52             continue;
     53         }
     54         contents->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
     55     }
     56     return 0;
     57 }
     58 
     59 static int hwc_set(struct hwc_composer_device_1* dev,size_t numDisplays,
     60                    hwc_display_contents_1_t** displays) {
     61     struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev;
     62     if (!numDisplays || !displays) {
     63         return 0;
     64     }
     65 
     66     hwc_display_contents_1_t* contents = displays[HWC_DISPLAY_PRIMARY];
     67 
     68     int retireFenceFd = -1;
     69     int err = 0;
     70     for (size_t layer = 0; layer < contents->numHwLayers; layer++) {
     71             hwc_layer_1_t* fb_layer = &contents->hwLayers[layer];
     72 
     73         int releaseFenceFd = -1;
     74         if (fb_layer->acquireFenceFd > 0) {
     75             const int kAcquireWarningMS= 3000;
     76             err = sync_wait(fb_layer->acquireFenceFd, kAcquireWarningMS);
     77             if (err < 0 && errno == ETIME) {
     78                 ALOGE("hwcomposer waited on fence %d for %d ms",
     79                       fb_layer->acquireFenceFd, kAcquireWarningMS);
     80             }
     81             close(fb_layer->acquireFenceFd);
     82 
     83             if (fb_layer->compositionType != HWC_FRAMEBUFFER_TARGET) {
     84                 ALOGE("hwcomposer found acquire fence on layer %d which is not an"
     85                       "HWC_FRAMEBUFFER_TARGET layer", layer);
     86             }
     87 
     88             releaseFenceFd = dup(fb_layer->acquireFenceFd);
     89             fb_layer->acquireFenceFd = -1;
     90         }
     91 
     92         if (fb_layer->compositionType != HWC_FRAMEBUFFER_TARGET) {
     93             continue;
     94         }
     95 
     96         pdev->fbdev->post(pdev->fbdev, fb_layer->handle);
     97         fb_layer->releaseFenceFd = releaseFenceFd;
     98 
     99         if (releaseFenceFd > 0) {
    100             if (retireFenceFd == -1) {
    101                 retireFenceFd = dup(releaseFenceFd);
    102             } else {
    103                 int mergedFenceFd = sync_merge("hwc_set retireFence",
    104                                                releaseFenceFd, retireFenceFd);
    105                 close(retireFenceFd);
    106                 retireFenceFd = mergedFenceFd;
    107             }
    108         }
    109     }
    110 
    111     contents->retireFenceFd = retireFenceFd;
    112     return err;
    113 }
    114 
    115 static int hwc_query(struct hwc_composer_device_1* dev, int what, int* value) {
    116     struct ranchu_hwc_composer_device_1* pdev =
    117             (struct ranchu_hwc_composer_device_1*)dev;
    118 
    119     switch (what) {
    120         case HWC_BACKGROUND_LAYER_SUPPORTED:
    121             // we do not support the background layer
    122             value[0] = 0;
    123             break;
    124         case HWC_VSYNC_PERIOD:
    125             value[0] = pdev->vsync_period_ns;
    126             break;
    127         default:
    128             // unsupported query
    129             ALOGE("%s badness unsupported query what=%d", __FUNCTION__, what);
    130             return -EINVAL;
    131     }
    132     return 0;
    133 }
    134 
    135 static int hwc_event_control(struct hwc_composer_device_1* dev, int dpy __unused,
    136                              int event, int enabled) {
    137     struct ranchu_hwc_composer_device_1* pdev =
    138             (struct ranchu_hwc_composer_device_1*)dev;
    139     int ret = -EINVAL;
    140 
    141     // enabled can only be 0 or 1
    142     if (!(enabled & ~1)) {
    143         if (event == HWC_EVENT_VSYNC) {
    144             pthread_mutex_lock(&pdev->vsync_lock);
    145             pdev->vsync_callback_enabled=enabled;
    146             pthread_mutex_unlock(&pdev->vsync_lock);
    147             ret = 0;
    148         }
    149     }
    150     return ret;
    151 }
    152 
    153 static int hwc_blank(struct hwc_composer_device_1* dev __unused, int disp,
    154                      int blank __unused) {
    155     if (disp != HWC_DISPLAY_PRIMARY) {
    156         return -EINVAL;
    157     }
    158     return 0;
    159 }
    160 
    161 static void hwc_dump(hwc_composer_device_1* dev __unused, char* buff __unused,
    162                      int buff_len __unused) {
    163     // This is run when running dumpsys.
    164     // No-op for now.
    165 }
    166 
    167 
    168 static int hwc_get_display_configs(struct hwc_composer_device_1* dev __unused,
    169                                    int disp, uint32_t* configs, size_t* numConfigs) {
    170     if (*numConfigs == 0) {
    171         return 0;
    172     }
    173 
    174     if (disp == HWC_DISPLAY_PRIMARY) {
    175         configs[0] = 0;
    176         *numConfigs = 1;
    177         return 0;
    178     }
    179 
    180     return -EINVAL;
    181 }
    182 
    183 
    184 static int32_t hwc_attribute(struct ranchu_hwc_composer_device_1* pdev,
    185                              const uint32_t attribute) {
    186     switch(attribute) {
    187         case HWC_DISPLAY_VSYNC_PERIOD:
    188             return pdev->vsync_period_ns;
    189         case HWC_DISPLAY_WIDTH:
    190             return pdev->fbdev->width;
    191         case HWC_DISPLAY_HEIGHT:
    192             return pdev->fbdev->height;
    193         case HWC_DISPLAY_DPI_X:
    194             return pdev->fbdev->xdpi*1000;
    195         case HWC_DISPLAY_DPI_Y:
    196             return pdev->fbdev->ydpi*1000;
    197         default:
    198             ALOGE("unknown display attribute %u", attribute);
    199             return -EINVAL;
    200     }
    201 }
    202 
    203 static int hwc_get_display_attributes(struct hwc_composer_device_1* dev __unused,
    204                                       int disp, uint32_t config __unused,
    205                                       const uint32_t* attributes, int32_t* values) {
    206 
    207     struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev;
    208     for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
    209         if (disp == HWC_DISPLAY_PRIMARY) {
    210             values[i] = hwc_attribute(pdev, attributes[i]);
    211             if (values[i] == -EINVAL) {
    212                 return -EINVAL;
    213             }
    214         } else {
    215             ALOGE("unknown display type %u", disp);
    216             return -EINVAL;
    217         }
    218     }
    219 
    220     return 0;
    221 }
    222 
    223 static int hwc_close(hw_device_t* dev) {
    224     struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev;
    225     pthread_kill(pdev->vsync_thread, SIGTERM);
    226     pthread_join(pdev->vsync_thread, NULL);
    227     free(dev);
    228     return 0;
    229 }
    230 
    231 static void* hwc_vsync_thread(void* data) {
    232     struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)data;
    233     setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
    234 
    235     struct timespec rt;
    236     if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
    237         ALOGE("%s:%d error in vsync thread clock_gettime: %s",
    238               __FILE__, __LINE__, strerror(errno));
    239     }
    240     const int log_interval = 60;
    241     int64_t last_logged = rt.tv_sec;
    242     int sent = 0;
    243     int last_sent = 0;
    244     bool vsync_enabled = false;
    245     struct timespec wait_time;
    246     wait_time.tv_sec = 0;
    247     wait_time.tv_nsec = pdev->vsync_period_ns;
    248 
    249     while (true) {
    250         int err = nanosleep(&wait_time, NULL);
    251         if (err == -1) {
    252             if (errno == EINTR) {
    253                 break;
    254             }
    255             ALOGE("error in vsync thread: %s", strerror(errno));
    256         }
    257 
    258         pthread_mutex_lock(&pdev->vsync_lock);
    259         vsync_enabled = pdev->vsync_callback_enabled;
    260         pthread_mutex_unlock(&pdev->vsync_lock);
    261 
    262         if (!vsync_enabled) {
    263             continue;
    264         }
    265 
    266         if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
    267             ALOGE("%s:%d error in vsync thread clock_gettime: %s",
    268                   __FILE__, __LINE__, strerror(errno));
    269         }
    270 
    271         int64_t timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec;
    272         pdev->procs->vsync(pdev->procs, 0, timestamp);
    273         if (rt.tv_sec - last_logged >= log_interval) {
    274             ALOGD("hw_composer sent %d syncs in %ds", sent - last_sent, rt.tv_sec - last_logged);
    275             last_logged = rt.tv_sec;
    276             last_sent = sent;
    277         }
    278         ++sent;
    279     }
    280 
    281     return NULL;
    282 }
    283 
    284 static void hwc_register_procs(struct hwc_composer_device_1* dev,
    285                                hwc_procs_t const* procs) {
    286     struct ranchu_hwc_composer_device_1* pdev = (struct ranchu_hwc_composer_device_1*)dev;
    287     pdev->procs = procs;
    288 }
    289 
    290 static int hwc_open(const struct hw_module_t* module, const char* name,
    291                     struct hw_device_t** device) {
    292     int ret = 0;
    293 
    294     if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
    295         ALOGE("%s called with bad name %s", __FUNCTION__, name);
    296         return -EINVAL;
    297     }
    298 
    299     ranchu_hwc_composer_device_1 *pdev = new ranchu_hwc_composer_device_1();
    300     if (!pdev) {
    301         ALOGE("%s failed to allocate dev", __FUNCTION__);
    302         return -ENOMEM;
    303     }
    304 
    305     pdev->base.common.tag = HARDWARE_DEVICE_TAG;
    306     pdev->base.common.version = HWC_DEVICE_API_VERSION_1_1;
    307     pdev->base.common.module = const_cast<hw_module_t *>(module);
    308     pdev->base.common.close = hwc_close;
    309 
    310     pdev->base.prepare = hwc_prepare;
    311     pdev->base.set = hwc_set;
    312     pdev->base.eventControl = hwc_event_control;
    313     pdev->base.blank = hwc_blank;
    314     pdev->base.query = hwc_query;
    315     pdev->base.registerProcs = hwc_register_procs;
    316     pdev->base.dump = hwc_dump;
    317     pdev->base.getDisplayConfigs = hwc_get_display_configs;
    318     pdev->base.getDisplayAttributes = hwc_get_display_attributes;
    319 
    320     pdev->vsync_period_ns = 1000*1000*1000/60; // vsync is 60 hz
    321 
    322     hw_module_t const* hw_module;
    323     ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &hw_module);
    324     if (ret != 0) {
    325         ALOGE("ranchu_hw_composer hwc_open %s module not found", GRALLOC_HARDWARE_MODULE_ID);
    326         return ret;
    327     }
    328     ret = framebuffer_open(hw_module, &pdev->fbdev);
    329     if (ret != 0) {
    330         ALOGE("ranchu_hw_composer hwc_open could not open framebuffer");
    331     }
    332 
    333     pthread_mutex_init(&pdev->vsync_lock, NULL);
    334     pdev->vsync_callback_enabled = false;
    335 
    336     ret = pthread_create (&pdev->vsync_thread, NULL, hwc_vsync_thread, pdev);
    337     if (ret) {
    338         ALOGE("ranchu_hw_composer could not start vsync_thread\n");
    339     }
    340 
    341     *device = &pdev->base.common;
    342 
    343     return ret;
    344 }
    345 
    346 
    347 static struct hw_module_methods_t hwc_module_methods = {
    348     open: hwc_open,
    349 };
    350 
    351 hwc_module_t HAL_MODULE_INFO_SYM = {
    352     common: {
    353         tag: HARDWARE_MODULE_TAG,
    354         module_api_version: HWC_MODULE_API_VERSION_0_1,
    355         hal_api_version: HARDWARE_HAL_API_VERSION,
    356         id: HWC_HARDWARE_MODULE_ID,
    357         name: "Android Emulator hwcomposer module",
    358         author: "The Android Open Source Project",
    359         methods: &hwc_module_methods,
    360     }
    361 };
    362