From 00e3d75a583303c0ebece8db1dbcffd0ef73a011 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Mon, 3 Mar 2025 11:44:19 +0100 Subject: [PATCH] rusticl/queue: make it unncessary to keep QueueContext Send Part-of: --- src/gallium/frontends/rusticl/core/queue.rs | 59 ++++++++++++++------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/src/gallium/frontends/rusticl/core/queue.rs b/src/gallium/frontends/rusticl/core/queue.rs index e2bee02384b..6ce9ccb30fe 100644 --- a/src/gallium/frontends/rusticl/core/queue.rs +++ b/src/gallium/frontends/rusticl/core/queue.rs @@ -24,24 +24,13 @@ use std::thread::JoinHandle; /// State tracking wrapper for [PipeContext] /// /// Used for tracking bound GPU state to lower CPU overhead and centralize state tracking -pub struct QueueContext { - // need to use ManuallyDrop so we can recycle the context without cloning - ctx: ManuallyDrop, +pub struct QueueContext<'a> { + ctx: &'a PipeContext, pub dev: &'static Device, use_stream: bool, } -impl QueueContext { - fn new_for(device: &'static Device) -> CLResult { - let ctx = device.create_context().ok_or(CL_OUT_OF_HOST_MEMORY)?; - - Ok(Self { - ctx: ManuallyDrop::new(ctx), - dev: device, - use_stream: device.prefers_real_buffer_in_cb0(), - }) - } - +impl QueueContext<'_> { pub fn update_cb0(&self, data: &[u8]) -> CLResult<()> { // only update if we actually bind data if !data.is_empty() { @@ -58,18 +47,49 @@ impl QueueContext { } // This should go once we moved all state tracking into QueueContext -impl Deref for QueueContext { +impl Deref for QueueContext<'_> { type Target = PipeContext; fn deref(&self) -> &Self::Target { - &self.ctx + self.ctx } } -impl Drop for QueueContext { +impl Drop for QueueContext<'_> { + fn drop(&mut self) { + self.set_constant_buffer(0, &[]); + } +} + +/// The main purpose of this type is to be able to create the context outside of the worker thread +/// to report back any sort of allocation failures early. +struct SendableQueueContext { + // need to use ManuallyDrop so we can recycle the context without cloning + ctx: ManuallyDrop, + dev: &'static Device, +} + +impl SendableQueueContext { + fn new(device: &'static Device) -> CLResult { + Ok(Self { + ctx: ManuallyDrop::new(device.create_context().ok_or(CL_OUT_OF_HOST_MEMORY)?), + dev: device, + }) + } + + /// The returned value can be used to execute operation on the wrapped context in a safe manner. + fn ctx(&self) -> QueueContext { + QueueContext { + ctx: &self.ctx, + dev: self.dev, + use_stream: self.dev.prefers_real_buffer_in_cb0(), + } + } +} + +impl Drop for SendableQueueContext { fn drop(&mut self) { let ctx = unsafe { ManuallyDrop::take(&mut self.ctx) }; - ctx.set_constant_buffer(0, &[]); self.dev.recycle_context(ctx); } } @@ -119,7 +139,7 @@ impl Queue { ) -> CLResult> { // we assume that memory allocation is the only possible failure. Any other failure reason // should be detected earlier (e.g.: checking for CAPs). - let ctx = QueueContext::new_for(device)?; + let ctx = SendableQueueContext::new(device)?; let (tx_q, rx_t) = mpsc::channel::>>(); Ok(Arc::new(Self { base: CLObjectBase::new(RusticlTypes::Queue), @@ -149,6 +169,7 @@ impl Queue { // TODO: use pipe_context::set_device_reset_callback to get notified about gone // GPU contexts let mut last_err = CL_SUCCESS as cl_int; + let ctx = ctx.ctx(); loop { let r = rx_t.recv(); if r.is_err() {