From 9a8c2f09600d3f83abc3ebbc4f0f48764ba64894 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Sun, 20 Jul 2025 18:21:53 +0200 Subject: [PATCH] rusticl/gl: flush and wait on gl objects inside clEnqueueAcquireGLObjects This fixes flakes in the gl/gles OpenCL CTS tests on radeonsi and zink. Cc: mesa-stable Part-of: (cherry picked from commit 45c28a20a44ec5957950739830f41a84395c9e86) --- .pick_status.json | 2 +- src/gallium/frontends/rusticl/api/memory.rs | 16 +- src/gallium/frontends/rusticl/core/context.rs | 6 + src/gallium/frontends/rusticl/core/gl.rs | 141 +++++++++--------- 4 files changed, 94 insertions(+), 71 deletions(-) diff --git a/.pick_status.json b/.pick_status.json index 33d35f94261..a8f82c8fa82 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -6224,7 +6224,7 @@ "description": "rusticl/gl: flush and wait on gl objects inside clEnqueueAcquireGLObjects", "nominated": true, "nomination_type": 1, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": null, "notes": null diff --git a/src/gallium/frontends/rusticl/api/memory.rs b/src/gallium/frontends/rusticl/api/memory.rs index 33de229d6f6..7dec8612dae 100644 --- a/src/gallium/frontends/rusticl/api/memory.rs +++ b/src/gallium/frontends/rusticl/api/memory.rs @@ -3185,13 +3185,27 @@ fn enqueue_acquire_gl_objects( return Err(CL_INVALID_GL_OBJECT); } + // We need to flush on the applications thread: + // + // If an OpenGL context is bound to the current thread, then any OpenGL commands which + // 1. affect or access the contents of a memory object listed in the mem_objects list, and + // 2. were issued on that OpenGL context prior to the call to clEnqueueAcquireGLObjects + // will complete before execution of any OpenCL commands following the clEnqueueAcquireGLObjects + // which affect or access any of those memory objects. If a non-NULL event object is returned, + // it will report completion only after completion of such OpenGL commands. + let fence_fd = q.context.flush_gl_mem_objects(&objs)?; create_and_queue( q, CL_COMMAND_ACQUIRE_GL_OBJECTS, evs, event, false, - Box::new(move |_, ctx| copy_cube_to_slice(ctx, &objs)), + Box::new(move |_, ctx| { + if let Some(fence_fd) = fence_fd { + ctx.import_fence(&fence_fd).gpu_wait(ctx); + } + copy_cube_to_slice(ctx, &objs) + }), ) } diff --git a/src/gallium/frontends/rusticl/core/context.rs b/src/gallium/frontends/rusticl/core/context.rs index 7f58298fc45..5614f1faacd 100644 --- a/src/gallium/frontends/rusticl/core/context.rs +++ b/src/gallium/frontends/rusticl/core/context.rs @@ -10,6 +10,7 @@ use crate::core::util::*; use crate::impl_cl_type_trait; use mesa_rust::pipe::context::RWFlags; +use mesa_rust::pipe::fence::FenceFd; use mesa_rust::pipe::resource::*; use mesa_rust::pipe::screen::ResourceType; use mesa_rust_gen::*; @@ -654,6 +655,11 @@ impl Context { Ok(res) } + + pub fn flush_gl_mem_objects(&self, mem_objects: &[Mem]) -> CLResult> { + let gl_ctx = self.gl_ctx_manager.as_ref().ok_or(CL_INVALID_CONTEXT)?; + gl_ctx.flush(mem_objects) + } } impl Drop for Context { diff --git a/src/gallium/frontends/rusticl/core/gl.rs b/src/gallium/frontends/rusticl/core/gl.rs index f06e8394366..65ae9a9044c 100644 --- a/src/gallium/frontends/rusticl/core/gl.rs +++ b/src/gallium/frontends/rusticl/core/gl.rs @@ -206,6 +206,60 @@ impl GLCtxManager { } } + fn do_flush(&self, exports_in: &mut [mesa_glinterop_export_in]) -> CLResult> { + let mut fd = -1; + let mut flush_out = mesa_glinterop_flush_out { + version: 1, + fence_fd: &mut fd, + ..Default::default() + }; + + let err = match self.gl_ctx { + GLCtx::EGL(disp, ctx) => { + let egl_flush_objects_func = self + .xplat_manager + .MesaGLInteropEGLFlushObjects()? + .ok_or(CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR)?; + + unsafe { + egl_flush_objects_func( + disp.cast(), + ctx.cast(), + exports_in.len() as u32, + exports_in.as_mut_ptr(), + &mut flush_out, + ) + } + } + GLCtx::GLX(disp, ctx) => { + let glx_flush_objects_func = self + .xplat_manager + .MesaGLInteropGLXFlushObjects()? + .ok_or(CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR)?; + + unsafe { + glx_flush_objects_func( + disp.cast(), + ctx.cast(), + exports_in.len() as u32, + exports_in.as_mut_ptr(), + &mut flush_out, + ) + } + } + }; + + if err != 0 { + return Err(interop_to_cl_error(err)); + } + + if fd != -1 { + Ok(Some(FenceFd { fd: fd })) + } else { + Ok(None) + } + } + pub fn export_object( &self, cl_ctx: &Arc, @@ -229,13 +283,12 @@ impl GLCtxManager { ..Default::default() }; - let mut fd = -1; - - let mut flush_out = mesa_glinterop_flush_out { - version: 1, - fence_fd: &mut fd, - ..Default::default() - }; + if let Some(fence_fd) = self.do_flush(&mut [export_in])? { + cl_ctx.devs.iter().for_each(|dev| { + let fence = dev.helper_ctx().import_fence(&fence_fd); + fence.wait(); + }); + } let err = unsafe { match &self.gl_ctx { @@ -244,74 +297,14 @@ impl GLCtxManager { .MesaGLInteropEGLExportObject()? .ok_or(CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR)?; - let egl_flush_objects_func = xplat_manager - .MesaGLInteropEGLFlushObjects()? - .ok_or(CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR)?; - - let err_flush = egl_flush_objects_func( - disp.cast(), - ctx.cast(), - 1, - &mut export_in, - &mut flush_out, - ); - - if err_flush != 0 { - err_flush - } else { - if fd != -1 { - // TODO: use fence_server_sync in ctx inside the queue thread - let fence_fd = FenceFd { fd }; - cl_ctx.devs.iter().for_each(|dev| { - let fence = dev.helper_ctx().import_fence(&fence_fd); - fence.wait(); - }); - } - - egl_export_object_func( - disp.cast(), - ctx.cast(), - &mut export_in, - &mut export_out, - ) - } + egl_export_object_func(disp.cast(), ctx.cast(), &mut export_in, &mut export_out) } GLCtx::GLX(disp, ctx) => { let glx_export_object_func = xplat_manager .MesaGLInteropGLXExportObject()? .ok_or(CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR)?; - let glx_flush_objects_func = xplat_manager - .MesaGLInteropGLXFlushObjects()? - .ok_or(CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR)?; - - let err_flush = glx_flush_objects_func( - disp.cast(), - ctx.cast(), - 1, - &mut export_in, - &mut flush_out, - ); - - if err_flush != 0 { - err_flush - } else { - if fd != -1 { - // TODO: use fence_server_sync in ctx inside the queue thread - let fence_fd = FenceFd { fd }; - cl_ctx.devs.iter().for_each(|dev| { - let fence = dev.helper_ctx().import_fence(&fence_fd); - fence.wait(); - }); - } - - glx_export_object_func( - disp.cast(), - ctx.cast(), - &mut export_in, - &mut export_out, - ) - } + glx_export_object_func(disp.cast(), ctx.cast(), &mut export_in, &mut export_out) } } }; @@ -331,6 +324,16 @@ impl GLCtxManager { export_out: export_out, }) } + + pub fn flush(&self, mem_objects: &[Mem]) -> CLResult> { + let mut exports_in = mem_objects + .iter() + .filter_map(|m| m.gl_obj.as_ref()) + .map(|gl_obj| gl_obj.props) + .collect::>(); + + self.do_flush(&mut exports_in) + } } #[derive(Clone)]