OpenGLRenderer: Use a single context with WebGL

This commit is contained in:
SirLynix 2022-12-06 09:06:38 +01:00 committed by Jérôme Leclercq
parent ea5c5240fc
commit 5b3703347f
16 changed files with 68 additions and 136 deletions

View File

@ -29,8 +29,8 @@ namespace Nz
OpenGLDevice(OpenGLDevice&&) = delete; ///TODO? OpenGLDevice(OpenGLDevice&&) = delete; ///TODO?
~OpenGLDevice(); ~OpenGLDevice();
std::unique_ptr<GL::Context> CreateContext(GL::ContextParams params) const; std::shared_ptr<GL::Context> CreateContext(GL::ContextParams params) const;
std::unique_ptr<GL::Context> CreateContext(GL::ContextParams params, WindowHandle handle) const; std::shared_ptr<GL::Context> CreateContext(GL::ContextParams params, WindowHandle handle) const;
const RenderDeviceInfo& GetDeviceInfo() const override; const RenderDeviceInfo& GetDeviceInfo() const override;
const RenderDeviceFeatures& GetEnabledFeatures() const override; const RenderDeviceFeatures& GetEnabledFeatures() const override;
@ -62,7 +62,7 @@ namespace Nz
private: private:
inline void NotifyContextDestruction(const GL::Context& context) const; inline void NotifyContextDestruction(const GL::Context& context) const;
std::unique_ptr<GL::Context> m_referenceContext; std::shared_ptr<GL::Context> m_referenceContext;
mutable std::unordered_set<const GL::Context*> m_contexts; mutable std::unordered_set<const GL::Context*> m_contexts;
RenderDeviceInfo m_deviceInfo; RenderDeviceInfo m_deviceInfo;
GL::Loader& m_loader; GL::Loader& m_loader;

View File

@ -45,7 +45,7 @@ namespace Nz
std::optional<OpenGLRenderPass> m_renderPass; std::optional<OpenGLRenderPass> m_renderPass;
std::size_t m_currentFrame; std::size_t m_currentFrame;
std::vector<std::unique_ptr<OpenGLRenderImage>> m_renderImage; std::vector<std::unique_ptr<OpenGLRenderImage>> m_renderImage;
std::unique_ptr<GL::Context> m_context; std::shared_ptr<GL::Context> m_context;
OpenGLWindowFramebuffer m_framebuffer; OpenGLWindowFramebuffer m_framebuffer;
Vector2ui m_size; Vector2ui m_size;
bool m_sizeInvalidated; bool m_sizeInvalidated;

View File

@ -25,8 +25,8 @@ namespace Nz::GL
EGLLoader(const Renderer::Config& config); EGLLoader(const Renderer::Config& config);
~EGLLoader(); ~EGLLoader();
std::unique_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, Context* shareContext) const override; std::shared_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, Context* shareContext) const override;
std::unique_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, WindowHandle handle, Context* shareContext) const override; std::shared_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, WindowHandle handle, Context* shareContext) const override;
inline EGLDisplay GetDefaultDisplay() const; inline EGLDisplay GetDefaultDisplay() const;
ContextType GetPreferredContextType() const override; ContextType GetPreferredContextType() const override;

View File

@ -31,8 +31,8 @@ namespace Nz::GL
Loader() = default; Loader() = default;
virtual ~Loader(); virtual ~Loader();
virtual std::unique_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, Context* shareContext = nullptr) const = 0; virtual std::shared_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, Context* shareContext = nullptr) const = 0;
virtual std::unique_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, WindowHandle handle, Context* shareContext = nullptr) const = 0; virtual std::shared_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, WindowHandle handle, Context* shareContext = nullptr) const = 0;
virtual ContextType GetPreferredContextType() const = 0; virtual ContextType GetPreferredContextType() const = 0;

View File

@ -102,7 +102,7 @@ namespace Nz::GL
inline void Shader::DestroyHelper(OpenGLDevice& /*device*/, const Context& context, GLuint objectId) inline void Shader::DestroyHelper(OpenGLDevice& /*device*/, const Context& context, GLuint objectId)
{ {
// context.glDeleteShader(objectId); context.glDeleteShader(objectId);
} }
} }

View File

@ -24,8 +24,8 @@ namespace Nz::GL
WGLLoader(const Renderer::Config& config); WGLLoader(const Renderer::Config& config);
~WGLLoader() = default; ~WGLLoader() = default;
std::unique_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, Context* shareContext) const override; std::shared_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, Context* shareContext) const override;
std::unique_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, WindowHandle handle, Context* shareContext) const override; std::shared_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, WindowHandle handle, Context* shareContext) const override;
ContextType GetPreferredContextType() const override; ContextType GetPreferredContextType() const override;

View File

@ -65,9 +65,7 @@ namespace Nz::GL
Fallback fallbacks; //< m_ omitted Fallback fallbacks; //< m_ omitted
std::unordered_set<std::string> m_supportedPlatformExtensions; std::unordered_set<std::string> m_supportedPlatformExtensions;
static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE s_handle; EMSCRIPTEN_WEBGL_CONTEXT_HANDLE m_handle;
static size_t s_handleCounter;
bool m_ownsDisplay;
}; };
} }

View File

@ -10,8 +10,7 @@ namespace Nz::GL
inline WebContext::WebContext(const OpenGLDevice* device, const WebLoader& loader) : inline WebContext::WebContext(const OpenGLDevice* device, const WebLoader& loader) :
Context(device), Context(device),
m_loader(loader), m_loader(loader),
//m_handle(0), m_handle(0)
m_ownsDisplay(false)
{ {
} }

View File

@ -21,8 +21,8 @@ namespace Nz::GL
friend SymbolLoader; friend SymbolLoader;
public: public:
std::unique_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, Context* shareContext) const override; std::shared_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, Context* shareContext) const override;
std::unique_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, WindowHandle handle, Context* shareContext) const override; std::shared_ptr<Context> CreateContext(const OpenGLDevice* device, const ContextParams& params, WindowHandle handle, Context* shareContext) const override;
ContextType GetPreferredContextType() const override; ContextType GetPreferredContextType() const override;

View File

@ -136,10 +136,7 @@ namespace Nz
std::strcpy(m_cpuBrandString.data(), "CPU from unknown vendor - cpuid not supported"); std::strcpy(m_cpuBrandString.data(), "CPU from unknown vendor - cpuid not supported");
if (!HardwareInfoImpl::IsCpuidSupported()) if (!HardwareInfoImpl::IsCpuidSupported())
{
NazaraWarning("Cpuid is not supported");
return; return;
}
// To begin, we get the id of the constructor and the id of maximal functions supported by the CPUID // To begin, we get the id of the constructor and the id of maximal functions supported by the CPUID
std::array<UInt32, 4> registers; std::array<UInt32, 4> registers;

View File

@ -147,14 +147,11 @@ namespace Nz::GL
GLenum Context::BindFramebuffer(GLuint fbo) const GLenum Context::BindFramebuffer(GLuint fbo) const
{ {
// it looks like emscripten wants us to rebind the FBO everytime
#ifndef NAZARA_PLATFORM_WEB
if (m_state.boundDrawFBO == fbo) if (m_state.boundDrawFBO == fbo)
return GL_DRAW_FRAMEBUFFER; return GL_DRAW_FRAMEBUFFER;
else if (m_state.boundReadFBO == fbo) else if (m_state.boundReadFBO == fbo)
return GL_READ_FRAMEBUFFER; return GL_READ_FRAMEBUFFER;
else else
#endif
{ {
if (!SetCurrentContext(this)) if (!SetCurrentContext(this))
throw std::runtime_error("failed to activate context"); throw std::runtime_error("failed to activate context");
@ -169,10 +166,7 @@ namespace Nz::GL
void Context::BindFramebuffer(FramebufferTarget target, GLuint fbo) const void Context::BindFramebuffer(FramebufferTarget target, GLuint fbo) const
{ {
auto& currentFbo = (target == FramebufferTarget::Draw) ? m_state.boundDrawFBO : m_state.boundReadFBO; auto& currentFbo = (target == FramebufferTarget::Draw) ? m_state.boundDrawFBO : m_state.boundReadFBO;
// it looks like emscripten wants us to rebind the FBO everytime
#ifndef NAZARA_PLATFORM_WEB
if (currentFbo != fbo) if (currentFbo != fbo)
#endif
{ {
if (!SetCurrentContext(this)) if (!SetCurrentContext(this))
throw std::runtime_error("failed to activate context"); throw std::runtime_error("failed to activate context");

View File

@ -133,14 +133,14 @@ namespace Nz::GL
eglTerminate(m_defaultDisplay); eglTerminate(m_defaultDisplay);
} }
std::unique_ptr<Context> EGLLoader::CreateContext(const OpenGLDevice* device, const ContextParams& params, Context* shareContext) const std::shared_ptr<Context> EGLLoader::CreateContext(const OpenGLDevice* device, const ContextParams& params, Context* shareContext) const
{ {
std::unique_ptr<EGLContextBase> context; std::shared_ptr<EGLContextBase> context;
#ifdef NAZARA_PLATFORM_WINDOWS #ifdef NAZARA_PLATFORM_WINDOWS
// On Windows context sharing seems to work only with window contexts // On Windows context sharing seems to work only with window contexts
context = std::make_unique<EGLContextWin32>(device, *this); context = std::make_shared<EGLContextWin32>(device, *this);
#else #else
context = std::make_unique<EGLContextBase>(device, *this); context = std::make_shared<EGLContextBase>(device, *this);
#endif #endif
if (!context->Create(params, static_cast<EGLContextBase*>(shareContext))) if (!context->Create(params, static_cast<EGLContextBase*>(shareContext)))
@ -158,9 +158,9 @@ namespace Nz::GL
return context; return context;
} }
std::unique_ptr<Context> EGLLoader::CreateContext([[maybe_unused]] const OpenGLDevice* device, const ContextParams& params, WindowHandle handle, Context* shareContext) const std::shared_ptr<Context> EGLLoader::CreateContext([[maybe_unused]] const OpenGLDevice* device, const ContextParams& params, WindowHandle handle, Context* shareContext) const
{ {
std::unique_ptr<EGLContextBase> context; std::shared_ptr<EGLContextBase> context;
switch (handle.type) switch (handle.type)
{ {
case WindowBackend::Invalid: case WindowBackend::Invalid:
@ -169,19 +169,19 @@ namespace Nz::GL
case WindowBackend::X11: case WindowBackend::X11:
#ifdef NAZARA_PLATFORM_LINUX #ifdef NAZARA_PLATFORM_LINUX
context = std::make_unique<EGLContextX11>(device, *this); context = std::make_shared<EGLContextX11>(device, *this);
#endif #endif
break; break;
case WindowBackend::Windows: case WindowBackend::Windows:
#ifdef NAZARA_PLATFORM_WINDOWS #ifdef NAZARA_PLATFORM_WINDOWS
context = std::make_unique<EGLContextWin32>(device, *this); context = std::make_shared<EGLContextWin32>(device, *this);
#endif #endif
break; break;
case WindowBackend::Wayland: case WindowBackend::Wayland:
#ifdef NAZARA_PLATFORM_LINUX #ifdef NAZARA_PLATFORM_LINUX
context = std::make_unique<EGLContextWayland>(device, *this); context = std::make_shared<EGLContextWayland>(device, *this);
#endif #endif
break; break;
} }

View File

@ -93,9 +93,9 @@ namespace Nz::GL
throw std::runtime_error("failed to create or initialize base context"); throw std::runtime_error("failed to create or initialize base context");
} }
std::unique_ptr<Context> WGLLoader::CreateContext(const OpenGLDevice* device, const ContextParams& params, Context* shareContext) const std::shared_ptr<Context> WGLLoader::CreateContext(const OpenGLDevice* device, const ContextParams& params, Context* shareContext) const
{ {
auto context = std::make_unique<WGLContext>(device, *this); auto context = std::make_shared<WGLContext>(device, *this);
if (!context->Create(&m_baseContext, params, static_cast<WGLContext*>(shareContext))) if (!context->Create(&m_baseContext, params, static_cast<WGLContext*>(shareContext)))
{ {
NazaraError("failed to create context"); NazaraError("failed to create context");
@ -111,9 +111,9 @@ namespace Nz::GL
return context; return context;
} }
std::unique_ptr<Context> WGLLoader::CreateContext(const OpenGLDevice* device, const ContextParams& params, WindowHandle handle, Context* shareContext) const std::shared_ptr<Context> WGLLoader::CreateContext(const OpenGLDevice* device, const ContextParams& params, WindowHandle handle, Context* shareContext) const
{ {
auto context = std::make_unique<WGLContext>(device, *this); auto context = std::make_shared<WGLContext>(device, *this);
if (!context->Create(&m_baseContext, params, handle, static_cast<WGLContext*>(shareContext))) if (!context->Create(&m_baseContext, params, handle, static_cast<WGLContext*>(shareContext)))
{ {
NazaraError("failed to create context"); NazaraError("failed to create context");

View File

@ -25,55 +25,6 @@ namespace Nz::GL
m_params = params; m_params = params;
std::size_t configCount;
std::array<EmscriptenWebGLContextAttributes, 0xFF> configs;
if (!ChooseConfig(configs.data(), configs.size(), &configCount))
return false;
std::size_t configIndex = 0;
return CreateInternal(configs[configIndex], shareContext);
}
bool WebContext::Create(const ContextParams& params, WindowHandle /*window*/, const WebContext* /*shareContext*/)
{
/*NazaraError("Unexpected context creation call");
return false;*/
return Create(params, nullptr);
}
void WebContext::Destroy()
{
if (s_handle > 0)
{
assert(s_handle > 0);
OnContextRelease();
NotifyContextDestruction(this);
s_handleCounter--;
if(s_handleCounter == 0)
{
emscripten_webgl_destroy_context(s_handle);
s_handle = 0;
}
}
}
void WebContext::EnableVerticalSync(bool /*enabled*/)
{
// TODO
}
void WebContext::SwapBuffers()
{
emscripten_webgl_commit_frame();
}
bool WebContext::ChooseConfig(EmscriptenWebGLContextAttributes* configs, std::size_t maxConfigCount, std::size_t* configCount)
{
EmscriptenWebGLContextAttributes configAttributes; EmscriptenWebGLContextAttributes configAttributes;
emscripten_webgl_init_context_attributes(&configAttributes); emscripten_webgl_init_context_attributes(&configAttributes);
@ -93,23 +44,38 @@ namespace Nz::GL
configAttributes.renderViaOffscreenBackBuffer = false; // todo configAttributes.renderViaOffscreenBackBuffer = false; // todo
configAttributes.proxyContextToMainThread = false; // todo configAttributes.proxyContextToMainThread = false; // todo
size_t numConfig = 1; return CreateInternal(configAttributes, shareContext);
}
configs[0] = configAttributes; bool WebContext::Create(const ContextParams& params, WindowHandle /*window*/, const WebContext* /*shareContext*/)
{
return Create(params, nullptr);
}
*configCount = numConfig; void WebContext::Destroy()
{
if (m_handle != 0)
{
OnContextRelease();
NotifyContextDestruction(this);
return true; emscripten_webgl_destroy_context(m_handle);
m_handle = 0;
}
}
void WebContext::EnableVerticalSync(bool /*enabled*/)
{
// TODO
}
void WebContext::SwapBuffers()
{
emscripten_webgl_commit_frame();
} }
bool WebContext::CreateInternal(EmscriptenWebGLContextAttributes config, const WebContext* shareContext) bool WebContext::CreateInternal(EmscriptenWebGLContextAttributes config, const WebContext* shareContext)
{ {
if(s_handleCounter > 0)
{
s_handleCounter++;
return true;
}
if (shareContext) if (shareContext)
{ {
NazaraWarning(std::string("shared contexes are not supported by WebGL but shareContext is not null")); NazaraWarning(std::string("shared contexes are not supported by WebGL but shareContext is not null"));
@ -145,8 +111,8 @@ namespace Nz::GL
config.majorVersion = version.major; config.majorVersion = version.major;
config.minorVersion = version.minor; config.minorVersion = version.minor;
s_handle = emscripten_webgl_create_context("canvas", &config); m_handle = emscripten_webgl_create_context("canvas", &config);
if (s_handle > 0) if (m_handle > 0)
{ {
break; break;
} }
@ -158,15 +124,13 @@ namespace Nz::GL
return false; return false;
} }
if (s_handle <= 0) if (m_handle <= 0)
{ {
NazaraError(std::string("failed to create Web context: ") + WebLoader::TranslateError(static_cast<EMSCRIPTEN_RESULT>(s_handle))); NazaraError(std::string("failed to create Web context: ") + WebLoader::TranslateError(static_cast<EMSCRIPTEN_RESULT>(m_handle)));
return false; return false;
} }
LoadExt(); LoadExt();
s_handleCounter++;
return true; return true;
} }
@ -197,7 +161,7 @@ namespace Nz::GL
bool WebContext::Activate() const bool WebContext::Activate() const
{ {
EMSCRIPTEN_RESULT succeeded = emscripten_webgl_make_context_current(s_handle); EMSCRIPTEN_RESULT succeeded = emscripten_webgl_make_context_current(m_handle);
if (succeeded != EMSCRIPTEN_RESULT_SUCCESS) if (succeeded != EMSCRIPTEN_RESULT_SUCCESS)
{ {
NazaraError("failed to activate context"); NazaraError("failed to activate context");
@ -226,6 +190,8 @@ namespace Nz::GL
return false; return false;
char* extensionString = emscripten_webgl_get_supported_extensions(); char* extensionString = emscripten_webgl_get_supported_extensions();
CallOnExit releaseStr([&] { free(extensionString); });
if (extensionString) if (extensionString)
{ {
SplitString(extensionString, " ", [&](std::string_view extension) SplitString(extensionString, " ", [&](std::string_view extension)
@ -234,20 +200,14 @@ namespace Nz::GL
std::string ext(extension); std::string ext(extension);
emscripten_webgl_enable_extension(s_handle, ext.c_str()); emscripten_webgl_enable_extension(m_handle, ext.c_str());
return true; return true;
}); });
} }
free(extensionString);
return true; return true;
} }
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE WebContext::s_handle = 0;
size_t WebContext::s_handleCounter = 0;
} }
#if defined(NAZARA_PLATFORM_WINDOWS) #if defined(NAZARA_PLATFORM_WINDOWS)

View File

@ -43,9 +43,9 @@ namespace Nz::GL
WebLoader& loader; WebLoader& loader;
}; };
std::unique_ptr<Context> WebLoader::CreateContext(const OpenGLDevice* device, const ContextParams& params, Context* shareContext) const std::shared_ptr<Context> WebLoader::CreateContext(const OpenGLDevice* device, const ContextParams& params, Context* shareContext) const
{ {
std::unique_ptr<WebContext> context = std::make_unique<WebContext>(device, *this); std::shared_ptr<WebContext> context = std::make_shared<WebContext>(device, *this);
if (!context->Create(params, static_cast<WebContext*>(shareContext))) if (!context->Create(params, static_cast<WebContext*>(shareContext)))
{ {
@ -62,25 +62,15 @@ namespace Nz::GL
return context; return context;
} }
std::unique_ptr<Context> WebLoader::CreateContext(const OpenGLDevice* device, const ContextParams& params, WindowHandle handle, Context* shareContext) const std::shared_ptr<Context> WebLoader::CreateContext(const OpenGLDevice* device, const ContextParams& params, WindowHandle handle, Context* shareContext) const
{ {
std::unique_ptr<WebContext> context; if (handle.type != WindowBackend::Web)
switch (handle.type)
{
case WindowBackend::Invalid:
break;
case WindowBackend::Web:
context = std::make_unique<WebContext>(device, *this);
break;
}
if (!context)
{ {
NazaraError("unsupported window type"); NazaraError("unsupported window type");
return {}; return {};
} }
std::shared_ptr<WebContext> context = std::make_shared<WebContext>(device, *this);
if (!context->Create(params, handle, static_cast<WebContext*>(shareContext))) if (!context->Create(params, handle, static_cast<WebContext*>(shareContext)))
{ {
NazaraError("failed to create context"); NazaraError("failed to create context");
@ -103,15 +93,7 @@ namespace Nz::GL
GLFunction WebLoader::LoadFunction(const char* name) const GLFunction WebLoader::LoadFunction(const char* name) const
{ {
/*GLFunction func = reinterpret_cast<GLFunction>(m_WebLib.GetSymbol(name));
if (!func && WebGetProcAddress)
func = reinterpret_cast<GLFunction>(WebGetProcAddress(name));
return func;*/
return reinterpret_cast<GLFunction>(emscripten_webgl_get_proc_address(name)); return reinterpret_cast<GLFunction>(emscripten_webgl_get_proc_address(name));
//return nullptr;
} }
const char* WebLoader::TranslateError(EMSCRIPTEN_RESULT errorId) const char* WebLoader::TranslateError(EMSCRIPTEN_RESULT errorId)

View File

@ -196,6 +196,8 @@ namespace Nz
{ {
#ifdef NAZARA_PLATFORM_WEB #ifdef NAZARA_PLATFORM_WEB
WindowHandle handle; WindowHandle handle;
handle.type = WindowBackend::Web;
return handle; return handle;
#else #else
SDL_SysWMinfo wmInfo; SDL_SysWMinfo wmInfo;