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, &params);
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