glcontext_egl.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * Copyright 2011-2015 Branimir Karadzic. All rights reserved.
  3. * License: http://www.opensource.org/licenses/BSD-2-Clause
  4. */
  5. #include "bgfx_p.h"
  6. #if (BGFX_CONFIG_RENDERER_OPENGLES || BGFX_CONFIG_RENDERER_OPENGL)
  7. # include "renderer_gl.h"
  8. # if BGFX_USE_EGL
  9. # if BX_PLATFORM_RPI
  10. # include <bcm_host.h>
  11. # endif // BX_PLATFORM_RPI
  12. #ifndef EGL_CONTEXT_MAJOR_VERSION_KHR
  13. # define EGL_CONTEXT_MAJOR_VERSION_KHR EGL_CONTEXT_CLIENT_VERSION
  14. #endif // EGL_CONTEXT_MAJOR_VERSION_KHR
  15. #ifndef EGL_CONTEXT_MINOR_VERSION_KHR
  16. # define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB
  17. #endif // EGL_CONTEXT_MINOR_VERSION_KHR
  18. namespace bgfx { namespace gl
  19. {
  20. #if BGFX_USE_GL_DYNAMIC_LIB
  21. typedef void (*EGLPROC)(void);
  22. typedef EGLPROC (EGLAPIENTRY* PFNEGLGETPROCADDRESSPROC)(const char *procname);
  23. typedef EGLBoolean (EGLAPIENTRY* PFNEGLSWAPINTERVALPROC)(EGLDisplay dpy, EGLint interval);
  24. typedef EGLBoolean (EGLAPIENTRY* PFNEGLMAKECURRENTPROC)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
  25. typedef EGLContext (EGLAPIENTRY* PFNEGLCREATECONTEXTPROC)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
  26. typedef EGLSurface (EGLAPIENTRY* PFNEGLCREATEWINDOWSURFACEPROC)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
  27. typedef EGLBoolean (EGLAPIENTRY* PFNEGLCHOOSECONFIGPROC)(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
  28. typedef EGLBoolean (EGLAPIENTRY* PFNEGLINITIALIZEPROC)(EGLDisplay dpy, EGLint *major, EGLint *minor);
  29. typedef EGLint (EGLAPIENTRY* PFNEGLGETERRORPROC)(void);
  30. typedef EGLDisplay (EGLAPIENTRY* PFNEGLGETDISPLAYPROC)(EGLNativeDisplayType display_id);
  31. typedef EGLBoolean (EGLAPIENTRY* PFNEGLTERMINATEPROC)(EGLDisplay dpy);
  32. typedef EGLBoolean (EGLAPIENTRY* PFNEGLDESTROYSURFACEPROC)(EGLDisplay dpy, EGLSurface surface);
  33. typedef EGLBoolean (EGLAPIENTRY* PFNEGLDESTROYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx);
  34. typedef EGLBoolean (EGLAPIENTRY* PFNEGLSWAPBUFFERSPROC)(EGLDisplay dpy, EGLSurface surface);
  35. #define EGL_IMPORT \
  36. EGL_IMPORT_FUNC(PFNEGLGETPROCADDRESSPROC, eglGetProcAddress); \
  37. EGL_IMPORT_FUNC(PFNEGLSWAPINTERVALPROC, eglSwapInterval); \
  38. EGL_IMPORT_FUNC(PFNEGLMAKECURRENTPROC, eglMakeCurrent); \
  39. EGL_IMPORT_FUNC(PFNEGLCREATECONTEXTPROC, eglCreateContext); \
  40. EGL_IMPORT_FUNC(PFNEGLCREATEWINDOWSURFACEPROC, eglCreateWindowSurface); \
  41. EGL_IMPORT_FUNC(PFNEGLCHOOSECONFIGPROC, eglChooseConfig); \
  42. EGL_IMPORT_FUNC(PFNEGLINITIALIZEPROC, eglInitialize); \
  43. EGL_IMPORT_FUNC(PFNEGLGETERRORPROC, eglGetError); \
  44. EGL_IMPORT_FUNC(PFNEGLGETDISPLAYPROC, eglGetDisplay); \
  45. EGL_IMPORT_FUNC(PFNEGLTERMINATEPROC, eglTerminate); \
  46. EGL_IMPORT_FUNC(PFNEGLDESTROYSURFACEPROC, eglDestroySurface); \
  47. EGL_IMPORT_FUNC(PFNEGLDESTROYCONTEXTPROC, eglDestroyContext); \
  48. EGL_IMPORT_FUNC(PFNEGLSWAPBUFFERSPROC, eglSwapBuffers);
  49. #define EGL_IMPORT_FUNC(_proto, _func) _proto _func
  50. EGL_IMPORT
  51. #undef EGL_IMPORT_FUNC
  52. void* eglOpen()
  53. {
  54. void* handle = bx::dlopen("libEGL." BX_DL_EXT);
  55. BGFX_FATAL(NULL != handle, Fatal::UnableToInitialize, "Failed to load libEGL dynamic library.");
  56. #define EGL_IMPORT_FUNC(_proto, _func) \
  57. _func = (_proto)bx::dlsym(handle, #_func); \
  58. BX_TRACE("%p " #_func, _func); \
  59. BGFX_FATAL(NULL != _func, Fatal::UnableToInitialize, "Failed get " #_func ".")
  60. EGL_IMPORT
  61. #undef EGL_IMPORT_FUNC
  62. return handle;
  63. }
  64. void eglClose(void* _handle)
  65. {
  66. bx::dlclose(_handle);
  67. #define EGL_IMPORT_FUNC(_proto, _func) _func = NULL
  68. EGL_IMPORT
  69. #undef EGL_IMPORT_FUNC
  70. }
  71. #else
  72. void* eglOpen()
  73. {
  74. return NULL;
  75. }
  76. void eglClose(void* /*_handle*/)
  77. {
  78. }
  79. #endif // BGFX_USE_GL_DYNAMIC_LIB
  80. # define GL_IMPORT(_optional, _proto, _func, _import) _proto _func = NULL
  81. # include "glimports.h"
  82. static const EGLint s_contextAttrs[] =
  83. {
  84. # if BGFX_CONFIG_RENDERER_OPENGLES >= 30
  85. EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
  86. # if BGFX_CONFIG_RENDERER_OPENGLES >= 31
  87. EGL_CONTEXT_MINOR_VERSION_KHR, 1,
  88. # else
  89. // EGL_CONTEXT_MINOR_VERSION_KHR, 0,
  90. # endif // BGFX_CONFIG_RENDERER_OPENGLES >= 31
  91. # elif BGFX_CONFIG_RENDERER_OPENGLES
  92. EGL_CONTEXT_MAJOR_VERSION_KHR, 2,
  93. // EGL_CONTEXT_MINOR_VERSION_KHR, 0,
  94. # endif // BGFX_CONFIG_RENDERER_
  95. EGL_NONE
  96. };
  97. struct SwapChainGL
  98. {
  99. SwapChainGL(EGLDisplay _display, EGLConfig _config, EGLContext _context, EGLNativeWindowType _nwh)
  100. : m_nwh(_nwh)
  101. , m_display(_display)
  102. {
  103. m_surface = eglCreateWindowSurface(m_display, _config, _nwh, NULL);
  104. BGFX_FATAL(m_surface != EGL_NO_SURFACE, Fatal::UnableToInitialize, "Failed to create surface.");
  105. m_context = eglCreateContext(m_display, _config, _context, s_contextAttrs);
  106. BX_CHECK(NULL != m_context, "Create swap chain failed: %x", eglGetError() );
  107. makeCurrent();
  108. GL_CHECK(glClearColor(0.0f, 0.0f, 0.0f, 0.0f) );
  109. GL_CHECK(glClear(GL_COLOR_BUFFER_BIT) );
  110. swapBuffers();
  111. GL_CHECK(glClear(GL_COLOR_BUFFER_BIT) );
  112. swapBuffers();
  113. }
  114. ~SwapChainGL()
  115. {
  116. eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  117. eglDestroyContext(m_display, m_context);
  118. eglDestroySurface(m_display, m_surface);
  119. }
  120. void makeCurrent()
  121. {
  122. eglMakeCurrent(m_display, m_surface, m_surface, m_context);
  123. }
  124. void swapBuffers()
  125. {
  126. eglSwapBuffers(m_display, m_surface);
  127. }
  128. EGLNativeWindowType m_nwh;
  129. EGLContext m_context;
  130. EGLDisplay m_display;
  131. EGLSurface m_surface;
  132. };
  133. # if BX_PLATFORM_RPI
  134. static EGL_DISPMANX_WINDOW_T s_dispmanWindow;
  135. void x11SetDisplayWindow(::Display* _display, ::Window _window)
  136. {
  137. // Noop for now...
  138. BX_UNUSED(_display, _window);
  139. }
  140. # endif // BX_PLATFORM_RPI
  141. void GlContext::create(uint32_t _width, uint32_t _height)
  142. {
  143. # if BX_PLATFORM_RPI
  144. bcm_host_init();
  145. # endif // BX_PLATFORM_RPI
  146. m_eglLibrary = eglOpen();
  147. BX_UNUSED(_width, _height);
  148. EGLNativeDisplayType ndt = EGL_DEFAULT_DISPLAY;
  149. EGLNativeWindowType nwh = (EGLNativeWindowType)NULL;
  150. # if BX_PLATFORM_WINDOWS
  151. ndt = GetDC(g_bgfxHwnd);
  152. nwh = g_bgfxHwnd;
  153. # elif BX_PLATFORM_LINUX
  154. ndt = (EGLNativeDisplayType)g_bgfxX11Display;
  155. nwh = (EGLNativeWindowType)g_bgfxX11Window;
  156. # endif // BX_PLATFORM_
  157. m_display = eglGetDisplay(ndt);
  158. BGFX_FATAL(m_display != EGL_NO_DISPLAY, Fatal::UnableToInitialize, "Failed to create display %p", m_display);
  159. EGLint major = 0;
  160. EGLint minor = 0;
  161. EGLBoolean success = eglInitialize(m_display, &major, &minor);
  162. BGFX_FATAL(success && major >= 1 && minor >= 3, Fatal::UnableToInitialize, "Failed to initialize %d.%d", major, minor);
  163. EGLint attrs[] =
  164. {
  165. EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
  166. # if BX_PLATFORM_ANDROID
  167. EGL_DEPTH_SIZE, 16,
  168. # else
  169. EGL_DEPTH_SIZE, 24,
  170. # endif // BX_PLATFORM_
  171. EGL_STENCIL_SIZE, 8,
  172. EGL_NONE
  173. };
  174. EGLint numConfig = 0;
  175. success = eglChooseConfig(m_display, attrs, &m_config, 1, &numConfig);
  176. BGFX_FATAL(success, Fatal::UnableToInitialize, "eglChooseConfig");
  177. # if BX_PLATFORM_ANDROID
  178. EGLint format;
  179. eglGetConfigAttrib(m_display, m_config, EGL_NATIVE_VISUAL_ID, &format);
  180. ANativeWindow_setBuffersGeometry(g_bgfxAndroidWindow, _width, _height, format);
  181. nwh = g_bgfxAndroidWindow;
  182. # elif BX_PLATFORM_RPI
  183. DISPMANX_DISPLAY_HANDLE_T dispmanDisplay = vc_dispmanx_display_open(0);
  184. DISPMANX_UPDATE_HANDLE_T dispmanUpdate = vc_dispmanx_update_start(0);
  185. VC_RECT_T dstRect = { 0, 0, _width, _height };
  186. VC_RECT_T srcRect = { 0, 0, _width << 16, _height << 16 };
  187. DISPMANX_ELEMENT_HANDLE_T dispmanElement = vc_dispmanx_element_add(dispmanUpdate
  188. , dispmanDisplay
  189. , 0
  190. , &dstRect
  191. , 0
  192. , &srcRect
  193. , DISPMANX_PROTECTION_NONE
  194. , NULL
  195. , NULL
  196. , DISPMANX_NO_ROTATE
  197. );
  198. s_dispmanWindow.element = dispmanElement;
  199. s_dispmanWindow.width = _width;
  200. s_dispmanWindow.height = _height;
  201. nwh = &s_dispmanWindow;
  202. vc_dispmanx_update_submit_sync(dispmanUpdate);
  203. # endif // BX_PLATFORM_ANDROID
  204. m_surface = eglCreateWindowSurface(m_display, m_config, nwh, NULL);
  205. BGFX_FATAL(m_surface != EGL_NO_SURFACE, Fatal::UnableToInitialize, "Failed to create surface.");
  206. m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, s_contextAttrs);
  207. BGFX_FATAL(m_context != EGL_NO_CONTEXT, Fatal::UnableToInitialize, "Failed to create context.");
  208. success = eglMakeCurrent(m_display, m_surface, m_surface, m_context);
  209. BGFX_FATAL(success, Fatal::UnableToInitialize, "Failed to set context.");
  210. m_current = NULL;
  211. eglSwapInterval(m_display, 0);
  212. # if BX_PLATFORM_EMSCRIPTEN
  213. emscripten_set_canvas_size(_width, _height);
  214. # endif // BX_PLATFORM_EMSCRIPTEN
  215. import();
  216. }
  217. void GlContext::destroy()
  218. {
  219. eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  220. eglDestroyContext(m_display, m_context);
  221. eglDestroySurface(m_display, m_surface);
  222. eglTerminate(m_display);
  223. m_context = NULL;
  224. eglClose(m_eglLibrary);
  225. # if BX_PLATFORM_RPI
  226. bcm_host_deinit();
  227. # endif // BX_PLATFORM_RPI
  228. }
  229. void GlContext::resize(uint32_t _width, uint32_t _height, uint32_t _flags)
  230. {
  231. BX_UNUSED(_width, _height);
  232. # if BX_PLATFORM_ANDROID
  233. EGLint format;
  234. eglGetConfigAttrib(m_display, m_config, EGL_NATIVE_VISUAL_ID, &format);
  235. ANativeWindow_setBuffersGeometry(g_bgfxAndroidWindow, _width, _height, format);
  236. # endif // BX_PLATFORM_ANDROID
  237. bool vsync = !!(_flags&BGFX_RESET_VSYNC);
  238. eglSwapInterval(m_display, vsync ? 1 : 0);
  239. }
  240. bool GlContext::isSwapChainSupported()
  241. {
  242. return BX_ENABLED(0
  243. | BX_PLATFORM_LINUX
  244. | BX_PLATFORM_WINDOWS
  245. );
  246. }
  247. SwapChainGL* GlContext::createSwapChain(void* _nwh)
  248. {
  249. return BX_NEW(g_allocator, SwapChainGL)(m_display, m_config, m_context, (EGLNativeWindowType)_nwh);
  250. }
  251. void GlContext::destroySwapChain(SwapChainGL* _swapChain)
  252. {
  253. BX_DELETE(g_allocator, _swapChain);
  254. }
  255. void GlContext::swap(SwapChainGL* _swapChain)
  256. {
  257. makeCurrent(_swapChain);
  258. if (NULL == _swapChain)
  259. {
  260. eglSwapBuffers(m_display, m_surface);
  261. }
  262. else
  263. {
  264. _swapChain->swapBuffers();
  265. }
  266. }
  267. void GlContext::makeCurrent(SwapChainGL* _swapChain)
  268. {
  269. if (m_current != _swapChain)
  270. {
  271. m_current = _swapChain;
  272. if (NULL == _swapChain)
  273. {
  274. eglMakeCurrent(m_display, m_surface, m_surface, m_context);
  275. }
  276. else
  277. {
  278. _swapChain->makeCurrent();
  279. }
  280. }
  281. }
  282. void GlContext::import()
  283. {
  284. BX_TRACE("Import:");
  285. # if BX_PLATFORM_WINDOWS || BX_PLATFORM_LINUX
  286. void* glesv2 = bx::dlopen("libGLESv2." BX_DL_EXT);
  287. # define GL_EXTENSION(_optional, _proto, _func, _import) \
  288. { \
  289. if (NULL == _func) \
  290. { \
  291. _func = (_proto)bx::dlsym(glesv2, #_import); \
  292. BX_TRACE("\t%p " #_func " (" #_import ")", _func); \
  293. BGFX_FATAL(_optional || NULL != _func, Fatal::UnableToInitialize, "Failed to create OpenGLES context. eglGetProcAddress(\"%s\")", #_import); \
  294. } \
  295. }
  296. # else
  297. # define GL_EXTENSION(_optional, _proto, _func, _import) \
  298. { \
  299. if (NULL == _func) \
  300. { \
  301. _func = (_proto)eglGetProcAddress(#_import); \
  302. BX_TRACE("\t%p " #_func " (" #_import ")", _func); \
  303. BGFX_FATAL(_optional || NULL != _func, Fatal::UnableToInitialize, "Failed to create OpenGLES context. eglGetProcAddress(\"%s\")", #_import); \
  304. } \
  305. }
  306. # endif // BX_PLATFORM_
  307. # include "glimports.h"
  308. }
  309. } /* namespace gl */ } // namespace bgfx
  310. # endif // BGFX_USE_EGL
  311. #endif // (BGFX_CONFIG_RENDERER_OPENGLES || BGFX_CONFIG_RENDERER_OPENGL)