From 677a26e4d7f637a5d63936a455d584cb2045628d Mon Sep 17 00:00:00 2001 From: Stephan Sundermann Date: Sat, 4 Jul 2026 12:02:36 +0200 Subject: [PATCH] hal-gal: fix EGL_BAD_ACCESS after first frame by moving capture off init thread HAL_GAL_CaptureFrameBuffer() was being called once during capture_init(), which runs on the caller's setup thread. However, actual frame capture happens later via capture_acquire_frame(), invoked from unicapture's dedicated capture thread spawned in unicapture_start(). HAL_GAL_Init() appears to bind an EGL/GL context to the calling thread, and that binding is thread-affine. Capturing a frame during init bound the context to the wrong thread, causing every subsequent capture from the real worker thread to fail with EGL_BAD_ACCESS (0x3002). Removing the init-time capture call means the surface is only ever captured from the capture thread, fixing continuous capture after the first frame. --- unicapture/backends/libhalgal.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/unicapture/backends/libhalgal.c b/unicapture/backends/libhalgal.c index 678d597..0fec152 100644 --- a/unicapture/backends/libhalgal.c +++ b/unicapture/backends/libhalgal.c @@ -47,13 +47,14 @@ int capture_init(cap_backend_config_t* config, void** state_p) } INFO("HAL_GAL_CreateSurface done! SurfaceID: %d", this->surface_info.vendorData); - if ((ret = HAL_GAL_CaptureFrameBuffer(&this->surface_info)) != 0) { - - ERR("HAL_GAL_CaptureFrameBuffer failed: %x", ret); - ret = -3; - goto err_destroy; - } - INFO("HAL_GAL_CaptureFrameBuffer done! %x", ret); + // NOTE: We deliberately do NOT call HAL_GAL_CaptureFrameBuffer() here. + // capture_init() runs on the caller's/setup thread, but actual frame + // capture happens later on unicapture's dedicated capture thread + // (see unicapture_run() -> capture_acquire_frame()). HAL_GAL_Init() + // appears to bind an EGL/GL context to the calling thread, and that + // binding is thread-affine. Capturing a frame here would bind/use the + // context on this (wrong) thread, causing EGL_BAD_ACCESS (0x3002) on + // every subsequent capture attempt from the real capture thread. // ToDo: compare open("/dev/mem", O_RDWR|O_SYNC); if ((this->mem_fd = open("/dev/gfx", 2)) < 0) {