comparison 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
comparison
equal deleted inserted replaced
2:cf2cb71d31dd 3:84e66ea83026
1 // Copyright 2012-2022 David Robillard <d@drobilla.net>
2 // Copyright 2021-2022 Filipe Coelho <falktx@falktx.com>
3 // SPDX-License-Identifier: ISC
4
5 #include "../pugl-upstream/src/stub.h"
6 #include "wasm.h"
7
8 #include "pugl/pugl.h"
9
10 #include <stdio.h>
11 #include <stdlib.h>
12
13 #include <EGL/egl.h>
14
15 // for performance reasons we can keep a single EGL context always active
16 #define PUGL_WASM_SINGLE_EGL_CONTEXT
17
18 typedef struct {
19 EGLDisplay display;
20 EGLConfig config;
21 EGLContext context;
22 EGLSurface surface;
23 } PuglWasmGlSurface;
24
25 static EGLint
26 puglWasmGlHintValue(const int value)
27 {
28 return value == PUGL_DONT_CARE ? EGL_DONT_CARE : value;
29 }
30
31 static int
32 puglWasmGlGetAttrib(const EGLDisplay display,
33 const EGLConfig config,
34 const EGLint attrib)
35 {
36 EGLint value = 0;
37 eglGetConfigAttrib(display, config, attrib, &value);
38 return value;
39 }
40
41 static PuglStatus
42 puglWasmGlConfigure(PuglView* view)
43 {
44 PuglInternals* const impl = view->impl;
45
46 const EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
47
48 if (display == EGL_NO_DISPLAY) {
49 return PUGL_CREATE_CONTEXT_FAILED;
50 }
51
52 int major, minor;
53 if (eglInitialize(display, &major, &minor) != EGL_TRUE) {
54 return PUGL_CREATE_CONTEXT_FAILED;
55 }
56
57 EGLConfig config;
58 int numConfigs;
59
60 if (eglGetConfigs(display, &config, 1, &numConfigs) != EGL_TRUE || numConfigs != 1) {
61 eglTerminate(display);
62 return PUGL_CREATE_CONTEXT_FAILED;
63 }
64
65 // clang-format off
66 const EGLint attrs[] = {
67 /*
68 GLX_X_RENDERABLE, True,
69 GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
70 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
71 GLX_RENDER_TYPE, GLX_RGBA_BIT,
72 EGL_SAMPLE_BUFFERS, view->hints[PUGL_MULTI_SAMPLE] ? 1 : 0,
73 */
74 EGL_SAMPLES, puglWasmGlHintValue(view->hints[PUGL_SAMPLES]),
75 EGL_RED_SIZE, puglWasmGlHintValue(view->hints[PUGL_RED_BITS]),
76 EGL_GREEN_SIZE, puglWasmGlHintValue(view->hints[PUGL_GREEN_BITS]),
77 EGL_BLUE_SIZE, puglWasmGlHintValue(view->hints[PUGL_BLUE_BITS]),
78 EGL_ALPHA_SIZE, puglWasmGlHintValue(view->hints[PUGL_ALPHA_BITS]),
79 EGL_DEPTH_SIZE, puglWasmGlHintValue(view->hints[PUGL_DEPTH_BITS]),
80 EGL_STENCIL_SIZE, puglWasmGlHintValue(view->hints[PUGL_STENCIL_BITS]),
81 EGL_NONE
82 };
83 // clang-format on
84
85 if (eglChooseConfig(display, attrs, &config, 1, &numConfigs) != EGL_TRUE || numConfigs != 1) {
86 eglTerminate(display);
87 return PUGL_CREATE_CONTEXT_FAILED;
88 }
89
90 PuglWasmGlSurface* const surface =
91 (PuglWasmGlSurface*)calloc(1, sizeof(PuglWasmGlSurface));
92 impl->surface = surface;
93
94 surface->display = display;
95 surface->config = config;
96 surface->context = EGL_NO_SURFACE;
97 surface->surface = EGL_NO_CONTEXT;
98
99 view->hints[PUGL_RED_BITS] =
100 puglWasmGlGetAttrib(display, config, EGL_RED_SIZE);
101 view->hints[PUGL_GREEN_BITS] =
102 puglWasmGlGetAttrib(display, config, EGL_GREEN_SIZE);
103 view->hints[PUGL_BLUE_BITS] =
104 puglWasmGlGetAttrib(display, config, EGL_BLUE_SIZE);
105 view->hints[PUGL_ALPHA_BITS] =
106 puglWasmGlGetAttrib(display, config, EGL_ALPHA_SIZE);
107 view->hints[PUGL_DEPTH_BITS] =
108 puglWasmGlGetAttrib(display, config, EGL_DEPTH_SIZE);
109 view->hints[PUGL_STENCIL_BITS] =
110 puglWasmGlGetAttrib(display, config, EGL_STENCIL_SIZE);
111 view->hints[PUGL_SAMPLES] =
112 puglWasmGlGetAttrib(display, config, EGL_SAMPLES);
113
114 // double-buffering is always enabled for EGL
115 view->hints[PUGL_DOUBLE_BUFFER] = 1;
116
117 return PUGL_SUCCESS;
118 }
119
120 PUGL_WARN_UNUSED_RESULT
121 static PuglStatus
122 puglWasmGlEnter(PuglView* view, const PuglExposeEvent* PUGL_UNUSED(expose))
123 {
124 PuglWasmGlSurface* const surface = (PuglWasmGlSurface*)view->impl->surface;
125 if (!surface || !surface->context || !surface->surface) {
126 return PUGL_FAILURE;
127 }
128
129 #ifndef PUGL_WASM_SINGLE_EGL_CONTEXT
130 return eglMakeCurrent(surface->display, surface->surface, surface->surface, surface->context) ? PUGL_SUCCESS : PUGL_FAILURE;
131 #else
132 return PUGL_SUCCESS;
133 #endif
134 }
135
136 PUGL_WARN_UNUSED_RESULT
137 static PuglStatus
138 puglWasmGlLeave(PuglView* view, const PuglExposeEvent* expose)
139 {
140 PuglWasmGlSurface* const surface = (PuglWasmGlSurface*)view->impl->surface;
141
142 if (expose) { // note: swap buffers always enabled for EGL
143 eglSwapBuffers(surface->display, surface->surface);
144 }
145
146 #ifndef PUGL_WASM_SINGLE_EGL_CONTEXT
147 return eglMakeCurrent(surface->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) ? PUGL_SUCCESS : PUGL_FAILURE;
148 #else
149 return PUGL_SUCCESS;
150 #endif
151 }
152
153 static PuglStatus
154 puglWasmGlCreate(PuglView* view)
155 {
156 PuglWasmGlSurface* const surface = (PuglWasmGlSurface*)view->impl->surface;
157 const EGLDisplay display = surface->display;
158 const EGLConfig config = surface->config;
159
160 const EGLint attrs[] = {
161 EGL_CONTEXT_CLIENT_VERSION,
162 view->hints[PUGL_CONTEXT_VERSION_MAJOR],
163
164 EGL_CONTEXT_MAJOR_VERSION,
165 view->hints[PUGL_CONTEXT_VERSION_MAJOR],
166
167 /*
168 EGL_CONTEXT_MINOR_VERSION,
169 view->hints[PUGL_CONTEXT_VERSION_MINOR],
170
171 EGL_CONTEXT_OPENGL_DEBUG,
172 (view->hints[PUGL_USE_DEBUG_CONTEXT] ? EGL_TRUE : EGL_FALSE),
173
174 EGL_CONTEXT_OPENGL_PROFILE_MASK,
175 (view->hints[PUGL_USE_COMPAT_PROFILE]
176 ? EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT
177 : EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT),
178 */
179
180 EGL_NONE
181 };
182
183 surface->context = eglCreateContext(display, config, EGL_NO_CONTEXT, attrs);
184
185 if (surface->context == EGL_NO_CONTEXT) {
186 return PUGL_CREATE_CONTEXT_FAILED;
187 }
188
189 surface->surface = eglCreateWindowSurface(display, config, 0, NULL);
190
191 if (surface->surface == EGL_NO_SURFACE) {
192 return PUGL_CREATE_CONTEXT_FAILED;
193 }
194
195 #ifdef PUGL_WASM_SINGLE_EGL_CONTEXT
196 eglMakeCurrent(surface->display, surface->surface, surface->surface, surface->context);
197 #endif
198
199 return PUGL_SUCCESS;
200 }
201
202 static void
203 puglWasmGlDestroy(PuglView* view)
204 {
205 PuglWasmGlSurface* surface = (PuglWasmGlSurface*)view->impl->surface;
206 if (surface) {
207 const EGLDisplay display = surface->display;
208 if (surface->surface != EGL_NO_SURFACE)
209 eglDestroySurface(display, surface->surface);
210 if (surface->context != EGL_NO_CONTEXT)
211 eglDestroyContext(display, surface->context);
212 eglTerminate(display);
213 free(surface);
214 view->impl->surface = NULL;
215 }
216 }
217
218 const PuglBackend*
219 puglGlBackend(void)
220 {
221 static const PuglBackend backend = {puglWasmGlConfigure,
222 puglWasmGlCreate,
223 puglWasmGlDestroy,
224 puglWasmGlEnter,
225 puglWasmGlLeave,
226 puglStubGetContext};
227 return &backend;
228 }