1 /* 2 * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/ 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 17 #include <algorithm> 18 19 #include <cstdint> 20 21 #include <log/log.h> 22 #include <cutils/properties.h> 23 24 #include "display.h" 25 #include "format.h" 26 #include "hwc_dev.h" 27 28 HWCDisplay::HWCDisplay(enum disp_role role) : 29 active_config(0), 30 role(role), 31 cb_procs(NULL), 32 is_dummy(false), 33 vsync_on(false), 34 blanked(true), 35 is_flip_pending(false) 36 { 37 } 38 39 void HWCDisplay::setup_composition_pipes() 40 { 41 std::unique_lock<std::mutex> lock(this->mutex); 42 43 KMSDisplay* kdisp = &this->disp_link; 44 45 int count = 0; 46 for (auto plane : kdisp->card->get_planes()) { 47 auto possible_crtcs = plane->get_possible_crtcs(); 48 if (std::find(possible_crtcs.begin(), possible_crtcs.end(), kdisp->crtc) != possible_crtcs.end()) { 49 planeProps[count].plane = plane; 50 ALOGI("Overlay %d: plane_id: %d", count, planeProps[count].plane->id()); 51 count++; 52 } 53 } 54 } 55 56 /* Page flip handler callback */ 57 void HWCDisplay::page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data) 58 { 59 HWCDisplay* display = static_cast<HWCDisplay*>(data); 60 61 std::unique_lock<std::mutex> lock(display->mutex); 62 63 if (display->is_flip_pending == false) { 64 ALOGW("Spurious page flip?"); 65 return; 66 } 67 68 /* release the old buffers */ 69 for (auto current_fb_info : display->current_fb_infos) 70 delete current_fb_info; 71 display->current_fb_infos.clear(); 72 73 /* pending are now current */ 74 for (auto pending_fb_info : display->pending_fb_infos) 75 display->current_fb_infos.push_back(pending_fb_info); 76 display->pending_fb_infos.clear(); 77 78 display->is_flip_pending = false; 79 lock.unlock(); 80 display->cond_flip.notify_one(); 81 } 82 83 static int vblank_kick(HWCDisplay* display) 84 { 85 drmVBlank vblank; 86 memset(&vblank, 0, sizeof(vblank)); 87 vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT | 88 display->role == DISP_ROLE_SECONDARY ? DRM_VBLANK_SECONDARY : 0); 89 vblank.request.sequence = 1; 90 vblank.request.signal = (unsigned long)display; 91 int err = drmWaitVBlank(display->disp_link.card->fd(), &vblank); 92 if (err < 0) { 93 /* FIXME: error in drmWaitVBlank() use SW vsync instead? */ 94 ALOGE("drmWaitVBlank error %d (%s)", err, strerror(errno)); 95 return -1; 96 } 97 98 return 0; 99 } 100 101 /* Callback function that gets triggered on vsync */ 102 void HWCDisplay::vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data) 103 { 104 HWCDisplay* display = static_cast<HWCDisplay*>(data); 105 106 std::unique_lock<std::mutex> lock(display->mutex); 107 108 if (display->vsync_on) { 109 int64_t ts = sec * (int64_t)1000000000 + usec * (int64_t)1000; 110 111 // ALOGD("Sending VBLANK at %lld for display %d", ts, display->role); 112 display->cb_procs->vsync(display->cb_procs, display->role, ts); 113 114 vblank_kick(display); 115 } 116 } 117 118 int HWCDisplay::set_vsync_state(bool state) 119 { 120 std::unique_lock<std::mutex> lock(this->mutex); 121 122 if (this->is_dummy) 123 return 0; 124 125 this->vsync_on = state; 126 127 if (this->vsync_on) 128 return vblank_kick(this); 129 130 return 0; 131 } 132 133 static void set_plane_properties(kms::AtomicReq& req, drm_plane_props_t* plane_props) 134 { 135 kms::Plane* plane = plane_props->plane; 136 137 req.add(plane, "FB_ID", plane_props->fb_info->fb_id); 138 139 req.add(plane, "IN_FENCE_FD", plane_props->layer->acquireFenceFd); 140 141 req.add(plane, { 142 { "CRTC_ID", plane_props->crtc_id }, 143 { "SRC_X", (plane_props->src_x) << 16 }, 144 { "SRC_Y", (plane_props->src_y) << 16 }, 145 { "SRC_W", (plane_props->src_w) << 16 }, 146 { "SRC_H", (plane_props->src_h) << 16 }, 147 { "CRTC_X", plane_props->crtc_x }, 148 { "CRTC_Y", plane_props->crtc_y }, 149 { "CRTC_W", plane_props->crtc_w }, 150 { "CRTC_H", plane_props->crtc_h }, 151 }); 152 153 /* optional props */ 154 req.add(plane, { 155 { "zorder", plane_props->zorder }, 156 { "pre_mult_alpha", plane_props->pre_mult_alpha }, 157 }); 158 } 159 160 int HWCDisplay::update_display(drm_plane_props_t* planeProp) 161 { 162 std::unique_lock<std::mutex> lock(this->mutex); 163 164 this->cond_flip.wait(lock, [this]{return !this->is_flip_pending;}); 165 166 buffer_handle_t handle = planeProp->layer->handle; 167 if (!handle) { 168 ALOGW("Got empty handle, nothing to display"); 169 return 0; 170 } 171 172 KMSDisplay* kdisp = &this->disp_link; 173 174 planeProp->fb_info = new DRMFramebuffer(kdisp->card->fd(), handle, false); 175 this->pending_fb_infos.push_back(planeProp->fb_info); 176 177 planeProp->crtc_id = kdisp->crtc->id(); 178 179 // Atomic display update 180 kms::AtomicReq req(*kdisp->card); 181 set_plane_properties(req, planeProp); 182 int ret = req.commit(this, true); 183 if (ret) { 184 ALOGE("cannot do atomic commit/page flip: %d (%s)", ret, strerror(errno)); 185 for (auto pending_fb_info : this->pending_fb_infos) 186 delete pending_fb_info; 187 this->pending_fb_infos.clear(); 188 return ret; 189 } 190 191 // ALOGD("Scheduled page flip on display %d", this->role); 192 this->is_flip_pending = true; 193 194 return 0; 195 } 196 197 void HWCDisplay::blank(int blank) 198 { 199 std::unique_lock<std::mutex> lock(this->mutex); 200 201 if (this->is_dummy) 202 return; 203 204 KMSDisplay* kdisp = &this->disp_link; 205 206 ALOGI("Linking connector %d to crtc %d", kdisp->con->id(), kdisp->crtc->id()); 207 208 int ret = kdisp->crtc->set_mode(kdisp->con, kdisp->mode); 209 if (ret) { 210 ALOGE("Failed to set crtc mode (%s)", strerror(-ret)); 211 return; 212 } 213 214 // FIXME: This should actually blank the screen 215 this->blanked = blank; 216 } 217 218 int HWCDisplay::get_display_configs(uint32_t* configs, size_t* numConfigs) 219 { 220 if (!configs || !numConfigs) 221 return -EINVAL; 222 223 if (*numConfigs == 0) 224 return 0; 225 226 std::unique_lock<std::mutex> lock(this->mutex); 227 228 size_t num = this->configs.size(); 229 if (num > *numConfigs) 230 num = *numConfigs; 231 232 for (size_t i = 0; i < num; i++) 233 configs[i] = i; 234 235 *numConfigs = num; 236 237 return 0; 238 } 239 240 int HWCDisplay::get_display_attributes(uint32_t cfg, const uint32_t* attributes, int32_t* values) 241 { 242 if (!attributes || !values) 243 return 0; 244 245 std::unique_lock<std::mutex> lock(this->mutex); 246 247 if (cfg >= this->configs.size()) 248 return -EINVAL; 249 250 display_config_t* config = &this->configs[cfg]; 251 252 for (size_t i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) { 253 switch (attributes[i]) { 254 case HWC_DISPLAY_VSYNC_PERIOD: 255 values[i] = 1000000000 / config->fps; 256 break; 257 case HWC_DISPLAY_WIDTH: 258 values[i] = config->xres; 259 break; 260 case HWC_DISPLAY_HEIGHT: 261 values[i] = config->yres; 262 break; 263 case HWC_DISPLAY_DPI_X: 264 values[i] = 1000 * config->xdpi; 265 break; 266 case HWC_DISPLAY_DPI_Y: 267 values[i] = 1000 * config->ydpi; 268 break; 269 } 270 } 271 272 return 0; 273 } 274