diff options
Diffstat (limited to 'libhwcomposer/display.cpp')
-rw-r--r-- | libhwcomposer/display.cpp | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/libhwcomposer/display.cpp b/libhwcomposer/display.cpp new file mode 100644 index 0000000..f881a84 --- /dev/null +++ b/libhwcomposer/display.cpp @@ -0,0 +1,273 @@ +/* + * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/ + * + * 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 <algorithm> + +#include <cstdint> + +#include <cutils/log.h> +#include <cutils/properties.h> + +#include "display.h" +#include "format.h" +#include "hwc_dev.h" + +HWCDisplay::HWCDisplay(enum disp_role role) : + active_config(0), + role(role), + cb_procs(NULL), + is_dummy(false), + vsync_on(false), + blanked(true), + is_flip_pending(false) +{ +} + +void HWCDisplay::setup_composition_pipes() +{ + std::unique_lock<std::mutex> lock(this->mutex); + + KMSDisplay* kdisp = &this->disp_link; + + int count = 0; + for (auto plane : kdisp->card->get_planes()) { + auto possible_crtcs = plane->get_possible_crtcs(); + if (std::find(possible_crtcs.begin(), possible_crtcs.end(), kdisp->crtc) != possible_crtcs.end()) { + planeProps[count].plane = plane; + ALOGI("Overlay %d: plane_id: %d", count, planeProps[count].plane->id()); + count++; + } + } +} + +/* Page flip handler callback */ +void HWCDisplay::page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data) +{ + HWCDisplay* display = static_cast<HWCDisplay*>(data); + + std::unique_lock<std::mutex> lock(display->mutex); + + if (display->is_flip_pending == false) { + ALOGW("Spurious page flip?"); + return; + } + + /* release the old buffers */ + for (auto current_fb_info : display->current_fb_infos) + delete current_fb_info; + display->current_fb_infos.clear(); + + /* pending are now current */ + for (auto pending_fb_info : display->pending_fb_infos) + display->current_fb_infos.push_back(pending_fb_info); + display->pending_fb_infos.clear(); + + display->is_flip_pending = false; + lock.unlock(); + display->cond_flip.notify_one(); +} + +static int vblank_kick(HWCDisplay* display) +{ + drmVBlank vblank; + memset(&vblank, 0, sizeof(vblank)); + vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT | + display->role == DISP_ROLE_SECONDARY ? DRM_VBLANK_SECONDARY : 0); + vblank.request.sequence = 1; + vblank.request.signal = (unsigned long)display; + int err = drmWaitVBlank(display->disp_link.card->fd(), &vblank); + if (err < 0) { + /* FIXME: error in drmWaitVBlank() use SW vsync instead? */ + ALOGE("drmWaitVBlank error %d (%s)", err, strerror(errno)); + return -1; + } + + return 0; +} + +/* Callback function that gets triggered on vsync */ +void HWCDisplay::vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data) +{ + HWCDisplay* display = static_cast<HWCDisplay*>(data); + + std::unique_lock<std::mutex> lock(display->mutex); + + if (display->vsync_on) { + int64_t ts = sec * (int64_t)1000000000 + usec * (int64_t)1000; + +// ALOGD("Sending VBLANK at %lld for display %d", ts, display->role); + display->cb_procs->vsync(display->cb_procs, display->role, ts); + + vblank_kick(display); + } +} + +int HWCDisplay::set_vsync_state(bool state) +{ + std::unique_lock<std::mutex> lock(this->mutex); + + if (this->is_dummy) + return 0; + + this->vsync_on = state; + + if (this->vsync_on) + return vblank_kick(this); + + return 0; +} + +static void set_plane_properties(kms::AtomicReq& req, drm_plane_props_t* plane_props) +{ + kms::Plane* plane = plane_props->plane; + + req.add(plane, "FB_ID", plane_props->fb_info->fb_id); + + req.add(plane, "IN_FENCE_FD", plane_props->layer->acquireFenceFd); + + req.add(plane, { + { "CRTC_ID", plane_props->crtc_id }, + { "SRC_X", (plane_props->src_x) << 16 }, + { "SRC_Y", (plane_props->src_y) << 16 }, + { "SRC_W", (plane_props->src_w) << 16 }, + { "SRC_H", (plane_props->src_h) << 16 }, + { "CRTC_X", plane_props->crtc_x }, + { "CRTC_Y", plane_props->crtc_y }, + { "CRTC_W", plane_props->crtc_w }, + { "CRTC_H", plane_props->crtc_h }, + }); + + /* optional props */ + req.add(plane, { + { "zorder", plane_props->zorder }, + { "pre_mult_alpha", plane_props->pre_mult_alpha }, + }); +} + +int HWCDisplay::update_display(drm_plane_props_t* planeProp) +{ + std::unique_lock<std::mutex> lock(this->mutex); + + this->cond_flip.wait(lock, [this]{return !this->is_flip_pending;}); + + buffer_handle_t handle = planeProp->layer->handle; + if (!handle) { + ALOGW("Got empty handle, nothing to display"); + return 0; + } + + KMSDisplay* kdisp = &this->disp_link; + + planeProp->fb_info = new DRMFramebuffer(kdisp->card->fd(), handle, false); + this->pending_fb_infos.push_back(planeProp->fb_info); + + planeProp->crtc_id = kdisp->crtc->id(); + + // Atomic display update + kms::AtomicReq req(*kdisp->card); + set_plane_properties(req, planeProp); + int ret = req.commit(this, true); + if (ret) { + ALOGE("cannot do atomic commit/page flip: %d (%s)", ret, strerror(errno)); + for (auto pending_fb_info : this->pending_fb_infos) + delete pending_fb_info; + this->pending_fb_infos.clear(); + return ret; + } + +// ALOGD("Scheduled page flip on display %d", this->role); + this->is_flip_pending = true; + + return 0; +} + +void HWCDisplay::blank(int blank) +{ + std::unique_lock<std::mutex> lock(this->mutex); + + if (this->is_dummy) + return; + + KMSDisplay* kdisp = &this->disp_link; + + ALOGI("Linking connector %d to crtc %d", kdisp->con->id(), kdisp->crtc->id()); + + int ret = kdisp->crtc->set_mode(kdisp->con, kdisp->mode); + if (ret) { + ALOGE("Failed to set crtc mode (%s)", strerror(-ret)); + return; + } + + // FIXME: This should actually blank the screen + this->blanked = blank; +} + +int HWCDisplay::get_display_configs(uint32_t* configs, size_t* numConfigs) +{ + if (!configs || !numConfigs) + return -EINVAL; + + if (*numConfigs == 0) + return 0; + + std::unique_lock<std::mutex> lock(this->mutex); + + size_t num = this->configs.size(); + if (num > *numConfigs) + num = *numConfigs; + + for (size_t i = 0; i < num; i++) + configs[i] = i; + + *numConfigs = num; + + return 0; +} + +int HWCDisplay::get_display_attributes(uint32_t cfg, const uint32_t* attributes, int32_t* values) +{ + if (!attributes || !values) + return 0; + + std::unique_lock<std::mutex> lock(this->mutex); + + if (cfg >= this->configs.size()) + return -EINVAL; + + display_config_t* config = &this->configs[cfg]; + + for (size_t i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) { + switch (attributes[i]) { + case HWC_DISPLAY_VSYNC_PERIOD: + values[i] = 1000000000 / config->fps; + break; + case HWC_DISPLAY_WIDTH: + values[i] = config->xres; + break; + case HWC_DISPLAY_HEIGHT: + values[i] = config->yres; + break; + case HWC_DISPLAY_DPI_X: + values[i] = 1000 * config->xdpi; + break; + case HWC_DISPLAY_DPI_Y: + values[i] = 1000 * config->ydpi; + break; + } + } + + return 0; +} |