1 /* 2 * drm_display.cpp - drm display 3 * 4 * Copyright (c) 2015 Intel Corporation 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * Author: John Ye <john.ye (at) intel.com> 19 */ 20 21 22 #include "drm_display.h" 23 #include "drm_v4l2_buffer.h" 24 #include "drm_bo_buffer.h" 25 #include <drm_fourcc.h> 26 #include <sys/ioctl.h> 27 #include <fcntl.h> 28 29 30 #define DEFAULT_DRM_DEVICE "i915" 31 #define DEFAULT_DRM_BUSID "PCI:00:02:00" 32 #define DEFAULT_DRM_BATCH_SIZE 0x80000 33 34 namespace XCam { 35 36 SmartPtr<DrmDisplay> DrmDisplay::_instance(NULL); 37 Mutex DrmDisplay::_mutex; 38 39 static std::atomic<uint32_t> global_signal_index(0); 40 41 bool DrmDisplay::_preview_flag = false; 42 43 bool 44 DrmDisplay::set_preview (bool flag) { 45 if (_instance.ptr () && flag != _preview_flag) 46 return false; 47 _preview_flag = flag; 48 return true; 49 }; 50 51 SmartPtr<DrmDisplay> 52 DrmDisplay::instance () 53 { 54 SmartLock lock(_mutex); 55 if (_instance.ptr()) 56 return _instance; 57 _instance = new DrmDisplay (); 58 return _instance; 59 } 60 61 DrmDisplay::DrmDisplay (const char *module) 62 : _module(NULL) 63 , _fd (-1) 64 , _buf_manager (NULL) 65 , _display_mode (DRM_DISPLAY_MODE_NONE) 66 , _crtc_index (-1) 67 , _crtc_id (0) 68 , _con_id (0) 69 , _encoder_id (0) 70 , _plane_id (0) 71 , _connector (NULL) 72 , _is_render_inited (false) 73 , _format (0) 74 , _width (0) 75 , _height (0) 76 { 77 xcam_mem_clear(_compose); 78 79 if (module) 80 _module = strndup (module, XCAM_MAX_STR_SIZE); 81 else 82 _module = strndup (DEFAULT_DRM_DEVICE, XCAM_MAX_STR_SIZE); 83 84 if (!_preview_flag) { 85 _fd = open_drivers ("/dev/dri/renderD", 128); 86 } 87 88 if (_fd < 0) 89 _fd = open_drivers ("/dev/dri/card", 0); 90 91 if (_fd < 0) { 92 _fd = drmOpen (_module, DEFAULT_DRM_BUSID); 93 if (_fd >= 0 && !is_authenticated (_fd, DEFAULT_DRM_BUSID)) { 94 drmClose (_fd); 95 _fd = -1; 96 } 97 } 98 99 if (_fd < 0) { 100 XCAM_LOG_WARNING ("please try root privilege if without X server"); 101 XCAM_LOG_ERROR ("failed to open drm device %s", XCAM_STR (_module)); 102 } 103 104 _buf_manager = drm_intel_bufmgr_gem_init (_fd, DEFAULT_DRM_BATCH_SIZE); 105 drm_intel_bufmgr_gem_enable_reuse (_buf_manager); 106 } 107 108 DrmDisplay::~DrmDisplay() 109 { 110 _display_buf.release (); 111 112 if (_buf_manager) 113 drm_intel_bufmgr_destroy (_buf_manager); 114 if (_fd >= 0) 115 drmClose (_fd); 116 if (_module) 117 xcam_free (_module); 118 }; 119 120 int 121 DrmDisplay::open_drivers (const char *base_path, int base_id) 122 { 123 int fd = -1; 124 char dev_path [32]; 125 XCAM_ASSERT (base_path); 126 127 for (int i = 0; i < 16; i++) { 128 sprintf (dev_path, "%s%d", base_path, base_id + i); 129 if (access (dev_path, F_OK) != 0) 130 continue; 131 132 fd = open_driver (dev_path); 133 if (fd >= 0) 134 break; 135 } 136 137 return fd; 138 } 139 140 int 141 DrmDisplay::open_driver (const char *dev_path) 142 { 143 XCAM_ASSERT (dev_path); 144 145 int fd = open (dev_path, O_RDWR); 146 if (fd < 0) { 147 XCAM_LOG_ERROR ("failed to open %s", dev_path); 148 return -1; 149 } 150 151 if (!strncmp (dev_path, "/dev/dri/card", 13)) { 152 if (!is_authenticated (fd, dev_path)) { 153 close (fd); 154 return -1; 155 } 156 } 157 158 return fd; 159 } 160 161 bool 162 DrmDisplay::is_authenticated (int fd, const char *msg) 163 { 164 drm_client_t client; 165 memset (&client, 0, sizeof (drm_client_t)); 166 if (ioctl (fd, DRM_IOCTL_GET_CLIENT, &client) == -1) { 167 XCAM_LOG_ERROR ("failed to get drm client"); 168 return false; 169 } 170 171 if (!client.auth) { 172 XCAM_LOG_ERROR ("%s is not authenticated", msg); 173 return false; 174 } 175 176 return true; 177 } 178 179 uint32_t 180 DrmDisplay::to_drm_fourcc (uint32_t fourcc_of_v4l2) 181 { 182 switch (fourcc_of_v4l2) { 183 case V4L2_PIX_FMT_RGB565: 184 return DRM_FORMAT_RGB565; 185 default: 186 break; 187 } 188 return fourcc_of_v4l2; 189 } 190 191 XCamReturn 192 DrmDisplay::get_crtc(drmModeRes *res) 193 { 194 _crtc_index = -1; 195 196 drmModeEncoderPtr encoder = drmModeGetEncoder(_fd, _encoder_id); 197 XCAM_FAIL_RETURN(ERROR, encoder, XCAM_RETURN_ERROR_PARAM, 198 "drmModeGetEncoder failed: %s", strerror(errno)); 199 200 _crtc_id = encoder->crtc_id; 201 drmModeFreeEncoder(encoder); 202 203 for (int i = 0; i < res->count_crtcs; i++) { 204 if (_crtc_id == res->crtcs[i]) { 205 _crtc_index = i; 206 break; 207 } 208 } 209 XCAM_FAIL_RETURN(ERROR, _crtc_index != -1, XCAM_RETURN_ERROR_PARAM, 210 "CRTC %d not found", _crtc_id); 211 212 return XCAM_RETURN_NO_ERROR; 213 } 214 215 XCamReturn 216 DrmDisplay::get_connector(drmModeRes *res) 217 { 218 XCAM_FAIL_RETURN(ERROR, res->count_connectors > 0, XCAM_RETURN_ERROR_PARAM, 219 "No connector found"); 220 for(int i = 0; i < res->count_connectors; ++i) { 221 _connector = drmModeGetConnector(_fd, res->connectors[i]); 222 if(_connector && _connector->connection == DRM_MODE_CONNECTED) { 223 _con_id = res->connectors[i]; 224 _encoder_id = res->encoders[i]; 225 _mode = *_connector->modes; 226 } 227 drmModeFreeConnector(_connector); 228 } 229 XCAM_FAIL_RETURN(ERROR, _connector, XCAM_RETURN_ERROR_PARAM, 230 "drmModeGetConnector failed: %s", strerror(errno)); 231 232 return XCAM_RETURN_NO_ERROR; 233 } 234 235 236 XCamReturn 237 DrmDisplay::get_plane() 238 { 239 drmModePlaneResPtr planes = drmModeGetPlaneResources(_fd); 240 XCAM_FAIL_RETURN(ERROR, planes, XCAM_RETURN_ERROR_PARAM, 241 "failed to query planes: %s", strerror(errno)); 242 243 drmModePlanePtr plane = NULL; 244 for (uint32_t i = 0; i < planes->count_planes; i++) { 245 if (plane) { 246 drmModeFreePlane(plane); 247 plane = NULL; 248 } 249 plane = drmModeGetPlane(_fd, planes->planes[i]); 250 XCAM_FAIL_RETURN(ERROR, plane, XCAM_RETURN_ERROR_PARAM, 251 "failed to query plane %d: %s", i, strerror(errno)); 252 253 if (plane->crtc_id || !(plane->possible_crtcs & (1 << _crtc_index))) { 254 continue; 255 } 256 257 for (uint32_t j = 0; j < plane->count_formats; j++) { 258 // found a plane matching the requested format 259 if (plane->formats[j] == _format) { 260 _plane_id = plane->plane_id; 261 drmModeFreePlane(plane); 262 drmModeFreePlaneResources(planes); 263 return XCAM_RETURN_NO_ERROR; 264 } 265 } 266 } 267 268 if (plane) 269 drmModeFreePlane(plane); 270 271 drmModeFreePlaneResources(planes); 272 273 return XCAM_RETURN_ERROR_PARAM; 274 } 275 276 XCamReturn 277 DrmDisplay::render_init ( 278 uint32_t con_id, 279 uint32_t crtc_id, 280 uint32_t width, 281 uint32_t height, 282 uint32_t format, 283 const struct v4l2_rect* compose) 284 { 285 XCamReturn ret = XCAM_RETURN_NO_ERROR; 286 287 if (is_render_inited ()) 288 return ret; 289 290 _con_id = con_id; 291 _crtc_id = crtc_id; 292 _width = width; 293 _height = height; 294 _format = to_drm_fourcc (format); 295 _compose = *compose; 296 _crtc_index = -1; 297 _plane_id = 0; 298 _connector = NULL; 299 300 drmModeRes *resource = drmModeGetResources(_fd); 301 XCAM_FAIL_RETURN(ERROR, resource, XCAM_RETURN_ERROR_PARAM, 302 "failed to query Drm Mode resources: %s", strerror(errno)); 303 304 ret = get_connector(resource); 305 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, 306 XCAM_RETURN_ERROR_PARAM, 307 "failed to get connector %s", strerror(errno)); 308 309 ret = get_crtc(resource); 310 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, 311 XCAM_RETURN_ERROR_PARAM, 312 "failed to get CRTC %s", strerror(errno)); 313 314 ret = get_plane(); 315 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, 316 XCAM_RETURN_ERROR_PARAM, 317 "failed to get plane with required format %s", strerror(errno)); 318 319 drmModeFreeResources(resource); 320 if (_display_mode == DRM_DISPLAY_MODE_OVERLAY) 321 _is_render_inited = true; 322 return XCAM_RETURN_NO_ERROR; 323 } 324 325 326 SmartPtr<V4l2Buffer> 327 DrmDisplay::create_drm_buf ( 328 const struct v4l2_format &format, 329 const uint32_t index, 330 const enum v4l2_buf_type buf_type) 331 { 332 struct drm_mode_create_dumb gem; 333 struct drm_prime_handle prime; 334 struct v4l2_buffer v4l2_buf; 335 int ret = 0; 336 337 xcam_mem_clear (gem); 338 xcam_mem_clear (prime); 339 xcam_mem_clear (v4l2_buf); 340 341 gem.width = format.fmt.pix.bytesperline; 342 gem.height = format.fmt.pix.height; 343 gem.bpp = 8; 344 ret = xcam_device_ioctl (_fd, DRM_IOCTL_MODE_CREATE_DUMB, &gem); 345 XCAM_ASSERT (ret >= 0); 346 347 prime.handle = gem.handle; 348 ret = xcam_device_ioctl (_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime); 349 if (ret < 0) { 350 XCAM_LOG_WARNING ("create drm failed on DRM_IOCTL_PRIME_HANDLE_TO_FD"); 351 return NULL; 352 } 353 354 v4l2_buf.index = index; 355 v4l2_buf.type = buf_type; 356 v4l2_buf.memory = V4L2_MEMORY_DMABUF; 357 v4l2_buf.m.fd = prime.fd; 358 v4l2_buf.length = XCAM_MAX (format.fmt.pix.sizeimage, gem.size); // todo check gem.size and format.fmt.pix.length 359 XCAM_LOG_DEBUG ("create drm buffer size:%lld", gem.size); 360 return new DrmV4l2Buffer (gem.handle, v4l2_buf, format, _instance); 361 } 362 363 XCamReturn 364 DrmDisplay::render_setup_frame_buffer (SmartPtr<VideoBuffer> &buf) 365 { 366 XCamReturn ret = XCAM_RETURN_NO_ERROR; 367 VideoBufferInfo video_info = buf->get_video_info (); 368 uint32_t fourcc = video_info.format; 369 uint32_t fb_handle = 0; 370 uint32_t bo_handle = 0; 371 uint32_t bo_handles[4] = { 0 }; 372 FB fb; 373 SmartPtr<V4l2BufferProxy> v4l2_proxy; 374 SmartPtr<DrmBoBuffer> bo_buf; 375 376 v4l2_proxy = buf.dynamic_cast_ptr<V4l2BufferProxy> (); 377 bo_buf = buf.dynamic_cast_ptr<DrmBoBuffer> (); 378 if (v4l2_proxy.ptr ()) { 379 struct drm_prime_handle prime; 380 memset(&prime, 0, sizeof (prime)); 381 prime.fd = v4l2_proxy->get_v4l2_dma_fd(); 382 383 ret = (XCamReturn) xcam_device_ioctl(_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime); 384 if (ret) { 385 XCAM_LOG_WARNING("FD_TO_PRIME_HANDLE failed: %s", strerror(errno)); 386 return XCAM_RETURN_ERROR_IOCTL; 387 } 388 bo_handle = prime.handle; 389 } else if (bo_buf.ptr ()) { 390 const drm_intel_bo* bo = bo_buf->get_bo (); 391 XCAM_ASSERT (bo); 392 bo_handle = bo->handle; 393 } else { 394 XCAM_ASSERT (false); 395 XCAM_LOG_WARNING("drm setup framebuffer doesn't support this buffer"); 396 return XCAM_RETURN_ERROR_PARAM; 397 } 398 399 for (uint32_t i = 0; i < 4; ++i) { 400 bo_handles [i] = bo_handle; 401 } 402 403 ret = (XCamReturn) drmModeAddFB2(_fd, video_info.width, video_info.height, fourcc, bo_handles, 404 video_info.strides, video_info.offsets, &fb_handle, 0); 405 406 fb.fb_handle = fb_handle; 407 fb.index = global_signal_index++; 408 _buf_fb_handles[buf.ptr ()] = fb; 409 410 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, XCAM_RETURN_ERROR_PARAM, 411 "drmModeAddFB2 failed: %s", strerror(errno)); 412 413 return ret; 414 } 415 416 XCamReturn 417 DrmDisplay::set_crtc (const FB &fb) 418 { 419 XCamReturn ret = XCAM_RETURN_NO_ERROR; 420 uint32_t fb_handle = fb.fb_handle; 421 //uint32_t index = fb.index; 422 423 if( !_is_render_inited) { 424 ret = (XCamReturn) drmModeSetCrtc(_fd, _crtc_id, fb_handle, 0, 425 0, &_con_id, 1, &_mode); 426 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, XCAM_RETURN_ERROR_IOCTL, 427 "failed to set crct via drm: %s", strerror(errno)); 428 _is_render_inited = true; 429 } 430 return ret; 431 } 432 433 XCamReturn 434 DrmDisplay::set_plane (const FB &fb) 435 { 436 XCamReturn ret = XCAM_RETURN_NO_ERROR; 437 uint32_t fb_handle = fb.fb_handle; 438 //uint32_t index = fb.index; 439 440 ret = (XCamReturn) drmModeSetPlane(_fd, _plane_id, _crtc_id, 441 fb_handle, 0, 442 _compose.left, _compose.top, 443 _compose.width, _compose.height, 444 0, 0, _width << 16, _height << 16); 445 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, XCAM_RETURN_ERROR_IOCTL, 446 "failed to set plane via drm: %s", strerror(errno)); 447 #if 0 448 drmVBlank vblank; 449 vblank.request.type = (drmVBlankSeqType) (DRM_VBLANK_EVENT | DRM_VBLANK_RELATIVE); 450 vblank.request.sequence = 1; 451 vblank.request.signal = (unsigned long) index; 452 ret = (XCamReturn) drmWaitVBlank(_fd, &vblank); 453 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, XCAM_RETURN_ERROR_IOCTL, 454 "failed to wait vblank: %s", strerror(errno)); 455 #endif 456 return XCAM_RETURN_NO_ERROR; 457 } 458 459 XCamReturn 460 DrmDisplay::page_flip (const FB &fb) 461 { 462 XCamReturn ret; 463 uint32_t fb_handle = fb.fb_handle; 464 uint32_t index = fb.index; 465 466 ret = (XCamReturn) drmModePageFlip(_fd, _crtc_id, fb_handle, 467 DRM_MODE_PAGE_FLIP_EVENT, 468 (void*)(unsigned long) index); 469 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, XCAM_RETURN_ERROR_IOCTL, 470 "failed on page flip: %s", strerror(errno)); 471 472 drmEventContext evctx; 473 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; 474 fd_set fds; 475 memset(&evctx, 0, sizeof evctx); 476 evctx.version = DRM_EVENT_CONTEXT_VERSION; 477 evctx.vblank_handler = NULL; 478 //evctx.page_flip_handler = page_flip_handler; 479 FD_ZERO(&fds); 480 FD_SET(_fd, &fds); 481 select(_fd + 1, &fds, NULL, NULL, &timeout); 482 drmHandleEvent(_fd, &evctx); 483 484 return XCAM_RETURN_NO_ERROR; 485 } 486 487 XCamReturn 488 DrmDisplay::render_buffer(SmartPtr<VideoBuffer> &buf) 489 { 490 XCamReturn ret = XCAM_RETURN_NO_ERROR; 491 FBMap::iterator iter = _buf_fb_handles.find (buf.ptr ()); 492 XCAM_FAIL_RETURN( 493 ERROR, 494 iter != _buf_fb_handles.end (), 495 XCAM_RETURN_ERROR_PARAM, 496 "buffer not register on framebuf"); 497 if(_display_mode == DRM_DISPLAY_MODE_OVERLAY) 498 ret = _plane_id ? set_plane(iter->second) : page_flip(iter->second); 499 else if(_display_mode == DRM_DISPLAY_MODE_PRIMARY) { 500 ret = set_crtc (iter->second); 501 ret = page_flip (iter->second); 502 } 503 _display_buf = buf; 504 505 return ret; 506 } 507 508 SmartPtr<DrmBoBuffer> 509 DrmDisplay::convert_to_drm_bo_buf (SmartPtr<DrmDisplay> &self, SmartPtr<VideoBuffer> &buf_in) 510 { 511 drm_intel_bo *bo = NULL; 512 int dma_fd = 0; 513 SmartPtr<DrmBoBuffer> new_bo_buf; 514 SmartPtr<DrmBoData> bo_data; 515 516 XCAM_ASSERT (self.ptr () == this); 517 XCAM_ASSERT (buf_in.ptr ()); 518 519 new_bo_buf = buf_in.dynamic_cast_ptr<DrmBoBuffer> (); 520 if (new_bo_buf.ptr ()) 521 return new_bo_buf; 522 523 const VideoBufferInfo video_info = buf_in->get_video_info (); 524 dma_fd = buf_in->get_fd (); 525 if (dma_fd < 0) { 526 XCAM_LOG_DEBUG ("DrmDisplay only support dma buffer conversion to drm bo by now"); 527 return NULL; 528 } 529 530 bo = drm_intel_bo_gem_create_from_prime (_buf_manager, dma_fd, video_info.size); 531 if (bo == NULL) { 532 XCAM_LOG_WARNING ("convert dma fd to drm bo failed"); 533 return NULL; 534 } 535 bo_data = new DrmBoData (self, bo); 536 bo_data->set_prime_fd (dma_fd, false); 537 new_bo_buf = new DrmBoBuffer (video_info, bo_data); 538 new_bo_buf->set_parent (buf_in); 539 new_bo_buf->set_timestamp (buf_in->get_timestamp ()); 540 return new_bo_buf; 541 } 542 543 SmartPtr<DrmBoData> 544 DrmDisplay::create_drm_bo (SmartPtr<DrmDisplay> &self, const VideoBufferInfo &info) 545 { 546 SmartPtr<DrmBoData> new_bo; 547 548 XCAM_ASSERT (_buf_manager); 549 XCAM_ASSERT (self.ptr() == this); 550 drm_intel_bo *bo = drm_intel_bo_alloc ( 551 _buf_manager, "xcam drm bo buf", info.size, 0x1000); 552 553 new_bo = new DrmBoData (self, bo); 554 return new_bo; 555 } 556 557 drm_intel_bo * 558 DrmDisplay::create_drm_bo_from_fd (int32_t fd, uint32_t size) 559 { 560 drm_intel_bo *bo = NULL; 561 XCAM_ASSERT (_buf_manager); 562 bo = drm_intel_bo_gem_create_from_prime (_buf_manager, fd, size); 563 564 XCAM_ASSERT (bo); 565 return bo; 566 } 567 568 569 }; 570