1 /***************************************************************************
3 * Copyright 2010,2011 BMW Car IT GmbH
4 * Copyright (C) 2011 DENSO CORPORATION and Robert Bosch Car Multimedia Gmbh
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 ****************************************************************************/
21 #include "GraphicSystems/DrmGLESGraphicSystem.h"
22 #include "IlmMatrix.h"
25 #include "EGL/eglext.h"
26 #include "GLES2/gl2.h"
28 #include "PlatformSurfaces/WaylandPlatformSurface.h"
29 #include "WindowSystems/WaylandBaseWindowSystem.h"
31 #include "wayland-server.h"
34 #include <drm_fourcc.h>
39 static drmModeModeInfo builtin_800x480_for_Crossville = {
41 800, 859, 999, 999, 0,
42 480, 507, 538, 524, 0,
44 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC,
50 pageFlipHandler(int /*fd*/, unsigned int /*frame*/, unsigned int /*sec*/,
51 unsigned int /*usec*/, void *data)
53 struct DrmOutput *output = static_cast<struct DrmOutput*>(data);
55 output->pageFlipPending = 0;
59 gbm_surface_release_buffer(output->surface, output->current->bo);
62 output->current = output->next;
65 if (output->windowSystem)
67 output->windowSystem->finishFrame();
72 onDrmInput(int fd, uint32_t /*mask*/, void * /*data*/)
74 drmEventContext evctx;
75 memset(&evctx, 0, sizeof evctx);
77 evctx.version = DRM_EVENT_CONTEXT_VERSION;
78 evctx.page_flip_handler = pageFlipHandler;
79 evctx.vblank_handler = NULL;
81 drmHandleEvent(fd, &evctx);
87 drmFbDestroyCallback(struct gbm_bo *bo, void *data)
89 struct DrmFb *fb = (struct DrmFb*)data;
90 struct gbm_device *gbm = gbm_bo_get_device(bo);
93 drmModeRmFB(gbm_device_get_fd(gbm), fb->fbId);
99 drmFbGetFromBo(struct gbm_bo *bo, int fdDev, struct DrmOutput *output)
101 struct DrmFb *fb = (struct DrmFb*)gbm_bo_get_user_data(bo);
102 uint32_t width, height, stride, handle;
108 fb = (struct DrmFb*)malloc(sizeof *fb);
112 width = gbm_bo_get_width(bo);
113 height = gbm_bo_get_height(bo);
114 stride = gbm_bo_get_stride(bo);
115 handle = gbm_bo_get_handle(bo).u32;
117 ret = drmModeAddFB(fdDev, width, height, 24, 32, stride, handle, &fb->fbId);
123 gbm_bo_set_user_data(bo, fb, drmFbDestroyCallback);
128 DrmGLESGraphicSystem::DrmGLESGraphicSystem(int windowWidth, int windowHeight,
129 PfnShaderProgramCreator shaderProgram)
130 : GLESGraphicsystem(windowWidth, windowHeight, shaderProgram)
136 , m_connectorAllocator(0)
137 , m_currentOutput(NULL)
139 LOG_DEBUG("DrmGLESGraphicSystem", "creating DrmGLESGraphicSystem");
141 m_pfEglBindWaylandDisplayWL = (PFNEGLBINDWAYLANDDISPLAYWL)eglGetProcAddress("eglBindWaylandDisplayWL");
142 m_pfEglUnbindWaylandDisplayWL = (PFNEGLUNBINDWAYLANDDISPLAYWL)eglGetProcAddress("eglUnbindWaylandDisplayWL");
144 if (!m_pfEglBindWaylandDisplayWL ||
145 !m_pfEglUnbindWaylandDisplayWL)
147 LOG_ERROR("DrmGLESGraphicSystem", "Query EGL extensions failed.");
151 DrmGLESGraphicSystem::~DrmGLESGraphicSystem()
153 WaylandBaseWindowSystem* windowSystem = dynamic_cast<WaylandBaseWindowSystem*>(m_baseWindowSystem);
154 struct wl_display* wlDisplay = windowSystem->getNativeDisplayHandle();
156 if (NULL != m_eglContext)
158 eglDestroyContext(m_eglDisplay, m_eglContext);
162 struct DrmOutput* output = NULL;
163 wl_list_for_each(output, &m_outputList, link) {
164 if (NULL != output->eglSurface)
166 eglDestroySurface(m_eglDisplay, output->eglSurface);
167 output->eglSurface = NULL;
170 if (NULL != output->surface)
172 gbm_surface_destroy(output->surface);
173 output->surface = NULL;
179 m_pfEglUnbindWaylandDisplayWL(m_eglDisplay, wlDisplay);
182 bool DrmGLESGraphicSystem::init(EGLNativeDisplayType display, EGLNativeWindowType NativeWindow)
185 LOG_DEBUG("DrmGLESGraphicSystem", "init..display:" << display <<
186 ", NativeWindow:" << NativeWindow);
188 m_nativeDisplay = display;
189 m_nativeWindow = NativeWindow;
191 wl_list_init(&m_outputList);
193 m_gbm = (gbm_device*)display;
196 LOG_ERROR("DrmGLESGraphicSystem", "gbm device is NULL.");
200 m_fdDev = gbm_device_get_fd(m_gbm);
203 LOG_ERROR("DrmGLESGraphicSystem", "failed to get device fd.");
207 m_eglDisplay = eglGetDisplay((EGLNativeDisplayType)m_gbm);
208 if (m_eglDisplay == EGL_NO_DISPLAY)
210 LOG_ERROR("DrmGLESGraphicSystem", "failed to get EGL display.");
215 if (!eglInitialize(m_eglDisplay, &major, &minor))
217 LOG_ERROR("DrmGLESGraphicSystem", "failed to initialising EGL.");
221 static const EGLint configAttribs[] = {
222 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
227 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
231 if (!eglChooseConfig(m_eglDisplay, configAttribs, &m_eglConfig, 1, &n) || n != 1)
233 LOG_ERROR("DrmGLESGraphicSystem", "failed to choose config.");
237 if (!initializeSystem())
239 LOG_ERROR("DrmGLESGraphicSystem", "failed to initialize system.");
243 if (!GLESGraphicsystem::initOpenGLES(m_windowWidth, m_windowHeight))
245 LOG_ERROR("DrmGLESGraphicSystem", "failed to initialize gles.");
252 void DrmGLESGraphicSystem::activateGraphicContext()
256 void DrmGLESGraphicSystem::updateScreenList(LmScreenList& screenList)
258 LmScreenListIterator iter = screenList.begin();
259 LmScreenListIterator iterEnd = screenList.end();
260 for (; iter != iterEnd; ++iter)
266 struct DrmOutput* output = NULL;
267 wl_list_for_each(output, &m_outputList, link)
269 LmScreen* lmScreen = new LmScreen(output->screenID, "");
270 screenList.push_back(lmScreen);
274 void DrmGLESGraphicSystem::switchScreen(uint screenID)
276 // Actually, when renderSWLayers is called, rendering target buffer is switched
277 // because of avoiding overhead of switching display.
278 struct DrmOutput* output = NULL;
279 wl_list_for_each(output, &m_outputList, link)
281 if (output->screenID != screenID)
286 LOG_DEBUG("DrmGLESGraphicSystem", "switch screen:" << m_currentOutput->screenID);
287 m_currentOutput = output;
288 drmOutputPrepareRender(m_currentOutput);
293 bool DrmGLESGraphicSystem::initializeSystem()
295 LOG_DEBUG("DrmGLESGraphicSystem", "initializeSystem IN");
297 WaylandBaseWindowSystem* windowSystem = dynamic_cast<WaylandBaseWindowSystem*>(m_baseWindowSystem);
298 struct wl_display* wlDisplay = windowSystem->getNativeDisplayHandle();
301 m_pfEglBindWaylandDisplayWL(m_eglDisplay, wlDisplay);
303 if (!createOutputs())
306 if (!eglBindAPI(EGL_OPENGL_ES_API))
308 LOG_ERROR("DrmGLESGraphicSystem", "failed to bind api EGL_OPENGL_ES_API.");
312 EGLint contextAttrs[] = {
313 EGL_CONTEXT_CLIENT_VERSION, 2,
317 m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttrs);
320 LOG_ERROR("DrmGLESGraphicSystem", "failed to create EGL context.");
324 struct DrmOutput *output = wl_container_of(m_outputList.prev, output, link);
326 if (!eglMakeCurrent(m_eglDisplay, output->eglSurface, output->eglSurface, m_eglContext))
328 LOG_ERROR("DrmGLESGraphicSystem", "failed to make context current.");
332 struct wl_event_loop *loop = wl_display_get_event_loop(wlDisplay);
333 wl_event_loop_add_fd(loop, m_fdDev, WL_EVENT_READABLE, onDrmInput, NULL);
335 LOG_DEBUG("DrmGLESGraphicSystem", "initializeSystem OUT");
340 bool DrmGLESGraphicSystem::createOutputs()
342 LOG_DEBUG("DrmGLESGraphicSystem", "createOutputs IN");
344 drmModeConnector* connector;
345 drmModeRes* resources;
348 resources = drmModeGetResources(m_fdDev);
351 LOG_DEBUG("DrmGLESGraphicSystem", "drmModeGetResources failed.");
355 m_crtcs = (uint32_t*)calloc(resources->count_crtcs, sizeof(uint32_t));
358 drmModeFreeResources(resources);
361 m_crtcsNum = resources->count_crtcs;
363 memcpy(m_crtcs, resources->crtcs, sizeof(uint32_t) * m_crtcsNum);
365 for (int ii = 0; ii < resources->count_connectors; ++ii)
367 connector = drmModeGetConnector(m_fdDev, resources->connectors[ii]);
368 if (connector == NULL)
371 if (connector->connection == DRM_MODE_CONNECTED)
373 if (createOutputForConnector(resources, connector, x, y) < 0)
375 drmModeFreeConnector(connector);
379 //x += container_of(m_outputList.prev, struct DrmOutput, link)->currentMode->width;
382 drmModeFreeConnector(connector);
385 if (wl_list_empty(&m_outputList))
387 LOG_ERROR("DrmGLESGraphicSystem", "DrmOutput list is empty.");
388 drmModeFreeResources(resources);
392 drmModeFreeResources(resources);
394 LOG_DEBUG("DrmGLESGraphicSystem", "createOutputs OUT");
398 int DrmGLESGraphicSystem::createOutputForConnector(drmModeRes* resources,
399 drmModeConnector* connector,
402 LOG_DEBUG("DrmGLESGraphicSystem", "createOutputForConnector IN");
404 drmModeEncoder* encoder;
405 struct DrmMode* drmMode = NULL;
407 encoder = drmModeGetEncoder(m_fdDev, connector->encoders[0]);
408 if (encoder == NULL){
409 LOG_ERROR("DrmGLESGraphicSystem", "No encoder for connector.");
413 for (ii = 0; ii < resources->count_crtcs; ++ii)
415 if (encoder->possible_crtcs & (1 << ii) &&
416 !(m_crtcAllocator & (1 << resources->crtcs[ii])))
421 if (ii == resources->count_crtcs)
423 LOG_ERROR("DrmGLESGraphicSystem", "No usable crtc for encoder.");
427 DrmOutput* output = (DrmOutput*)malloc(sizeof *output);
430 drmModeFreeEncoder(encoder);
433 memset(output, 0x00, sizeof *output);
435 output->windowSystem = m_baseWindowSystem;
436 output->fdDev = m_fdDev;
437 output->crtcID = resources->crtcs[ii];
438 output->connectorID = connector->connector_id;
440 m_crtcAllocator |= (1 << output->crtcID);
441 m_connectorAllocator |= (1 << output->connectorID);
443 wl_list_init(&output->modeList);
445 output->orgCrtc = drmModeGetCrtc(m_fdDev, output->crtcID);
446 drmModeFreeEncoder(encoder);
448 for (ii = 0; ii < connector->count_modes; ++ii)
450 if (drmOutputAddMode(output, &connector->modes[ii]))
454 if (connector->count_modes == 0)
456 if (drmOutputAddMode(output, &builtin_800x480_for_Crossville))
460 drmMode = wl_container_of(output->modeList.next, drmMode, link);
461 output->currentMode = drmMode;
462 drmMode->flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
464 output->surface = gbm_surface_create(m_gbm,
465 output->currentMode->width,
466 output->currentMode->height,
467 GBM_BO_FORMAT_XRGB8888,
468 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
469 if (!output->surface) {
470 LOG_ERROR("DrmGLESGraphicSystem", "failed to create gbm surface.");
471 goto err_gbm_surface;
474 output->eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig,
475 (EGLNativeWindowType)output->surface, NULL);
476 if (output->eglSurface == EGL_NO_SURFACE) {
477 LOG_ERROR("DrmGLESGraphicSystem", "failed to create egl surface.");
478 goto err_egl_surface;
481 output->screenID = (uint)wl_list_length(&m_outputList);
482 m_currentOutput = output;
484 wl_list_insert(m_outputList.prev, &output->link);
486 LOG_DEBUG("DrmGLESGraphicSystem", "createOutputForConnector OUT (NORMAL)");
490 if (output->eglSurface)
491 eglDestroySurface(m_eglDisplay, output->eglSurface);
495 gbm_surface_destroy(output->surface);
498 drmModeFreeCrtc(output->orgCrtc);
499 m_crtcAllocator &= ~(1 << output->crtcID);
500 m_connectorAllocator &= ~(1 << output->connectorID);
503 LOG_DEBUG("DrmGLESGraphicSystem", "createOutputForConnector OUT (ERROR)");
507 int DrmGLESGraphicSystem::drmOutputAddMode(struct DrmOutput* output, drmModeModeInfo* info)
509 struct DrmMode* mode;
511 mode = (struct DrmMode*)malloc(sizeof *mode);
516 mode->width = info->hdisplay;
517 mode->height = info->vdisplay;
518 mode->refresh = info->vrefresh;
519 mode->modeInfo = *info;
520 wl_list_insert(output->modeList.prev, &mode->link);
525 int DrmGLESGraphicSystem::drmOutputPrepareRender(struct DrmOutput* output)
527 if (!eglMakeCurrent(m_eglDisplay, output->eglSurface, output->eglSurface, m_eglContext))
529 LOG_ERROR("DrmGLESGraphicSystem", "failed to make current.");
535 void DrmGLESGraphicSystem::swapBuffers()
537 LOG_DEBUG("DrmGLESGraphicSystem", "swapBuffers IN");
539 struct DrmOutput* output = NULL;
541 wl_list_for_each(output, &m_outputList, link)
543 if (output != m_currentOutput)
550 eglSwapBuffers(m_eglDisplay, output->eglSurface);
551 struct gbm_bo *bo = gbm_surface_lock_front_buffer(output->surface);
555 output->next = drmFbGetFromBo(bo, m_fdDev, output);
558 gbm_surface_release_buffer(output->surface, bo);
563 if (!output->current)
565 if (drmModeSetCrtc(m_fdDev, output->crtcID,
566 output->next->fbId, 0, 0,
567 &output->connectorID, 1,
568 &output->currentMode->modeInfo))
570 LOG_ERROR("DrmGLESGraphicSystem", "failed to set mode in swapBuffers.");
575 if (drmModePageFlip(m_fdDev, output->crtcID, output->next->fbId,
576 DRM_MODE_PAGE_FLIP_EVENT, output) < 0)
578 LOG_ERROR("DrmGLESGraphicSystem", "queueing pageflip failed");
582 output->pageFlipPending = 1;
586 LOG_DEBUG("DrmGLESGraphicSystem", "swapBuffers OUT");