summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/bgfx/src/glcontext_html5.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/bgfx/src/glcontext_html5.cpp')
-rw-r--r--3rdparty/bgfx/src/glcontext_html5.cpp240
1 files changed, 240 insertions, 0 deletions
diff --git a/3rdparty/bgfx/src/glcontext_html5.cpp b/3rdparty/bgfx/src/glcontext_html5.cpp
new file mode 100644
index 00000000000..cce0f299da8
--- /dev/null
+++ b/3rdparty/bgfx/src/glcontext_html5.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
+ */
+
+#include "bgfx_p.h"
+
+#if BGFX_CONFIG_RENDERER_OPENGLES
+# include "renderer_gl.h"
+
+# if BGFX_USE_HTML5
+
+# include "emscripten.h"
+
+// from emscripten gl.c, because we're not going to go
+// through egl
+extern "C" void* emscripten_GetProcAddress(const char *name_);
+extern "C" void* emscripten_webgl1_get_proc_address(const char *name_);
+extern "C" void* emscripten_webgl2_get_proc_address(const char *name_);
+
+namespace bgfx { namespace gl
+{
+
+# define GL_IMPORT(_optional, _proto, _func, _import) _proto _func = NULL
+# include "glimports.h"
+
+ static EmscriptenWebGLContextAttributes s_attrs;
+
+ struct SwapChainGL
+ {
+ SwapChainGL(int _context, const char* _canvas)
+ : m_context(_context)
+ {
+ m_canvas = (char*)BX_ALLOC(g_allocator, strlen(_canvas) + 1);
+ strcpy(m_canvas, _canvas);
+
+ makeCurrent();
+ GL_CHECK(glClearColor(0.0f, 0.0f, 0.0f, 0.0f) );
+ GL_CHECK(glClear(GL_COLOR_BUFFER_BIT) );
+ swapBuffers();
+ GL_CHECK(glClear(GL_COLOR_BUFFER_BIT) );
+ swapBuffers();
+ }
+
+ ~SwapChainGL()
+ {
+ EMSCRIPTEN_CHECK(emscripten_webgl_destroy_context(m_context) );
+ BX_FREE(g_allocator, m_canvas);
+ }
+
+ void makeCurrent()
+ {
+ EMSCRIPTEN_CHECK(emscripten_webgl_make_context_current(m_context) );
+ }
+
+ void swapBuffers()
+ {
+ // There is no swapBuffers equivalent. A swap happens whenever control is returned back
+ // to the browser.
+ }
+
+ int m_context;
+ char* m_canvas;
+ };
+
+ void GlContext::create(uint32_t _width, uint32_t _height, uint32_t /*_flags*/)
+ {
+ // assert?
+ if (m_primary != NULL)
+ return;
+
+ const char* canvas = (const char*) g_platformData.nwh;
+
+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE) g_platformData.context;
+ if (context > 0)
+ {
+ if (emscripten_webgl_get_context_attributes(context, &s_attrs) >= 0)
+ {
+ import(s_attrs.majorVersion);
+ m_primary = BX_NEW(g_allocator, SwapChainGL)(context, canvas);
+ }
+ else
+ {
+ BX_TRACE("Invalid WebGL context. (Canvas handle: '%s', context handle: %d)", canvas, context);
+ }
+ }
+ else
+ {
+ m_primary = createSwapChain((void*)canvas, (int)_width, (int)_height);
+ }
+
+ if (0 != _width
+ && 0 != _height)
+ {
+ EMSCRIPTEN_CHECK(emscripten_set_canvas_element_size(canvas, (int)_width, (int)_height) );
+ }
+
+ makeCurrent(m_primary);
+ }
+
+ void GlContext::destroy()
+ {
+ if (m_primary)
+ {
+ if (m_current == m_primary)
+ {
+ m_current = NULL;
+ }
+
+ BX_DELETE(g_allocator, m_primary);
+ m_primary = NULL;
+ }
+ }
+
+ void GlContext::resize(uint32_t _width, uint32_t _height, uint32_t /* _flags */)
+ {
+ if (m_primary == NULL)
+ {
+ return;
+ }
+
+ EMSCRIPTEN_CHECK(emscripten_set_canvas_element_size(m_primary->m_canvas, (int) _width, (int) _height) );
+ }
+
+ SwapChainGL* GlContext::createSwapChain(void* _nwh, int _width, int _height)
+ {
+ emscripten_webgl_init_context_attributes(&s_attrs);
+ BX_UNUSED(_width, _height);
+
+ // Work around bug https://bugs.chromium.org/p/chromium/issues/detail?id=1045643 in Chrome
+ // by having alpha always enabled.
+ s_attrs.alpha = true;
+ s_attrs.premultipliedAlpha = false;
+ s_attrs.depth = true;
+ s_attrs.stencil = true;
+ s_attrs.enableExtensionsByDefault = true;
+ s_attrs.antialias = false;
+
+ s_attrs.minorVersion = 0;
+ const char* canvas = (const char*) _nwh;
+ int32_t error = 0;
+
+ for (int version = 2; version >= 1; --version)
+ {
+ s_attrs.majorVersion = version;
+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(canvas, &s_attrs);
+
+ if (context > 0)
+ {
+ EMSCRIPTEN_CHECK(emscripten_webgl_make_context_current(context) );
+
+ SwapChainGL* swapChain = BX_NEW(g_allocator, SwapChainGL)(context, canvas);
+
+ import(version);
+
+ return swapChain;
+ }
+
+ error = (int32_t)context;
+ }
+
+ BX_TRACE("Failed to create WebGL context. (Canvas handle: '%s', last attempt error %d)", canvas, error);
+ BX_UNUSED(error);
+
+ return NULL;
+ }
+
+ uint64_t GlContext::getCaps() const
+ {
+ return BGFX_CAPS_SWAP_CHAIN;
+ }
+
+ void GlContext::destroySwapChain(SwapChainGL* _swapChain)
+ {
+ BX_DELETE(g_allocator, _swapChain);
+ }
+
+ void GlContext::swap(SwapChainGL* /* _swapChain */)
+ {
+ }
+
+ void GlContext::makeCurrent(SwapChainGL* _swapChain)
+ {
+ if (m_current != _swapChain)
+ {
+ m_current = _swapChain;
+
+ if (NULL == _swapChain)
+ {
+ if (NULL != m_primary)
+ {
+ m_primary->makeCurrent();
+ }
+ }
+ else
+ {
+ _swapChain->makeCurrent();
+ }
+ }
+ }
+
+ template<typename Fn>
+ static Fn getProcAddress(int _version, const char* _name)
+ {
+ Fn func = reinterpret_cast<Fn>(emscripten_webgl1_get_proc_address(_name) );
+ if (NULL == func && _version >= 2)
+ {
+ func = reinterpret_cast<Fn>(emscripten_webgl2_get_proc_address(_name) );
+ }
+
+ return func;
+ }
+
+ void GlContext::import(int _webGLVersion)
+ {
+ BX_TRACE("Import:");
+
+# define GL_EXTENSION(_optional, _proto, _func, _import) \
+ { \
+ if (NULL == _func) \
+ { \
+ _func = getProcAddress<_proto>(_webGLVersion, #_import); \
+ BX_TRACE("\t%p " #_func " (" #_import ")", _func); \
+ BGFX_FATAL(_optional || NULL != _func, Fatal::UnableToInitialize \
+ , "Failed to create WebGL/OpenGLES context. GetProcAddress(\"%s\")" \
+ , #_import \
+ ); \
+ } \
+ }
+
+# include "glimports.h"
+
+# undef GL_EXTENSION
+
+ }
+
+} /* namespace gl */ } // namespace bgfx
+
+# endif // BGFX_USE_EGL
+#endif // (BGFX_CONFIG_RENDERER_OPENGLES || BGFX_CONFIG_RENDERER_OPENGL)