rusticl: add QueueContext to track GPU state

Signed-off-by: Karol Herbst <kherbst@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25946>
This commit is contained in:
Karol Herbst
2023-10-27 16:26:38 +02:00
parent a4f47ba52c
commit 5f97ef3d03
2 changed files with 36 additions and 9 deletions
+2 -3
View File
@@ -4,7 +4,6 @@ use crate::core::context::*;
use crate::core::queue::*;
use crate::impl_cl_type_trait;
use mesa_rust::pipe::context::*;
use mesa_rust::pipe::query::*;
use mesa_rust_gen::*;
use mesa_rust_util::static_assert;
@@ -24,7 +23,7 @@ static_assert!(CL_RUNNING == 1);
static_assert!(CL_SUBMITTED == 2);
static_assert!(CL_QUEUED == 3);
pub type EventSig = Box<dyn FnOnce(&Arc<Queue>, &PipeContext) -> CLResult<()>>;
pub type EventSig = Box<dyn FnOnce(&Arc<Queue>, &QueueContext) -> CLResult<()>>;
pub enum EventTimes {
Queued = CL_PROFILING_COMMAND_QUEUED as isize,
@@ -194,7 +193,7 @@ impl Event {
// We always assume that work here simply submits stuff to the hardware even if it's just doing
// sw emulation or nothing at all.
// If anything requets waiting, we will update the status through fencing later.
pub fn call(&self, ctx: &PipeContext) {
pub fn call(&self, ctx: &QueueContext) {
let mut lock = self.state();
let status = lock.status;
let queue = self.queue.as_ref().unwrap();
+34 -6
View File
@@ -10,6 +10,7 @@ use mesa_rust_util::properties::*;
use rusticl_opencl_gen::*;
use std::mem;
use std::ops::Deref;
use std::sync::mpsc;
use std::sync::Arc;
use std::sync::Mutex;
@@ -17,6 +18,33 @@ use std::sync::Weak;
use std::thread;
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 {
ctx: PipeContext,
}
impl QueueContext {
fn new_for(device: &Device) -> CLResult<Self> {
Ok(Self {
ctx: device
.screen()
.create_context()
.ok_or(CL_OUT_OF_HOST_MEMORY)?,
})
}
}
// This should go once we moved all state tracking into QueueContext
impl Deref for QueueContext {
type Target = PipeContext;
fn deref(&self) -> &Self::Target {
&self.ctx
}
}
struct QueueState {
pending: Vec<Arc<Event>>,
last: Weak<Event>,
@@ -53,7 +81,7 @@ impl Queue {
) -> CLResult<Arc<Queue>> {
// we assume that memory allocation is the only possible failure. Any other failure reason
// should be detected earlier (e.g.: checking for CAPs).
let pipe = device.screen().create_context().unwrap();
let ctx = QueueContext::new_for(device)?;
let (tx_q, rx_t) = mpsc::channel::<Vec<Arc<Event>>>();
Ok(Arc::new(Self {
base: CLObjectBase::new(),
@@ -81,7 +109,7 @@ impl Queue {
// If we hit any deps from another queue, flush so we don't risk a dead
// lock.
if e.deps.iter().any(|ev| ev.queue != e.queue) {
flush_events(&mut flushed, &pipe);
flush_events(&mut flushed, &ctx);
}
// We have to wait on user events or events from other queues.
@@ -98,25 +126,25 @@ impl Queue {
continue;
}
e.call(&pipe);
e.call(&ctx);
if e.is_user() {
// On each user event we flush our events as application might
// wait on them before signaling user events.
flush_events(&mut flushed, &pipe);
flush_events(&mut flushed, &ctx);
// Wait on user events as they are synchronization points in the
// application's control.
e.wait();
} else if Platform::dbg().sync_every_event {
flushed.push(e);
flush_events(&mut flushed, &pipe);
flush_events(&mut flushed, &ctx);
} else {
flushed.push(e);
}
}
flush_events(&mut flushed, &pipe);
flush_events(&mut flushed, &ctx);
})
.unwrap(),
}))