• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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
set_preview(bool flag)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>
instance()52 DrmDisplay::instance ()
53 {
54     SmartLock lock(_mutex);
55     if (_instance.ptr())
56         return _instance;
57     _instance = new DrmDisplay ();
58     return _instance;
59 }
60 
DrmDisplay(const char * module)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 
~DrmDisplay()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
open_drivers(const char * base_path,int base_id)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
open_driver(const char * dev_path)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
is_authenticated(int fd,const char * msg)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
to_drm_fourcc(uint32_t fourcc_of_v4l2)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
get_crtc(drmModeRes * res)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
get_connector(drmModeRes * res)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
get_plane()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
render_init(uint32_t con_id,uint32_t crtc_id,uint32_t width,uint32_t height,uint32_t format,const struct v4l2_rect * compose)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>
create_drm_buf(const struct v4l2_format & format,const uint32_t index,const enum v4l2_buf_type buf_type)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
render_setup_frame_buffer(SmartPtr<VideoBuffer> & buf)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
set_crtc(const FB & fb)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
set_plane(const FB & fb)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
page_flip(const FB & fb)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
render_buffer(SmartPtr<VideoBuffer> & buf)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>
convert_to_drm_bo_buf(SmartPtr<DrmDisplay> & self,SmartPtr<VideoBuffer> & buf_in)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>
create_drm_bo(SmartPtr<DrmDisplay> & self,const VideoBufferInfo & info)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 *
create_drm_bo_from_fd(int32_t fd,uint32_t size)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