diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 20:38:23 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 20:38:23 +0000 |
commit | ff6e3c025658a5fa1affd094f220b623e7e1b24b (patch) | |
tree | 9faab72d69c92d24e349d184f5869b9796f17e0c /src/tests/opengl_surfaceless.c | |
parent | Initial commit. (diff) | |
download | libplacebo-upstream.tar.xz libplacebo-upstream.zip |
Adding upstream version 6.338.2.upstream/6.338.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tests/opengl_surfaceless.c')
-rw-r--r-- | src/tests/opengl_surfaceless.c | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/src/tests/opengl_surfaceless.c b/src/tests/opengl_surfaceless.c new file mode 100644 index 0000000..2d12a08 --- /dev/null +++ b/src/tests/opengl_surfaceless.c @@ -0,0 +1,247 @@ +#include "gpu_tests.h" +#include "opengl/utils.h" + +#include <libplacebo/opengl.h> + +static void opengl_interop_tests(pl_gpu gpu) +{ + pl_fmt fmt = pl_find_fmt(gpu, PL_FMT_UNORM, 1, 0, 0, + PL_FMT_CAP_RENDERABLE | PL_FMT_CAP_LINEAR); + if (!fmt) + return; + + pl_tex export = pl_tex_create(gpu, pl_tex_params( + .w = 32, + .h = 32, + .format = fmt, + .sampleable = true, + .renderable = true, + .blit_dst = fmt->caps & PL_FMT_CAP_BLITTABLE, + )); + + REQUIRE(export); + + struct pl_opengl_wrap_params wrap = { + .width = export->params.w, + .height = export->params.h, + .depth = export->params.d, + }; + + wrap.texture = pl_opengl_unwrap(gpu, export, &wrap.target, &wrap.iformat, NULL); + REQUIRE(wrap.texture); + + pl_tex import = pl_opengl_wrap(gpu, &wrap); + REQUIRE(import); + REQUIRE(import->params.renderable); + REQUIRE_CMP(import->params.blit_dst, ==, export->params.blit_dst, "d"); + + pl_tex_destroy(gpu, &import); + pl_tex_destroy(gpu, &export); +} + +#define PBUFFER_WIDTH 640 +#define PBUFFER_HEIGHT 480 + +struct swapchain_priv { + EGLDisplay display; + EGLSurface surface; +}; + +static void swap_buffers(void *priv) +{ + struct swapchain_priv *p = priv; + eglSwapBuffers(p->display, p->surface); +} + +static void opengl_swapchain_tests(pl_opengl gl, + EGLDisplay display, EGLSurface surface) +{ + if (surface == EGL_NO_SURFACE) + return; + + printf("testing opengl swapchain\n"); + pl_gpu gpu = gl->gpu; + pl_swapchain sw; + sw = pl_opengl_create_swapchain(gl, pl_opengl_swapchain_params( + .swap_buffers = swap_buffers, + .priv = &(struct swapchain_priv) { display, surface }, + )); + REQUIRE(sw); + + int w = PBUFFER_WIDTH, h = PBUFFER_HEIGHT; + REQUIRE(pl_swapchain_resize(sw, &w, &h)); + + for (int i = 0; i < 10; i++) { + struct pl_swapchain_frame frame; + REQUIRE(pl_swapchain_start_frame(sw, &frame)); + if (frame.fbo->params.blit_dst) + pl_tex_clear(gpu, frame.fbo, (float[4]){0}); + + // TODO: test this with an actual pl_renderer instance + struct pl_frame target; + pl_frame_from_swapchain(&target, &frame); + + REQUIRE(pl_swapchain_submit_frame(sw)); + pl_swapchain_swap_buffers(sw); + } + + pl_swapchain_destroy(&sw); +} + +int main() +{ + if (!gladLoaderLoadEGL(EGL_NO_DISPLAY)) + return SKIP; + + const char *extstr = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + if (!extstr || !strstr(extstr, "EGL_MESA_platform_surfaceless")) + return SKIP; + + // Create the OpenGL context + EGLDisplay dpy = eglGetPlatformDisplayEXT(EGL_PLATFORM_SURFACELESS_MESA, + (void *) EGL_DEFAULT_DISPLAY, NULL); + if (dpy == EGL_NO_DISPLAY) + return SKIP; + + EGLint major, minor; + if (!eglInitialize(dpy, &major, &minor)) + return SKIP; + + if (!gladLoaderLoadEGL(dpy)) + return SKIP; + + printf("Initialized EGL v%d.%d\n", major, minor); + int egl_ver = major * 10 + minor; + + struct { + EGLenum api; + EGLenum render; + int major, minor; + int glsl_ver; + EGLenum profile; + } egl_vers[] = { + { EGL_OPENGL_API, EGL_OPENGL_BIT, 4, 6, 460, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT }, + { EGL_OPENGL_API, EGL_OPENGL_BIT, 3, 3, 330, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT }, + { EGL_OPENGL_API, EGL_OPENGL_BIT, 3, 0, 130, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT, }, + { EGL_OPENGL_ES_API, EGL_OPENGL_ES3_BIT, 3, 0, 300, }, + }; + + struct pl_glsl_version last_glsl = {0}; + struct pl_gpu_limits last_limits = {0}; + + pl_log log = pl_test_logger(); + + for (int i = 0; i < PL_ARRAY_SIZE(egl_vers); i++) { + + const int cfg_attribs[] = { + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_RENDERABLE_TYPE, egl_vers[i].render, + EGL_NONE + }; + + EGLConfig config = 0; + EGLint num_configs = 0; + bool ok = eglChooseConfig(dpy, cfg_attribs, &config, 1, &num_configs); + if (!ok || !num_configs) + goto error; + + if (!eglBindAPI(egl_vers[i].api)) + goto error; + + EGLContext egl; + if (egl_vers[i].api == EGL_OPENGL_ES_API) { + // OpenGL ES + const EGLint egl_attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, egl_vers[i].major, + (egl_ver >= 15) ? EGL_CONTEXT_OPENGL_DEBUG : EGL_NONE, EGL_TRUE, + EGL_NONE + }; + + printf("Attempting creation of OpenGL ES v%d context\n", egl_vers[i].major); + egl = eglCreateContext(dpy, config, EGL_NO_CONTEXT, egl_attribs); + } else { + // Desktop OpenGL + const int egl_attribs[] = { + EGL_CONTEXT_MAJOR_VERSION, egl_vers[i].major, + EGL_CONTEXT_MINOR_VERSION, egl_vers[i].minor, + EGL_CONTEXT_OPENGL_PROFILE_MASK, egl_vers[i].profile, + (egl_ver >= 15) ? EGL_CONTEXT_OPENGL_DEBUG : EGL_NONE, EGL_TRUE, + EGL_NONE + }; + + printf("Attempting creation of Desktop OpenGL v%d.%d context\n", + egl_vers[i].major, egl_vers[i].minor); + egl = eglCreateContext(dpy, config, EGL_NO_CONTEXT, egl_attribs); + } + + if (!egl) + goto error; + + const EGLint pbuffer_attribs[] = { + EGL_WIDTH, PBUFFER_WIDTH, + EGL_HEIGHT, PBUFFER_HEIGHT, + EGL_NONE + }; + + EGLSurface surf = eglCreatePbufferSurface(dpy, config, pbuffer_attribs); + + if (!eglMakeCurrent(dpy, surf, surf, egl)) + goto error; + + pl_opengl gl = pl_opengl_create(log, pl_opengl_params( + .get_proc_addr = (pl_voidfunc_t (*)(const char *)) eglGetProcAddress, + .max_glsl_version = egl_vers[i].glsl_ver, + .debug = true, + .egl_display = dpy, + .egl_context = egl, +#ifdef CI_ALLOW_SW + .allow_software = true, +#endif + )); + if (!gl) + goto next; + + // Skip repeat tests + pl_gpu gpu = gl->gpu; + if (memcmp(&last_glsl, &gpu->glsl, sizeof(last_glsl)) == 0 && + memcmp(&last_limits, &gpu->limits, sizeof(last_limits)) == 0) + { + printf("Skipping tests due to duplicate capabilities/version\n"); + goto next; + } + +#ifdef CI_MAXGL + if (last_glsl.version && last_glsl.gles == gpu->glsl.gles) + goto next; +#endif + + last_glsl = gpu->glsl; + last_limits = gpu->limits; + + gpu_shader_tests(gpu); + gpu_interop_tests(gpu); + opengl_interop_tests(gpu); + opengl_swapchain_tests(gl, dpy, surf); + + // Reduce log spam after first successful test + pl_log_level_update(log, PL_LOG_INFO); + +next: + pl_opengl_destroy(&gl); + eglDestroySurface(dpy, surf); + eglDestroyContext(dpy, egl); + continue; + +error: ; + EGLint error = eglGetError(); + if (error != EGL_SUCCESS) + fprintf(stderr, "EGL error: %s\n", egl_err_str(error)); + } + + eglTerminate(dpy); + gladLoaderUnloadEGL(); + pl_log_destroy(&log); + + if (!last_glsl.version) + return SKIP; +} |