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();
std::unique_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) const;
std::shared_ptr<GL::Context> CreateContext(GL::ContextParams params, WindowHandle handle) const;
const RenderDeviceInfo& GetDeviceInfo() const override;
const RenderDeviceFeatures& GetEnabledFeatures() const override;
@ -62,7 +62,7 @@ namespace Nz
private:
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;
RenderDeviceInfo m_deviceInfo;
GL::Loader& m_loader;

View File

@ -45,7 +45,7 @@ namespace Nz
std::optional<OpenGLRenderPass> m_renderPass;
std::size_t m_currentFrame;
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;
Vector2ui m_size;
bool m_sizeInvalidated;

View File

@ -25,8 +25,8 @@ namespace Nz::GL
EGLLoader(const Renderer::Config& config);
~EGLLoader();
std::unique_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, 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;
ContextType GetPreferredContextType() const override;

View File

@ -31,8 +31,8 @@ namespace Nz::GL
Loader() = default;
virtual ~Loader();
virtual std::unique_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, 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;

View File

@ -102,7 +102,7 @@ namespace Nz::GL
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() = default;
std::unique_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, 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;

View File

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

View File

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

View File

@ -21,8 +21,8 @@ namespace Nz::GL
friend SymbolLoader;
public:
std::unique_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, 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;

View File

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

View File

@ -147,14 +147,11 @@ namespace Nz::GL
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)
return GL_DRAW_FRAMEBUFFER;
else if (m_state.boundReadFBO == fbo)
return GL_READ_FRAMEBUFFER;
else
#endif
{
if (!SetCurrentContext(this))
throw std::runtime_error("failed to activate context");
@ -169,10 +166,7 @@ namespace Nz::GL
void Context::BindFramebuffer(FramebufferTarget target, GLuint fbo) const
{
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)
#endif
{
if (!SetCurrentContext(this))
throw std::runtime_error("failed to activate context");

View File

@ -133,14 +133,14 @@ namespace Nz::GL
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
// 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
context = std::make_unique<EGLContextBase>(device, *this);
context = std::make_shared<EGLContextBase>(device, *this);
#endif
if (!context->Create(params, static_cast<EGLContextBase*>(shareContext)))
@ -158,9 +158,9 @@ namespace Nz::GL
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)
{
case WindowBackend::Invalid:
@ -169,19 +169,19 @@ namespace Nz::GL
case WindowBackend::X11:
#ifdef NAZARA_PLATFORM_LINUX
context = std::make_unique<EGLContextX11>(device, *this);
context = std::make_shared<EGLContextX11>(device, *this);
#endif
break;
case WindowBackend::Windows:
#ifdef NAZARA_PLATFORM_WINDOWS
context = std::make_unique<EGLContextWin32>(device, *this);
context = std::make_shared<EGLContextWin32>(device, *this);
#endif
break;
case WindowBackend::Wayland:
#ifdef NAZARA_PLATFORM_LINUX
context = std::make_unique<EGLContextWayland>(device, *this);
context = std::make_shared<EGLContextWayland>(device, *this);
#endif
break;
}

View File

@ -93,9 +93,9 @@ namespace Nz::GL
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)))
{
NazaraError("failed to create context");
@ -111,9 +111,9 @@ namespace Nz::GL
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)))
{
NazaraError("failed to create context");

View File

@ -25,55 +25,6 @@ namespace Nz::GL
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;
emscripten_webgl_init_context_attributes(&configAttributes);
@ -93,23 +44,38 @@ namespace Nz::GL
configAttributes.renderViaOffscreenBackBuffer = 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)
{
if(s_handleCounter > 0)
{
s_handleCounter++;
return true;
}
if (shareContext)
{
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.minorVersion = version.minor;
s_handle = emscripten_webgl_create_context("canvas", &config);
if (s_handle > 0)
m_handle = emscripten_webgl_create_context("canvas", &config);
if (m_handle > 0)
{
break;
}
@ -158,15 +124,13 @@ namespace Nz::GL
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;
}
LoadExt();
s_handleCounter++;
return true;
}
@ -197,7 +161,7 @@ namespace Nz::GL
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)
{
NazaraError("failed to activate context");
@ -226,6 +190,8 @@ namespace Nz::GL
return false;
char* extensionString = emscripten_webgl_get_supported_extensions();
CallOnExit releaseStr([&] { free(extensionString); });
if (extensionString)
{
SplitString(extensionString, " ", [&](std::string_view extension)
@ -234,20 +200,14 @@ namespace Nz::GL
std::string ext(extension);
emscripten_webgl_enable_extension(s_handle, ext.c_str());
emscripten_webgl_enable_extension(m_handle, ext.c_str());
return true;
});
}
free(extensionString);
return true;
}
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE WebContext::s_handle = 0;
size_t WebContext::s_handleCounter = 0;
}
#if defined(NAZARA_PLATFORM_WINDOWS)

View File

@ -43,9 +43,9 @@ namespace Nz::GL
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)))
{
@ -62,25 +62,15 @@ namespace Nz::GL
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;
switch (handle.type)
{
case WindowBackend::Invalid:
break;
case WindowBackend::Web:
context = std::make_unique<WebContext>(device, *this);
break;
}
if (!context)
if (handle.type != WindowBackend::Web)
{
NazaraError("unsupported window type");
return {};
}
std::shared_ptr<WebContext> context = std::make_shared<WebContext>(device, *this);
if (!context->Create(params, handle, static_cast<WebContext*>(shareContext)))
{
NazaraError("failed to create context");
@ -103,15 +93,7 @@ namespace Nz::GL
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 nullptr;
}
const char* WebLoader::TranslateError(EMSCRIPTEN_RESULT errorId)

View File

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