glcontext_html5.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * Copyright 2011-2019 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. 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. m_current = NULL;
  69. BX_DELETE(g_allocator, m_primary);
  70. m_primary = NULL;
  71. }
  72. }
  73. void GlContext::resize(uint32_t _width, uint32_t _height, uint32_t /* _flags */)
  74. {
  75. if (m_primary == NULL)
  76. return;
  77. emscripten_set_canvas_element_size(m_primary->m_canvas, (int) _width, (int) _height);
  78. }
  79. SwapChainGL* GlContext::createSwapChain(void* _nwh)
  80. {
  81. emscripten_webgl_init_context_attributes(&s_attrs);
  82. s_attrs.alpha = false;
  83. s_attrs.depth = true;
  84. s_attrs.stencil = true;
  85. s_attrs.enableExtensionsByDefault = true;
  86. // let emscripten figure out the best WebGL context to create
  87. // TODO this isn't necessarily the right thing, I don't think the code actually does the fallback like it should
  88. s_attrs.majorVersion = 0;
  89. s_attrs.majorVersion = 0;
  90. const char* canvas = (const char*) _nwh;
  91. int context = emscripten_webgl_create_context(canvas, &s_attrs);
  92. if (context <= 0)
  93. {
  94. BX_TRACE("Failed to create WebGL context. (Canvas handle: '%s', error %d)", canvas, (int)context);
  95. return NULL;
  96. }
  97. int result = emscripten_webgl_make_context_current(context);
  98. if (EMSCRIPTEN_RESULT_SUCCESS != result)
  99. {
  100. BX_TRACE("emscripten_webgl_make_context_current failed (%d)", result);
  101. return NULL;
  102. }
  103. SwapChainGL* swapChain = BX_NEW(g_allocator, SwapChainGL)(context, canvas);
  104. import(1);
  105. return swapChain;
  106. }
  107. uint64_t GlContext::getCaps() const
  108. {
  109. return BGFX_CAPS_SWAP_CHAIN;
  110. }
  111. void GlContext::destroySwapChain(SwapChainGL* _swapChain)
  112. {
  113. BX_DELETE(g_allocator, _swapChain);
  114. }
  115. void GlContext::swap(SwapChainGL* /* _swapChain */)
  116. {
  117. }
  118. void GlContext::makeCurrent(SwapChainGL* _swapChain)
  119. {
  120. if (m_current != _swapChain)
  121. {
  122. m_current = _swapChain;
  123. if (NULL == _swapChain)
  124. {
  125. if (NULL != m_primary)
  126. {
  127. m_primary->makeCurrent();
  128. }
  129. }
  130. else
  131. {
  132. _swapChain->makeCurrent();
  133. }
  134. }
  135. }
  136. void GlContext::import(int webGLVersion)
  137. {
  138. BX_TRACE("Import:");
  139. # define GL_EXTENSION(_optional, _proto, _func, _import) \
  140. { \
  141. if (NULL == _func) \
  142. { \
  143. _func = (_proto)emscripten_webgl1_get_proc_address(#_import); \
  144. if (!_func && webGLVersion >= 2) \
  145. _func = (_proto)emscripten_webgl2_get_proc_address(#_import); \
  146. BX_TRACE("\t%p " #_func " (" #_import ")", _func); \
  147. BGFX_FATAL(_optional || NULL != _func, Fatal::UnableToInitialize, "Failed to create WebGL/OpenGLES context. GetProcAddress(\"%s\")", #_import); \
  148. } \
  149. }
  150. # include "glimports.h"
  151. }
  152. } /* namespace gl */ } // namespace bgfx
  153. # endif // BGFX_USE_EGL
  154. #endif // (BGFX_CONFIG_RENDERER_OPENGLES || BGFX_CONFIG_RENDERER_OPENGL)