2 * Copyright (C) 2011-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
24 #include "WinSystemEGL.h"
25 #include "filesystem/SpecialProtocol.h"
26 #include "guilib/GraphicContext.h"
27 #include "settings/DisplaySettings.h"
28 #include "guilib/IDirtyRegionSolver.h"
29 #include "settings/AdvancedSettings.h"
30 #include "settings/Settings.h"
31 #include "settings/DisplaySettings.h"
32 #include "utils/log.h"
33 #include "EGLWrapper.h"
34 #include "EGLQuirks.h"
36 ////////////////////////////////////////////////////////////////////////////////////////////
37 CWinSystemEGL::CWinSystemEGL() : CWinSystemBase()
39 m_eWindowSystem = WINDOW_SYSTEM_EGL;
44 m_display = EGL_NO_DISPLAY;
45 m_surface = EGL_NO_SURFACE;
46 m_context = EGL_NO_CONTEXT;
53 CWinSystemEGL::~CWinSystemEGL()
57 DestroyWindowSystem();
62 bool CWinSystemEGL::InitWindowSystem()
64 RESOLUTION_INFO preferred_resolution;
66 m_egl = new CEGLWrapper;
70 CLog::Log(LOGERROR, "%s: EGL not in a good state",__FUNCTION__);
74 if (!m_egl->Initialize("auto"))
76 CLog::Log(LOGERROR, "%s: Could not initialize",__FUNCTION__);
80 CLog::Log(LOGNOTICE, "%s: Using EGL Implementation: %s",__FUNCTION__,m_egl->GetNativeName().c_str());
82 if (!m_egl->CreateNativeDisplay())
84 CLog::Log(LOGERROR, "%s: Could not get native display",__FUNCTION__);
88 if (!m_egl->CreateNativeWindow())
90 CLog::Log(LOGERROR, "%s: Could not get native window",__FUNCTION__);
94 if (!m_egl->InitDisplay(&m_display))
96 CLog::Log(LOGERROR, "%s: Could not create display",__FUNCTION__);
100 EGLint surface_type = EGL_WINDOW_BIT;
101 // for the non-trivial dirty region modes, we need the EGL buffer to be preserved across updates
102 if (g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_COST_REDUCTION ||
103 g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_UNION)
104 surface_type |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
106 EGLint configAttrs [] = {
113 EGL_SAMPLE_BUFFERS, 0,
115 EGL_SURFACE_TYPE, surface_type,
116 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
120 if (!m_egl->ChooseConfig(m_display, configAttrs, &m_config))
122 CLog::Log(LOGERROR, "%s: Could not find a compatible configuration",__FUNCTION__);
126 // Some platforms require a surface before we can probe the resolution.
127 // Create the window here, then the creation in CreateNewWindow() will be skipped.
129 m_egl->GetQuirks(&quirks);
130 if (quirks & EGL_QUIRK_NEED_WINDOW_FOR_RES)
132 RESOLUTION_INFO temp;
136 m_extensions = m_egl->GetExtensions(m_display);
137 return CWinSystemBase::InitWindowSystem();
140 bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res)
144 CLog::Log(LOGERROR, "CWinSystemEGL::CreateWindow no EGL!");
149 m_egl->SetNativeResolution(res);
151 if (!m_egl->CreateSurface(m_display, m_config, &m_surface))
153 CLog::Log(LOGNOTICE, "%s: Could not create a surface. Trying with a fresh Native Window.",__FUNCTION__);
154 m_egl->DestroyNativeWindow();
155 if (!m_egl->CreateNativeWindow())
157 CLog::Log(LOGERROR, "%s: Could not get native window",__FUNCTION__);
161 if (!m_egl->CreateSurface(m_display, m_config, &m_surface))
163 CLog::Log(LOGERROR, "%s: Could not create surface",__FUNCTION__);
168 /* The intel driver on wayland is broken and always returns a surface
169 * size of -1, -1. Work around it for now */
170 if (m_egl->TrustSurfaceSize())
172 int width = 0, height = 0;
173 if (!m_egl->GetSurfaceSize(m_display, m_surface, &width, &height))
175 CLog::Log(LOGERROR, "%s: Surface is invalid",__FUNCTION__);
178 CLog::Log(LOGDEBUG, "%s: Created surface of size %ix%i",__FUNCTION__, width, height);
181 CLog::Log(LOGDEBUG, "%s: Cannot reliably get surface size with this backend",__FUNCTION__);
183 EGLint contextAttrs[] =
185 EGL_CONTEXT_CLIENT_VERSION, 2,
189 if (!m_egl->BindAPI(EGL_OPENGL_ES_API))
191 CLog::Log(LOGERROR, "%s: Could not bind %i api",__FUNCTION__, EGL_OPENGL_ES_API);
195 if (m_context == EGL_NO_CONTEXT)
197 if (!m_egl->CreateContext(m_display, m_config, contextAttrs, &m_context))
199 CLog::Log(LOGERROR, "%s: Could not create context",__FUNCTION__);
204 if (!m_egl->BindContext(m_display, m_surface, m_context))
206 CLog::Log(LOGERROR, "%s: Could not bind to context",__FUNCTION__);
210 // for the non-trivial dirty region modes, we need the EGL buffer to be preserved across updates
211 if (g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_COST_REDUCTION ||
212 g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_UNION)
214 if (!m_egl->SurfaceAttrib(m_display, m_surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED))
215 CLog::Log(LOGDEBUG, "%s: Could not set EGL_SWAP_BEHAVIOR",__FUNCTION__);
218 m_bWindowCreated = true;
223 bool CWinSystemEGL::DestroyWindowSystem()
230 if (m_context != EGL_NO_CONTEXT)
231 m_egl->DestroyContext(m_display, m_context);
232 m_context = EGL_NO_CONTEXT;
234 if (m_display != EGL_NO_DISPLAY)
235 m_egl->DestroyDisplay(m_display);
236 m_display = EGL_NO_DISPLAY;
238 m_egl->DestroyNativeWindow();
240 m_egl->DestroyNativeDisplay();
249 bool CWinSystemEGL::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
251 RESOLUTION_INFO current_resolution;
252 current_resolution.iWidth = current_resolution.iHeight = 0;
254 m_nWidth = res.iWidth;
255 m_nHeight = res.iHeight;
256 m_displayWidth = res.iScreenWidth;
257 m_displayHeight = res.iScreenHeight;
258 m_fRefreshRate = res.fRefreshRate;
260 if ((m_bWindowCreated && m_egl && m_egl->GetNativeResolution(¤t_resolution)) &&
261 current_resolution.iWidth == res.iWidth && current_resolution.iHeight == res.iHeight &&
262 current_resolution.iScreenWidth == res.iScreenWidth && current_resolution.iScreenHeight == res.iScreenHeight &&
263 m_bFullScreen == fullScreen && current_resolution.fRefreshRate == res.fRefreshRate &&
264 (current_resolution.dwFlags & D3DPRESENTFLAG_MODEMASK) == (res.dwFlags & D3DPRESENTFLAG_MODEMASK))
266 CLog::Log(LOGDEBUG, "CWinSystemEGL::CreateNewWindow: No need to create a new window");
270 m_bFullScreen = fullScreen;
271 // Destroy any existing window
272 if (m_surface != EGL_NO_SURFACE)
275 // If we previously destroyed an existing window we need to create a new one
276 // (otherwise this is taken care of by InitWindowSystem())
277 if (!CreateWindow(res))
279 CLog::Log(LOGERROR, "%s: Could not create new window",__FUNCTION__);
287 bool CWinSystemEGL::DestroyWindow()
292 m_egl->ReleaseContext(m_display);
293 if (m_surface != EGL_NO_SURFACE)
294 m_egl->DestroySurface(m_surface, m_display);
297 m_egl->GetQuirks(&quirks);
298 if (quirks & EGL_QUIRK_DESTROY_NATIVE_WINDOW_WITH_SURFACE)
299 m_egl->DestroyNativeWindow();
301 m_surface = EGL_NO_SURFACE;
302 m_bWindowCreated = false;
306 bool CWinSystemEGL::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
308 CRenderSystemGLES::ResetRenderSystem(newWidth, newHeight, true, 0);
309 SetVSyncImpl(m_iVSyncMode);
313 bool CWinSystemEGL::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
315 CreateNewWindow("", fullScreen, res, NULL);
316 CRenderSystemGLES::ResetRenderSystem(res.iWidth, res.iHeight, fullScreen, res.fRefreshRate);
317 SetVSyncImpl(m_iVSyncMode);
321 void CWinSystemEGL::UpdateResolutions()
323 CWinSystemBase::UpdateResolutions();
325 RESOLUTION_INFO resDesktop, curDisplay;
326 std::vector<RESOLUTION_INFO> resolutions;
328 if (!m_egl->ProbeResolutions(resolutions) || resolutions.empty())
330 CLog::Log(LOGWARNING, "%s: ProbeResolutions failed. Trying safe default.",__FUNCTION__);
332 RESOLUTION_INFO fallback;
333 if (m_egl->GetPreferredResolution(&fallback))
335 resolutions.push_back(fallback);
339 CLog::Log(LOGERROR, "%s: Fatal Error, GetPreferredResolution failed",__FUNCTION__);
344 /* ProbeResolutions includes already all resolutions.
345 * Only get desktop resolution so we can replace xbmc's desktop res
347 if (m_egl->GetNativeResolution(&curDisplay))
348 resDesktop = curDisplay;
351 RESOLUTION ResDesktop = RES_INVALID;
352 RESOLUTION res_index = RES_DESKTOP;
354 for (size_t i = 0; i < resolutions.size(); i++)
356 // if this is a new setting,
357 // create a new empty setting to fill in.
358 if ((int)CDisplaySettings::Get().ResolutionInfoSize() <= res_index)
361 CDisplaySettings::Get().AddResolutionInfo(res);
364 g_graphicsContext.ResetOverscan(resolutions[i]);
365 CDisplaySettings::Get().GetResolutionInfo(res_index) = resolutions[i];
367 CLog::Log(LOGNOTICE, "Found resolution %d x %d for display %d with %d x %d%s @ %f Hz\n",
368 resolutions[i].iWidth,
369 resolutions[i].iHeight,
370 resolutions[i].iScreen,
371 resolutions[i].iScreenWidth,
372 resolutions[i].iScreenHeight,
373 resolutions[i].dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "",
374 resolutions[i].fRefreshRate);
376 if(resDesktop.iWidth == resolutions[i].iWidth &&
377 resDesktop.iHeight == resolutions[i].iHeight &&
378 resDesktop.iScreenWidth == resolutions[i].iScreenWidth &&
379 resDesktop.iScreenHeight == resolutions[i].iScreenHeight &&
380 (resDesktop.dwFlags & D3DPRESENTFLAG_MODEMASK) == (resolutions[i].dwFlags & D3DPRESENTFLAG_MODEMASK) &&
381 resDesktop.fRefreshRate == resolutions[i].fRefreshRate)
383 ResDesktop = res_index;
386 res_index = (RESOLUTION)((int)res_index + 1);
389 // swap desktop index for desktop res if available
390 if (ResDesktop != RES_INVALID)
392 CLog::Log(LOGNOTICE, "Found (%dx%d%s@%f) at %d, setting to RES_DESKTOP at %d",
393 resDesktop.iWidth, resDesktop.iHeight,
394 resDesktop.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "",
395 resDesktop.fRefreshRate,
396 (int)ResDesktop, (int)RES_DESKTOP);
398 RESOLUTION_INFO desktop = CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP);
399 CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP) = CDisplaySettings::Get().GetResolutionInfo(ResDesktop);
400 CDisplaySettings::Get().GetResolutionInfo(ResDesktop) = desktop;
404 bool CWinSystemEGL::IsExtSupported(const char* extension)
412 return (m_extensions.find(name) != std::string::npos || CRenderSystemGLES::IsExtSupported(extension));
415 bool CWinSystemEGL::PresentRenderImpl(const CDirtyRegionList &dirty)
417 m_egl->SwapBuffers(m_display, m_surface);
421 void CWinSystemEGL::SetVSyncImpl(bool enable)
423 m_iVSyncMode = enable ? 10:0;
424 if (!m_egl->SetVSync(m_display, enable))
427 CLog::Log(LOGERROR, "%s,Could not set egl vsync", __FUNCTION__);
431 void CWinSystemEGL::ShowOSMouse(bool show)
435 bool CWinSystemEGL::HasCursor()
437 #ifdef TARGET_ANDROID
444 void CWinSystemEGL::NotifyAppActiveChange(bool bActivated)
448 bool CWinSystemEGL::Minimize()
454 bool CWinSystemEGL::Restore()
460 bool CWinSystemEGL::Hide()
462 return m_egl->ShowWindow(false);
465 bool CWinSystemEGL::Show(bool raise)
467 return m_egl->ShowWindow(true);
470 EGLDisplay CWinSystemEGL::GetEGLDisplay()
475 EGLContext CWinSystemEGL::GetEGLContext()
480 EGLConfig CWinSystemEGL::GetEGLConfig()
485 // the logic in this function should match whether CBaseRenderer::FindClosestResolution picks a 3D mode
486 bool CWinSystemEGL::Support3D(int width, int height, uint32_t mode) const
488 RESOLUTION_INFO &curr = CDisplaySettings::Get().GetResolutionInfo(g_graphicsContext.GetVideoResolution());
490 // if we are using automatic hdmi mode switching
491 if (CSettings::Get().GetInt("videoplayer.adjustrefreshrate") != ADJUST_REFRESHRATE_OFF)
493 int searchWidth = curr.iScreenWidth;
494 int searchHeight = curr.iScreenHeight;
496 // only search the custom resolutions
497 for (unsigned int i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
499 RESOLUTION_INFO res = CDisplaySettings::Get().GetResolutionInfo(i);
500 if(res.iScreenWidth == searchWidth && res.iScreenHeight == searchHeight && (res.dwFlags & mode))
504 // otherwise just consider current mode
507 if (curr.dwFlags & mode)
514 bool CWinSystemEGL::ClampToGUIDisplayLimits(int &width, int &height)
516 width = width > m_nWidth ? m_nWidth : width;
517 height = height > m_nHeight ? m_nHeight : height;