Mercurial > hg > pub > prymula > com
diff DPF-Prymula-audioplugins/dpf/dgl/src/pugl-extra/wasm_gl.c @ 3:84e66ea83026
DPF-Prymula-audioplugins-0.231015-2
author | prymula <prymula76@outlook.com> |
---|---|
date | Mon, 16 Oct 2023 21:53:34 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DPF-Prymula-audioplugins/dpf/dgl/src/pugl-extra/wasm_gl.c Mon Oct 16 21:53:34 2023 +0200 @@ -0,0 +1,228 @@ +// Copyright 2012-2022 David Robillard <d@drobilla.net> +// Copyright 2021-2022 Filipe Coelho <falktx@falktx.com> +// SPDX-License-Identifier: ISC + +#include "../pugl-upstream/src/stub.h" +#include "wasm.h" + +#include "pugl/pugl.h" + +#include <stdio.h> +#include <stdlib.h> + +#include <EGL/egl.h> + +// for performance reasons we can keep a single EGL context always active +#define PUGL_WASM_SINGLE_EGL_CONTEXT + +typedef struct { + EGLDisplay display; + EGLConfig config; + EGLContext context; + EGLSurface surface; +} PuglWasmGlSurface; + +static EGLint +puglWasmGlHintValue(const int value) +{ + return value == PUGL_DONT_CARE ? EGL_DONT_CARE : value; +} + +static int +puglWasmGlGetAttrib(const EGLDisplay display, + const EGLConfig config, + const EGLint attrib) +{ + EGLint value = 0; + eglGetConfigAttrib(display, config, attrib, &value); + return value; +} + +static PuglStatus +puglWasmGlConfigure(PuglView* view) +{ + PuglInternals* const impl = view->impl; + + const EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + + if (display == EGL_NO_DISPLAY) { + return PUGL_CREATE_CONTEXT_FAILED; + } + + int major, minor; + if (eglInitialize(display, &major, &minor) != EGL_TRUE) { + return PUGL_CREATE_CONTEXT_FAILED; + } + + EGLConfig config; + int numConfigs; + + if (eglGetConfigs(display, &config, 1, &numConfigs) != EGL_TRUE || numConfigs != 1) { + eglTerminate(display); + return PUGL_CREATE_CONTEXT_FAILED; + } + + // clang-format off + const EGLint attrs[] = { + /* + GLX_X_RENDERABLE, True, + GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + EGL_SAMPLE_BUFFERS, view->hints[PUGL_MULTI_SAMPLE] ? 1 : 0, + */ + EGL_SAMPLES, puglWasmGlHintValue(view->hints[PUGL_SAMPLES]), + EGL_RED_SIZE, puglWasmGlHintValue(view->hints[PUGL_RED_BITS]), + EGL_GREEN_SIZE, puglWasmGlHintValue(view->hints[PUGL_GREEN_BITS]), + EGL_BLUE_SIZE, puglWasmGlHintValue(view->hints[PUGL_BLUE_BITS]), + EGL_ALPHA_SIZE, puglWasmGlHintValue(view->hints[PUGL_ALPHA_BITS]), + EGL_DEPTH_SIZE, puglWasmGlHintValue(view->hints[PUGL_DEPTH_BITS]), + EGL_STENCIL_SIZE, puglWasmGlHintValue(view->hints[PUGL_STENCIL_BITS]), + EGL_NONE + }; + // clang-format on + + if (eglChooseConfig(display, attrs, &config, 1, &numConfigs) != EGL_TRUE || numConfigs != 1) { + eglTerminate(display); + return PUGL_CREATE_CONTEXT_FAILED; + } + + PuglWasmGlSurface* const surface = + (PuglWasmGlSurface*)calloc(1, sizeof(PuglWasmGlSurface)); + impl->surface = surface; + + surface->display = display; + surface->config = config; + surface->context = EGL_NO_SURFACE; + surface->surface = EGL_NO_CONTEXT; + + view->hints[PUGL_RED_BITS] = + puglWasmGlGetAttrib(display, config, EGL_RED_SIZE); + view->hints[PUGL_GREEN_BITS] = + puglWasmGlGetAttrib(display, config, EGL_GREEN_SIZE); + view->hints[PUGL_BLUE_BITS] = + puglWasmGlGetAttrib(display, config, EGL_BLUE_SIZE); + view->hints[PUGL_ALPHA_BITS] = + puglWasmGlGetAttrib(display, config, EGL_ALPHA_SIZE); + view->hints[PUGL_DEPTH_BITS] = + puglWasmGlGetAttrib(display, config, EGL_DEPTH_SIZE); + view->hints[PUGL_STENCIL_BITS] = + puglWasmGlGetAttrib(display, config, EGL_STENCIL_SIZE); + view->hints[PUGL_SAMPLES] = + puglWasmGlGetAttrib(display, config, EGL_SAMPLES); + + // double-buffering is always enabled for EGL + view->hints[PUGL_DOUBLE_BUFFER] = 1; + + return PUGL_SUCCESS; +} + +PUGL_WARN_UNUSED_RESULT +static PuglStatus +puglWasmGlEnter(PuglView* view, const PuglExposeEvent* PUGL_UNUSED(expose)) +{ + PuglWasmGlSurface* const surface = (PuglWasmGlSurface*)view->impl->surface; + if (!surface || !surface->context || !surface->surface) { + return PUGL_FAILURE; + } + +#ifndef PUGL_WASM_SINGLE_EGL_CONTEXT + return eglMakeCurrent(surface->display, surface->surface, surface->surface, surface->context) ? PUGL_SUCCESS : PUGL_FAILURE; +#else + return PUGL_SUCCESS; +#endif +} + +PUGL_WARN_UNUSED_RESULT +static PuglStatus +puglWasmGlLeave(PuglView* view, const PuglExposeEvent* expose) +{ + PuglWasmGlSurface* const surface = (PuglWasmGlSurface*)view->impl->surface; + + if (expose) { // note: swap buffers always enabled for EGL + eglSwapBuffers(surface->display, surface->surface); + } + +#ifndef PUGL_WASM_SINGLE_EGL_CONTEXT + return eglMakeCurrent(surface->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) ? PUGL_SUCCESS : PUGL_FAILURE; +#else + return PUGL_SUCCESS; +#endif +} + +static PuglStatus +puglWasmGlCreate(PuglView* view) +{ + PuglWasmGlSurface* const surface = (PuglWasmGlSurface*)view->impl->surface; + const EGLDisplay display = surface->display; + const EGLConfig config = surface->config; + + const EGLint attrs[] = { + EGL_CONTEXT_CLIENT_VERSION, + view->hints[PUGL_CONTEXT_VERSION_MAJOR], + + EGL_CONTEXT_MAJOR_VERSION, + view->hints[PUGL_CONTEXT_VERSION_MAJOR], + + /* + EGL_CONTEXT_MINOR_VERSION, + view->hints[PUGL_CONTEXT_VERSION_MINOR], + + EGL_CONTEXT_OPENGL_DEBUG, + (view->hints[PUGL_USE_DEBUG_CONTEXT] ? EGL_TRUE : EGL_FALSE), + + EGL_CONTEXT_OPENGL_PROFILE_MASK, + (view->hints[PUGL_USE_COMPAT_PROFILE] + ? EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT + : EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT), + */ + + EGL_NONE + }; + + surface->context = eglCreateContext(display, config, EGL_NO_CONTEXT, attrs); + + if (surface->context == EGL_NO_CONTEXT) { + return PUGL_CREATE_CONTEXT_FAILED; + } + + surface->surface = eglCreateWindowSurface(display, config, 0, NULL); + + if (surface->surface == EGL_NO_SURFACE) { + return PUGL_CREATE_CONTEXT_FAILED; + } + +#ifdef PUGL_WASM_SINGLE_EGL_CONTEXT + eglMakeCurrent(surface->display, surface->surface, surface->surface, surface->context); +#endif + + return PUGL_SUCCESS; +} + +static void +puglWasmGlDestroy(PuglView* view) +{ + PuglWasmGlSurface* surface = (PuglWasmGlSurface*)view->impl->surface; + if (surface) { + const EGLDisplay display = surface->display; + if (surface->surface != EGL_NO_SURFACE) + eglDestroySurface(display, surface->surface); + if (surface->context != EGL_NO_CONTEXT) + eglDestroyContext(display, surface->context); + eglTerminate(display); + free(surface); + view->impl->surface = NULL; + } +} + +const PuglBackend* +puglGlBackend(void) +{ + static const PuglBackend backend = {puglWasmGlConfigure, + puglWasmGlCreate, + puglWasmGlDestroy, + puglWasmGlEnter, + puglWasmGlLeave, + puglStubGetContext}; + return &backend; +}