glcontext_html5.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. * Copyright 2011-2020 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
  7. # include "renderer_gl.h"
  8. # if BGFX_USE_HTML5
  9. #include <emscripten/emscripten.h>
  10. #include <emscripten/html5.h>
  11. // from emscripten gl.c, because we're not going to go
  12. // through egl
  13. extern "C" void* emscripten_GetProcAddress(const char *name_);
  14. extern "C" void* emscripten_webgl1_get_proc_address(const char *name_);
  15. extern "C" void* emscripten_webgl2_get_proc_address(const char *name_);
  16. namespace bgfx { namespace gl
  17. {
  18. # define GL_IMPORT(_optional, _proto, _func, _import) _proto _func = NULL
  19. # include "glimports.h"
  20. static EmscriptenWebGLContextAttributes s_attrs;
  21. struct SwapChainGL
  22. {
  23. SwapChainGL(int _context, const char* _canvas)
  24. : m_context(_context)
  25. {
  26. m_canvas = (char*)BX_ALLOC(g_allocator, strlen(_canvas) + 1);
  27. strcpy(m_canvas, _canvas);
  28. makeCurrent();
  29. GL_CHECK(glClearColor(0.0f, 0.0f, 0.0f, 0.0f) );
  30. GL_CHECK(glClear(GL_COLOR_BUFFER_BIT) );
  31. swapBuffers();
  32. GL_CHECK(glClear(GL_COLOR_BUFFER_BIT) );
  33. swapBuffers();
  34. }
  35. ~SwapChainGL()
  36. {
  37. emscripten_webgl_destroy_context(m_context);
  38. BX_FREE(g_allocator, m_canvas);
  39. }
  40. void makeCurrent()
  41. {
  42. emscripten_webgl_make_context_current(m_context);
  43. }
  44. void swapBuffers()
  45. {
  46. // There is no swapBuffers equivalent. A swap happens whenever control is returned back
  47. // to the browser.
  48. }
  49. int m_context;
  50. char* m_canvas;
  51. };
  52. void GlContext::create(uint32_t _width, uint32_t _height)
  53. {
  54. // assert?
  55. if (m_primary != NULL)
  56. return;
  57. const char* canvas = (const char*) g_platformData.nwh; // if 0, Module.canvas is used
  58. m_primary = createSwapChain((void*)canvas);
  59. if (_width && _height)
  60. emscripten_set_canvas_element_size(canvas, (int)_width, (int)_height);
  61. makeCurrent(m_primary);
  62. }
  63. void GlContext::destroy()
  64. {
  65. if (m_primary)
  66. {
  67. if (m_current == m_primary)
  68. {
  69. m_current = NULL;
  70. }
  71. BX_DELETE(g_allocator, m_primary);
  72. m_primary = NULL;
  73. }
  74. }
  75. void GlContext::resize(uint32_t _width, uint32_t _height, uint32_t /* _flags */)
  76. {
  77. if (m_primary == NULL)
  78. {
  79. return;
  80. }
  81. emscripten_set_canvas_element_size(m_primary->m_canvas, (int) _width, (int) _height);
  82. }
  83. SwapChainGL* GlContext::createSwapChain(void* _nwh)
  84. {
  85. emscripten_webgl_init_context_attributes(&s_attrs);
  86. s_attrs.alpha = false;
  87. s_attrs.depth = true;
  88. s_attrs.stencil = true;
  89. s_attrs.enableExtensionsByDefault = true;
  90. // let emscripten figure out the best WebGL context to create
  91. s_attrs.majorVersion = 0;
  92. s_attrs.majorVersion = 0;
  93. const char* canvas = (const char*) _nwh;
  94. int context = emscripten_webgl_create_context(canvas, &s_attrs);
  95. if (context <= 0)
  96. {
  97. BX_TRACE("Failed to create WebGL context. (Canvas handle: '%s', error %d)", canvas, (int)context);
  98. return NULL;
  99. }
  100. int result = emscripten_webgl_make_context_current(context);
  101. if (EMSCRIPTEN_RESULT_SUCCESS != result)
  102. {
  103. BX_TRACE("emscripten_webgl_make_context_current failed (%d)", result);
  104. return NULL;
  105. }
  106. SwapChainGL* swapChain = BX_NEW(g_allocator, SwapChainGL)(context, canvas);
  107. import(1);
  108. return swapChain;
  109. }
  110. uint64_t GlContext::getCaps() const
  111. {
  112. return BGFX_CAPS_SWAP_CHAIN;
  113. }
  114. void GlContext::destroySwapChain(SwapChainGL* _swapChain)
  115. {
  116. BX_DELETE(g_allocator, _swapChain);
  117. }
  118. void GlContext::swap(SwapChainGL* /* _swapChain */)
  119. {
  120. }
  121. void GlContext::makeCurrent(SwapChainGL* _swapChain)
  122. {
  123. if (m_current != _swapChain)
  124. {
  125. m_current = _swapChain;
  126. if (NULL == _swapChain)
  127. {
  128. if (NULL != m_primary)
  129. {
  130. m_primary->makeCurrent();
  131. }
  132. }
  133. else
  134. {
  135. _swapChain->makeCurrent();
  136. }
  137. }
  138. }
  139. void GlContext::import(int webGLVersion)
  140. {
  141. BX_TRACE("Import:");
  142. # define GL_EXTENSION(_optional, _proto, _func, _import) \
  143. { \
  144. if (NULL == _func) \
  145. { \
  146. _func = (_proto)emscripten_webgl1_get_proc_address(#_import); \
  147. if (!_func && webGLVersion >= 2) \
  148. _func = (_proto)emscripten_webgl2_get_proc_address(#_import); \
  149. BX_TRACE("\t%p " #_func " (" #_import ")", _func); \
  150. BGFX_FATAL(_optional || NULL != _func, Fatal::UnableToInitialize, "Failed to create WebGL/OpenGLES context. GetProcAddress(\"%s\")", #_import); \
  151. } \
  152. }
  153. # include "glimports.h"
  154. }
  155. } /* namespace gl */ } // namespace bgfx
  156. # endif // BGFX_USE_EGL
  157. #endif // (BGFX_CONFIG_RENDERER_OPENGLES || BGFX_CONFIG_RENDERER_OPENGL)