1 #include "gpu_tests.h"
2
3 #ifndef EPOXY_HAS_EGL
main()4 int main()
5 {
6 return SKIP;
7 }
8 #else // EPOXY_HAS_EGL
9
10 #include "opengl/utils.h"
11 #include <epoxy/gl.h>
12 #include <epoxy/egl.h>
13
opengl_interop_tests(pl_gpu gpu)14 static void opengl_interop_tests(pl_gpu gpu)
15 {
16 pl_fmt fmt = pl_find_fmt(gpu, PL_FMT_UNORM, 1, 0, 0,
17 PL_FMT_CAP_RENDERABLE | PL_FMT_CAP_LINEAR);
18 if (!fmt)
19 return;
20
21 pl_tex export = pl_tex_create(gpu, &(struct pl_tex_params) {
22 .w = 32,
23 .h = 32,
24 .format = fmt,
25 .sampleable = true,
26 .renderable = true,
27 .blit_dst = fmt->caps & PL_FMT_CAP_BLITTABLE,
28 });
29
30 REQUIRE(export);
31
32 struct pl_opengl_wrap_params wrap = {
33 .width = export->params.w,
34 .height = export->params.h,
35 .depth = export->params.d,
36 };
37
38 wrap.texture = pl_opengl_unwrap(gpu, export, &wrap.target, &wrap.iformat, NULL);
39 REQUIRE(wrap.texture);
40
41 pl_tex import = pl_opengl_wrap(gpu, &wrap);
42 REQUIRE(import);
43 REQUIRE(import->params.renderable);
44 REQUIRE(import->params.blit_dst == export->params.blit_dst);
45
46 pl_tex_destroy(gpu, &import);
47 pl_tex_destroy(gpu, &export);
48 }
49
50 #define PBUFFER_WIDTH 640
51 #define PBUFFER_HEIGHT 480
52
53 struct swapchain_priv {
54 EGLDisplay display;
55 EGLSurface surface;
56 };
57
swap_buffers(void * priv)58 static void swap_buffers(void *priv)
59 {
60 struct swapchain_priv *p = priv;
61 eglSwapBuffers(p->display, p->surface);
62 }
63
opengl_swapchain_tests(pl_opengl gl,EGLDisplay display,EGLSurface surface)64 static void opengl_swapchain_tests(pl_opengl gl,
65 EGLDisplay display, EGLSurface surface)
66 {
67 if (surface == EGL_NO_SURFACE)
68 return;
69
70 printf("testing opengl swapchain\n");
71 pl_gpu gpu = gl->gpu;
72 pl_swapchain sw;
73 sw = pl_opengl_create_swapchain(gl, &(struct pl_opengl_swapchain_params) {
74 .swap_buffers = swap_buffers,
75 .priv = &(struct swapchain_priv) { display, surface },
76 });
77 REQUIRE(sw);
78
79 int w = PBUFFER_WIDTH, h = PBUFFER_HEIGHT;
80 REQUIRE(pl_swapchain_resize(sw, &w, &h));
81
82 for (int i = 0; i < 10; i++) {
83 struct pl_swapchain_frame frame;
84 REQUIRE(pl_swapchain_start_frame(sw, &frame));
85 if (frame.fbo->params.blit_dst)
86 pl_tex_clear(gpu, frame.fbo, (float[4]){0});
87
88 // TODO: test this with an actual pl_renderer instance
89 struct pl_frame target;
90 pl_frame_from_swapchain(&target, &frame);
91
92 REQUIRE(pl_swapchain_submit_frame(sw));
93 pl_swapchain_swap_buffers(sw);
94 }
95
96 pl_swapchain_destroy(&sw);
97 }
98
opengl_test_export_import(pl_opengl gl,enum pl_handle_type handle_type)99 static void opengl_test_export_import(pl_opengl gl,
100 enum pl_handle_type handle_type)
101 {
102 pl_gpu gpu = gl->gpu;
103 printf("testing opengl import/export\n");
104
105 if (!(gpu->export_caps.tex & handle_type) ||
106 !(gpu->import_caps.tex & handle_type)) {
107 fprintf(stderr, "%s unsupported caps!\n", __func__);
108 return;
109 }
110
111 pl_fmt fmt = pl_find_fmt(gpu, PL_FMT_UNORM, 1, 0, 0, PL_FMT_CAP_BLITTABLE);
112 if (!fmt) {
113 fprintf(stderr, "%s unsupported format\n", __func__);
114 return;
115 }
116
117 pl_tex export = pl_tex_create(gpu, &(struct pl_tex_params) {
118 .w = 32,
119 .h = 32,
120 .format = fmt,
121 .export_handle = handle_type,
122 });
123 REQUIRE(export);
124 REQUIRE_HANDLE(export->shared_mem, handle_type);
125
126 pl_tex import = pl_tex_create(gpu, &(struct pl_tex_params) {
127 .w = 32,
128 .h = 32,
129 .format = fmt,
130 .import_handle = handle_type,
131 .shared_mem = export->shared_mem,
132 });
133 REQUIRE(import);
134
135 pl_tex_destroy(gpu, &import);
136 pl_tex_destroy(gpu, &export);
137 }
138
main()139 int main()
140 {
141 // Create the OpenGL context
142 if (!epoxy_has_egl_extension(EGL_NO_DISPLAY, "EGL_MESA_platform_surfaceless"))
143 return SKIP;
144
145 EGLDisplay dpy = eglGetPlatformDisplayEXT(EGL_PLATFORM_SURFACELESS_MESA,
146 EGL_DEFAULT_DISPLAY, NULL);
147 if (dpy == EGL_NO_DISPLAY)
148 return SKIP;
149
150 EGLint major, minor;
151 if (!eglInitialize(dpy, &major, &minor))
152 return SKIP;
153
154 printf("Initialized EGL v%d.%d\n", major, minor);
155 int egl_ver = major * 10 + minor;
156
157 struct {
158 EGLenum api;
159 EGLenum render;
160 int major, minor;
161 int glsl_ver;
162 EGLenum profile;
163 } egl_vers[] = {
164 { EGL_OPENGL_API, EGL_OPENGL_BIT, 4, 6, 460, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT },
165 { EGL_OPENGL_API, EGL_OPENGL_BIT, 4, 5, 450, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT },
166 { EGL_OPENGL_API, EGL_OPENGL_BIT, 4, 4, 440, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT },
167 { EGL_OPENGL_API, EGL_OPENGL_BIT, 4, 0, 400, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT },
168 { EGL_OPENGL_API, EGL_OPENGL_BIT, 3, 3, 330, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT },
169 { EGL_OPENGL_API, EGL_OPENGL_BIT, 3, 2, 150, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT },
170 { EGL_OPENGL_API, EGL_OPENGL_BIT, 3, 1, 140, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT, },
171 { EGL_OPENGL_API, EGL_OPENGL_BIT, 3, 0, 130, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT, },
172 { EGL_OPENGL_API, EGL_OPENGL_BIT, 2, 1, 120, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT, },
173 { EGL_OPENGL_API, EGL_OPENGL_BIT, 2, 0, 110, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT, },
174 { EGL_OPENGL_ES_API, EGL_OPENGL_ES3_BIT, 3, 0, 300, },
175 { EGL_OPENGL_ES_API, EGL_OPENGL_ES2_BIT, 2, 0, 100, },
176 };
177
178 struct pl_glsl_version last_glsl = {0};
179 struct pl_gpu_limits last_limits = {0};
180
181 pl_log log = pl_test_logger();
182
183 for (int i = 0; i < PL_ARRAY_SIZE(egl_vers); i++) {
184
185 const int cfg_attribs[] = {
186 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
187 EGL_RENDERABLE_TYPE, egl_vers[i].render,
188 EGL_NONE
189 };
190
191 EGLConfig config = 0;
192 EGLint num_configs = 0;
193 bool ok = eglChooseConfig(dpy, cfg_attribs, &config, 1, &num_configs);
194 if (!ok || !num_configs)
195 goto error;
196
197 if (!eglBindAPI(egl_vers[i].api))
198 goto error;
199
200 EGLContext egl;
201 if (egl_vers[i].api == EGL_OPENGL_ES_API) {
202 // OpenGL ES
203 const EGLint egl_attribs[] = {
204 EGL_CONTEXT_CLIENT_VERSION, egl_vers[i].major,
205 (egl_ver >= 15) ? EGL_CONTEXT_OPENGL_DEBUG : EGL_NONE, EGL_TRUE,
206 EGL_NONE
207 };
208
209 printf("Attempting creation of OpenGL ES v%d context\n", egl_vers[i].major);
210 egl = eglCreateContext(dpy, config, EGL_NO_CONTEXT, egl_attribs);
211 } else {
212 // Desktop OpenGL
213 const int egl_attribs[] = {
214 EGL_CONTEXT_MAJOR_VERSION, egl_vers[i].major,
215 EGL_CONTEXT_MINOR_VERSION, egl_vers[i].minor,
216 EGL_CONTEXT_OPENGL_PROFILE_MASK, egl_vers[i].profile,
217 (egl_ver >= 15) ? EGL_CONTEXT_OPENGL_DEBUG : EGL_NONE, EGL_TRUE,
218 EGL_NONE
219 };
220
221 printf("Attempting creation of Desktop OpenGL v%d.%d context\n",
222 egl_vers[i].major, egl_vers[i].minor);
223 egl = eglCreateContext(dpy, config, EGL_NO_CONTEXT, egl_attribs);
224 }
225
226 if (!egl)
227 goto error;
228
229 const EGLint pbuffer_attribs[] = {
230 EGL_WIDTH, PBUFFER_WIDTH,
231 EGL_HEIGHT, PBUFFER_HEIGHT,
232 EGL_NONE
233 };
234
235 EGLSurface surf = eglCreatePbufferSurface(dpy, config, pbuffer_attribs);
236
237 if (!eglMakeCurrent(dpy, surf, surf, egl))
238 goto error;
239
240 struct pl_opengl_params params = pl_opengl_default_params;
241 params.max_glsl_version = egl_vers[i].glsl_ver;
242 params.debug = true;
243 params.egl_display = dpy;
244 params.egl_context = egl;
245 #ifdef CI_ALLOW_SW
246 params.allow_software = true;
247 #endif
248
249 pl_opengl gl = pl_opengl_create(log, ¶ms);
250 if (!gl)
251 goto next;
252
253 // Skip repeat tests
254 pl_gpu gpu = gl->gpu;
255 if (memcmp(&last_glsl, &gpu->glsl, sizeof(last_glsl)) == 0 &&
256 memcmp(&last_limits, &gpu->limits, sizeof(last_limits)) == 0)
257 {
258 printf("Skipping tests due to duplicate capabilities/version\n");
259 goto next;
260 }
261
262 last_glsl = gpu->glsl;
263 last_limits = gpu->limits;
264
265 gpu_shader_tests(gpu);
266 gpu_interop_tests(gpu);
267 opengl_interop_tests(gpu);
268 opengl_swapchain_tests(gl, dpy, surf);
269 opengl_test_export_import(gl, PL_HANDLE_DMA_BUF);
270
271 // Reduce log spam after first successful test
272 pl_log_level_update(log, PL_LOG_INFO);
273
274 next:
275 pl_opengl_destroy(&gl);
276 eglDestroySurface(dpy, surf);
277 eglDestroyContext(dpy, egl);
278 continue;
279
280 error: ;
281 EGLint error = eglGetError();
282 if (error != EGL_SUCCESS)
283 fprintf(stderr, "EGL error: %s\n", egl_err_str(error));
284 }
285
286 eglTerminate(dpy);
287 pl_log_destroy(&log);
288
289 if (!last_glsl.version)
290 return SKIP;
291 }
292
293 #endif // EPOXY_HAS_EGL
294