glcontext_egl.cpp 16 KB

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