blob: 536963e9792ef21a9361b383244e8128844502ee [file] [log] [blame]
John Ye1503c6b2015-01-22 13:26:33 +08001/*
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"
Wind Yuan25aed2b2015-02-10 17:46:23 +080024#include "drm_bo_buffer.h"
Wind Yuan95e5b362015-03-27 15:17:50 +080025#include <drm_fourcc.h>
John Ye1503c6b2015-01-22 13:26:33 +080026
27#define DEFAULT_DRM_DEVICE "i915"
Wind Yuan25aed2b2015-02-10 17:46:23 +080028#define DEFAULT_DRM_BATCH_SIZE 0x80000
John Ye1503c6b2015-01-22 13:26:33 +080029
30namespace XCam {
31
32SmartPtr<DrmDisplay> DrmDisplay::_instance(NULL);
33Mutex DrmDisplay::_mutex;
34
Wind Yuan50f5e9e2015-03-26 16:57:13 +080035static std::atomic<uint32_t> global_signal_index(0);
36
John Ye1503c6b2015-01-22 13:26:33 +080037SmartPtr<DrmDisplay>
38DrmDisplay::instance()
39{
40 SmartLock lock(_mutex);
41 if (_instance.ptr())
42 return _instance;
43 _instance = new DrmDisplay;
44 return _instance;
45}
46
Wind Yuan50f5e9e2015-03-26 16:57:13 +080047DrmDisplay::DrmDisplay(const char* module)
John Ye1503c6b2015-01-22 13:26:33 +080048 : _module(NULL)
49 , _fd (-1)
Wind Yuan25aed2b2015-02-10 17:46:23 +080050 , _buf_manager (NULL)
John Ye1503c6b2015-01-22 13:26:33 +080051 , _crtc_index (-1)
52 , _crtc_id (0)
53 , _con_id (0)
54 , _plane_id (0)
Wind Yuan50f5e9e2015-03-26 16:57:13 +080055 , _connector (NULL)
56 , _is_render_inited (false)
John Yecef36802015-01-26 16:00:16 +080057 , _format (0)
58 , _width (0)
59 , _height (0)
John Ye1503c6b2015-01-22 13:26:33 +080060{
John Yecef36802015-01-26 16:00:16 +080061 xcam_mem_clear(&_compose);
62
Wind Yuan50f5e9e2015-03-26 16:57:13 +080063 if (module)
64 _module = strdup (module);
65 else
66 _module = strdup (DEFAULT_DRM_DEVICE);
67
Wind Yuan25aed2b2015-02-10 17:46:23 +080068 //_fd = drmOpenRender (128);
Wind Yuan50f5e9e2015-03-26 16:57:13 +080069 _fd = drmOpen (_module, NULL);
John Ye1503c6b2015-01-22 13:26:33 +080070 if (_fd < 0)
Wind Yuan50f5e9e2015-03-26 16:57:13 +080071 XCAM_LOG_ERROR("failed to open drm device %s", _module);
Wind Yuan25aed2b2015-02-10 17:46:23 +080072
73 _buf_manager = drm_intel_bufmgr_gem_init (_fd, DEFAULT_DRM_BATCH_SIZE);
74 drm_intel_bufmgr_gem_enable_reuse (_buf_manager);
John Ye1503c6b2015-01-22 13:26:33 +080075}
76
Wind Yuan25aed2b2015-02-10 17:46:23 +080077DrmDisplay::~DrmDisplay()
78{
79 if (_buf_manager)
80 drm_intel_bufmgr_destroy (_buf_manager);
81 if (_fd > 0)
82 drmClose(_fd);
Wind Yuan50f5e9e2015-03-26 16:57:13 +080083 if (_module)
84 xcam_free (_module);
Wind Yuan25aed2b2015-02-10 17:46:23 +080085};
86
Wind Yuan95e5b362015-03-27 15:17:50 +080087uint32_t
88DrmDisplay::to_drm_fourcc (uint32_t fourcc_of_v4l2)
89{
90 switch (fourcc_of_v4l2) {
91 case V4L2_PIX_FMT_RGB565:
92 return DRM_FORMAT_RGB565;
93 default:
94 break;
95 }
96 return fourcc_of_v4l2;
97}
98
John Ye1503c6b2015-01-22 13:26:33 +080099XCamReturn
100DrmDisplay::get_crtc(drmModeRes *res)
101{
102 _crtc_index = -1;
103
104 for (int i = 0; i < res->count_crtcs; i++) {
105 if (_crtc_id == res->crtcs[i]) {
106 _crtc_index = i;
107 break;
108 }
109 }
110 XCAM_FAIL_RETURN(ERROR, _crtc_index != -1, XCAM_RETURN_ERROR_PARAM,
111 "CRTC %d not found", _crtc_id);
112
113 return XCAM_RETURN_NO_ERROR;
114}
115
116XCamReturn
117DrmDisplay::get_connector(drmModeRes *res)
118{
119 XCAM_FAIL_RETURN(ERROR, res->count_connectors > 0, XCAM_RETURN_ERROR_PARAM,
120 "No connector found");
121 _connector = drmModeGetConnector(_fd, _con_id);
122 XCAM_FAIL_RETURN(ERROR, _connector, XCAM_RETURN_ERROR_PARAM,
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800123 "drmModeGetConnector failed: %s", strerror(errno));
Wind Yuan024e1f32015-03-30 16:27:41 +0800124 XCAM_FAIL_RETURN(ERROR, _connector->connection == DRM_MODE_CONNECTED,
125 XCAM_RETURN_ERROR_PARAM, "get_connector failed since it is not connected");
John Ye1503c6b2015-01-22 13:26:33 +0800126
127 return XCAM_RETURN_NO_ERROR;
128}
129
130
131XCamReturn
132DrmDisplay::get_plane()
133{
134 drmModePlaneResPtr planes = drmModeGetPlaneResources(_fd);
135 XCAM_FAIL_RETURN(ERROR, planes, XCAM_RETURN_ERROR_PARAM,
136 "failed to query planes: %s", strerror(errno));
137
138 drmModePlanePtr plane = NULL;
139 for (uint32_t i = 0; i < planes->count_planes; i++) {
140 if (plane) {
141 drmModeFreePlane(plane);
142 plane = NULL;
143 }
144 plane = drmModeGetPlane(_fd, planes->planes[i]);
145 XCAM_FAIL_RETURN(ERROR, plane, XCAM_RETURN_ERROR_PARAM,
146 "failed to query plane %d: %s", i, strerror(errno));
147
148 if (plane->crtc_id || !(plane->possible_crtcs & (1 << _crtc_index))) {
149 continue;
150 }
151
152 for (uint32_t j = 0; j < plane->count_formats; j++) {
153 // found a plane matching the requested format
154 if (plane->formats[j] == _format) {
155 _plane_id = plane->plane_id;
156 drmModeFreePlane(plane);
157 drmModeFreePlaneResources(planes);
158 return XCAM_RETURN_NO_ERROR;
159 }
160 }
161 }
162
163 if (plane)
164 drmModeFreePlane(plane);
165
166 drmModeFreePlaneResources(planes);
167
168 return XCAM_RETURN_ERROR_PARAM;
169}
170
171XCamReturn
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800172DrmDisplay::render_init (
173 uint32_t con_id,
174 uint32_t crtc_id,
175 uint32_t width,
176 uint32_t height,
177 uint32_t format,
178 const struct v4l2_rect* compose)
John Ye1503c6b2015-01-22 13:26:33 +0800179{
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800180 XCamReturn ret = XCAM_RETURN_NO_ERROR;
John Ye1503c6b2015-01-22 13:26:33 +0800181
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800182 if (is_render_inited ())
183 return ret;
184
John Ye1503c6b2015-01-22 13:26:33 +0800185 _con_id = con_id;
186 _crtc_id = crtc_id;
187 _width = width;
188 _height = height;
Wind Yuan95e5b362015-03-27 15:17:50 +0800189 _format = to_drm_fourcc (format);
John Yecef36802015-01-26 16:00:16 +0800190 _compose = *compose;
John Ye1503c6b2015-01-22 13:26:33 +0800191 _crtc_index = -1;
192 _plane_id = 0;
193 _connector = NULL;
194
John Ye1503c6b2015-01-22 13:26:33 +0800195 drmModeRes *resource = drmModeGetResources(_fd);
196 XCAM_FAIL_RETURN(ERROR, resource, XCAM_RETURN_ERROR_PARAM,
197 "failed to query Drm Mode resources: %s", strerror(errno));
198
199 ret = get_crtc(resource);
200 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR,
201 XCAM_RETURN_ERROR_PARAM,
202 "failed to get CRTC %s", strerror(errno));
203
204 ret = get_connector(resource);
205 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR,
206 XCAM_RETURN_ERROR_PARAM,
207 "failed to get connector %s", strerror(errno));
208
209 ret = get_plane();
210 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR,
211 XCAM_RETURN_ERROR_PARAM,
212 "failed to get plane with required format %s", strerror(errno));
213
214 drmModeFreeResources(resource);
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800215
216 _is_render_inited = true;
John Ye1503c6b2015-01-22 13:26:33 +0800217 return XCAM_RETURN_NO_ERROR;
218}
219
220
221SmartPtr<V4l2Buffer>
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800222DrmDisplay::create_drm_buf (
223 const struct v4l2_format &format,
224 const uint32_t index,
225 const enum v4l2_buf_type buf_type)
John Ye1503c6b2015-01-22 13:26:33 +0800226{
227 struct drm_mode_create_dumb gem;
228 struct drm_prime_handle prime;
229 struct v4l2_buffer v4l2_buf;
230 int ret = 0;
231
232 xcam_mem_clear (&gem);
233 xcam_mem_clear (&prime);
234 xcam_mem_clear (&v4l2_buf);
235
236 gem.width = format.fmt.pix.bytesperline;
237 gem.height = format.fmt.pix.height;
238 gem.bpp = 8;
239 ret = xcam_device_ioctl (_fd, DRM_IOCTL_MODE_CREATE_DUMB, &gem);
240 XCAM_ASSERT (ret >= 0);
241
242 prime.handle = gem.handle;
243 ret = xcam_device_ioctl (_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime);
244 if (ret < 0) {
245 XCAM_LOG_WARNING ("create drm failed on DRM_IOCTL_PRIME_HANDLE_TO_FD");
246 return NULL;
247 }
248
249 v4l2_buf.index = index;
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800250 v4l2_buf.type = buf_type;
John Ye1503c6b2015-01-22 13:26:33 +0800251 v4l2_buf.memory = V4L2_MEMORY_DMABUF;
252 v4l2_buf.m.fd = prime.fd;
253 v4l2_buf.length = XCAM_MAX (format.fmt.pix.sizeimage, gem.size); // todo check gem.size and format.fmt.pix.length
254 XCAM_LOG_DEBUG ("create drm buffer size:%lld", gem.size);
Wind Yuan25aed2b2015-02-10 17:46:23 +0800255 return new DrmV4l2Buffer (gem.handle, v4l2_buf, format, _instance);
John Ye1503c6b2015-01-22 13:26:33 +0800256}
257
John Ye1503c6b2015-01-22 13:26:33 +0800258XCamReturn
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800259DrmDisplay::render_setup_frame_buffer (SmartPtr<VideoBuffer> &buf)
John Ye1503c6b2015-01-22 13:26:33 +0800260{
261 XCamReturn ret = XCAM_RETURN_NO_ERROR;
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800262 VideoBufferInfo video_info = buf->get_video_info ();
263 uint32_t fourcc = video_info.format;
264 uint32_t fb_handle = 0;
265 uint32_t bo_handle = 0;
266 uint32_t bo_handles[4] = { 0 };
267 FB fb;
268 SmartPtr<V4l2BufferProxy> v4l2_proxy;
269 SmartPtr<DrmBoBuffer> bo_buf;
John Ye1503c6b2015-01-22 13:26:33 +0800270
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800271 if (has_frame_buffer (buf))
272 return XCAM_RETURN_NO_ERROR;
John Ye1503c6b2015-01-22 13:26:33 +0800273
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800274 v4l2_proxy = buf.dynamic_cast_ptr<V4l2BufferProxy> ();
275 bo_buf = buf.dynamic_cast_ptr<DrmBoBuffer> ();
276 if (v4l2_proxy.ptr ()) {
277 struct drm_prime_handle prime;
278 memset(&prime, 0, sizeof (prime));
279 prime.fd = v4l2_proxy->get_v4l2_dma_fd();
280
281 ret = (XCamReturn) xcam_device_ioctl(_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime);
282 if (ret) {
283 XCAM_LOG_WARNING("FD_TO_PRIME_HANDLE failed: %s", strerror(errno));
284 return XCAM_RETURN_ERROR_IOCTL;
285 }
286 bo_handle = prime.handle;
287 } else if (bo_buf.ptr ()) {
288 const drm_intel_bo* bo = bo_buf->get_bo ();
289 bo_handle = bo->handle;
290 } else {
291 XCAM_ASSERT (false);
292 XCAM_LOG_WARNING("drm setup framebuffer doesn't support this buffer");
293 return XCAM_RETURN_ERROR_PARAM;
John Ye1503c6b2015-01-22 13:26:33 +0800294 }
295
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800296 for (uint32_t i = 0; i < 4; ++i) {
297 bo_handles [i] = bo_handle;
298 }
John Ye1503c6b2015-01-22 13:26:33 +0800299
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800300 ret = (XCamReturn) drmModeAddFB2(_fd, video_info.width, video_info.height, fourcc, bo_handles,
301 video_info.strides, video_info.offsets, &fb_handle, 0);
John Ye1503c6b2015-01-22 13:26:33 +0800302
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800303 fb.fb_handle = fb_handle;
304 fb.index = global_signal_index++;
305 _buf_fb_handles[buf.ptr ()] = fb;
John Ye1503c6b2015-01-22 13:26:33 +0800306
307 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, XCAM_RETURN_ERROR_PARAM,
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800308 "drmModeAddFB2 failed: %s", strerror(errno));
John Ye1503c6b2015-01-22 13:26:33 +0800309
310 return ret;
311}
312
313XCamReturn
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800314DrmDisplay::set_plane (const FB &fb)
John Ye1503c6b2015-01-22 13:26:33 +0800315{
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800316 XCamReturn ret = XCAM_RETURN_NO_ERROR;
317 uint32_t fb_handle = fb.fb_handle;
318 uint32_t index = fb.index;
John Ye1503c6b2015-01-22 13:26:33 +0800319
320 ret = (XCamReturn) drmModeSetPlane(_fd, _plane_id, _crtc_id,
321 fb_handle, 0,
322 _compose.left, _compose.top,
323 _compose.width, _compose.height,
324 0, 0, _width << 16, _height << 16);
325 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, XCAM_RETURN_ERROR_IOCTL,
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800326 "failed to set plane via drm: %s", strerror(errno));
Wind Yuan024e1f32015-03-30 16:27:41 +0800327#if 0
John Ye1503c6b2015-01-22 13:26:33 +0800328 drmVBlank vblank;
329 vblank.request.type = (drmVBlankSeqType) (DRM_VBLANK_EVENT | DRM_VBLANK_RELATIVE);
330 vblank.request.sequence = 1;
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800331 vblank.request.signal = (unsigned long) index;
John Ye1503c6b2015-01-22 13:26:33 +0800332 ret = (XCamReturn) drmWaitVBlank(_fd, &vblank);
333 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, XCAM_RETURN_ERROR_IOCTL,
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800334 "failed to wait vblank: %s", strerror(errno));
Wind Yuan024e1f32015-03-30 16:27:41 +0800335#endif
John Ye1503c6b2015-01-22 13:26:33 +0800336 return XCAM_RETURN_NO_ERROR;
337}
338
339XCamReturn
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800340DrmDisplay::page_flip (const FB &fb)
John Ye1503c6b2015-01-22 13:26:33 +0800341{
342 XCamReturn ret;
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800343 uint32_t fb_handle = fb.fb_handle;
344 uint32_t index = fb.index;
John Ye1503c6b2015-01-22 13:26:33 +0800345
346 ret = (XCamReturn) drmModePageFlip(_fd, _crtc_id, fb_handle,
347 DRM_MODE_PAGE_FLIP_EVENT,
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800348 (void*)(unsigned long) index);
John Ye1503c6b2015-01-22 13:26:33 +0800349 XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, XCAM_RETURN_ERROR_IOCTL,
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800350 "failed on page flip: %s", strerror(errno));
John Ye1503c6b2015-01-22 13:26:33 +0800351
352 return XCAM_RETURN_NO_ERROR;
353}
354
355XCamReturn
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800356DrmDisplay::render_buffer(SmartPtr<VideoBuffer> &buf)
John Ye1503c6b2015-01-22 13:26:33 +0800357{
Wind Yuan50f5e9e2015-03-26 16:57:13 +0800358 FBMap::iterator iter = _buf_fb_handles.find (buf.ptr ());
359 XCAM_FAIL_RETURN(
360 ERROR,
361 iter != _buf_fb_handles.end (),
362 XCAM_RETURN_ERROR_PARAM,
363 "buffer not register on framebuf");
364
365 return _plane_id ? set_plane(iter->second) : page_flip(iter->second);
John Ye1503c6b2015-01-22 13:26:33 +0800366}
367
Wind Yuan25aed2b2015-02-10 17:46:23 +0800368
369SmartPtr<DrmBoBuffer>
370DrmDisplay::convert_to_drm_bo_buf (SmartPtr<DrmDisplay> &self, SmartPtr<VideoBuffer> &buf_in)
371{
372 drm_intel_bo *bo = NULL;
373 int dma_fd = 0;
374 SmartPtr<V4l2BufferProxy> v4l2_proxy;
375 SmartPtr<DrmBoBuffer> new_bo_buf;
376 SmartPtr<DrmBoWrapper> bo_wrapper;
377
378 XCAM_ASSERT (self.ptr () == this);
379
380 new_bo_buf = buf_in.dynamic_cast_ptr<DrmBoBuffer> ();
381 if (new_bo_buf.ptr ())
382 return new_bo_buf;
383
384 v4l2_proxy = buf_in.dynamic_cast_ptr<V4l2BufferProxy> ();
385 if (!v4l2_proxy.ptr () || v4l2_proxy->get_v4l2_mem_type () != V4L2_MEMORY_DMABUF) {
386 XCAM_LOG_DEBUG ("DrmDisplay only support dma buffer conversion to drm bo by now");
387 return NULL;
388 }
389
390 dma_fd = v4l2_proxy->get_v4l2_dma_fd ();
391 XCAM_ASSERT (dma_fd > 0);
392 bo = drm_intel_bo_gem_create_from_prime (_buf_manager, dma_fd, v4l2_proxy->get_v4l2_buf_length ());
393 if (bo == NULL) {
394 XCAM_LOG_WARNING ("convert dma fd to drm bo failed");
395 return NULL;
396 }
397 bo_wrapper = new DrmBoWrapper (self, bo);
398 new_bo_buf = new DrmBoBuffer (self, buf_in->get_video_info (), bo_wrapper);
399 new_bo_buf->set_parent (buf_in);
400 return new_bo_buf;
401}
402
403SmartPtr<DrmBoWrapper>
404DrmDisplay::create_drm_bo (SmartPtr<DrmDisplay> &self, const VideoBufferInfo &info)
405{
406 SmartPtr<DrmBoWrapper> new_bo;
407
408 XCAM_ASSERT (_buf_manager);
409 XCAM_ASSERT (self.ptr() == this);
410 drm_intel_bo *bo = drm_intel_bo_alloc (
411 _buf_manager, "xcam drm bo buf", info.size, 0x1000);
412
413 new_bo = new DrmBoWrapper (self, bo);
414 return new_bo;
415}
416
John Ye1503c6b2015-01-22 13:26:33 +0800417};