glcontext_egl.cpp 13 KB

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