diff --git a/src/gallium/frontends/rusticl/core/kernel.rs b/src/gallium/frontends/rusticl/core/kernel.rs index 47c51ab0fad..c75968164a8 100644 --- a/src/gallium/frontends/rusticl/core/kernel.rs +++ b/src/gallium/frontends/rusticl/core/kernel.rs @@ -1641,11 +1641,6 @@ impl Kernel { // subtract the shader local_size as we only request something on top of that. variable_local_size -= static_local_size; - let samplers: Vec<_> = samplers - .iter() - .map(|s| ctx.create_sampler_state(s)) - .collect(); - let mut resources = Vec::with_capacity(resource_info.len()); let mut globals: Vec<*mut u32> = Vec::with_capacity(resource_info.len()); for (res, offset) in resource_info { @@ -1654,7 +1649,7 @@ impl Kernel { } ctx.bind_kernel(&nir_kernel_builds, variant)?; - ctx.bind_sampler_states(&samplers); + ctx.bind_sampler_states(samplers); ctx.bind_sampler_views(sviews); ctx.set_shader_images(&iviews); ctx.set_global_binding(resources.as_slice(), &mut globals); @@ -1700,12 +1695,9 @@ impl Kernel { } ctx.clear_global_binding(globals.len() as u32); - ctx.clear_sampler_states(samplers.len() as u32); ctx.memory_barrier(PIPE_BARRIER_GLOBAL_BUFFER); - samplers.iter().for_each(|s| ctx.delete_sampler_state(*s)); - if let Some(printf_buf) = &printf_buf { let tx = ctx .buffer_map(printf_buf, 0, printf_size as i32, RWFlags::RD) diff --git a/src/gallium/frontends/rusticl/core/memory.rs b/src/gallium/frontends/rusticl/core/memory.rs index a27f3e6a379..f52a0d72186 100644 --- a/src/gallium/frontends/rusticl/core/memory.rs +++ b/src/gallium/frontends/rusticl/core/memory.rs @@ -30,6 +30,7 @@ use std::collections::btree_map::Entry; use std::collections::HashMap; use std::convert::TryInto; use std::fmt::Debug; +use std::hash::Hash; use std::mem; use std::mem::size_of; use std::num::NonZeroU64; @@ -2296,3 +2297,38 @@ impl Sampler { )) } } + +/// A custom wrapper around pipe_sampler_state that implements certain Traits (e.g. Hash and +/// PartialEq) only looking at fields we actually care about. All other fields will be ignored! +#[repr(transparent)] +pub struct PipeSamplerState(pipe_sampler_state); + +impl From for PipeSamplerState { + fn from(value: pipe_sampler_state) -> Self { + Self(value) + } +} + +impl Hash for PipeSamplerState { + fn hash(&self, state: &mut H) { + state.write_u32(self.0.wrap_r()); + state.write_u32(self.0.min_img_filter()); + state.write_u32(self.0.unnormalized_coords()); + } +} + +impl PartialEq for PipeSamplerState { + fn eq(&self, other: &Self) -> bool { + self.0.wrap_r() == other.0.wrap_r() + && self.0.min_img_filter() == other.0.min_img_filter() + && self.0.unnormalized_coords() == other.0.unnormalized_coords() + } +} + +impl Eq for PipeSamplerState {} + +impl PipeSamplerState { + pub fn pipe(&self) -> &pipe_sampler_state { + &self.0 + } +} diff --git a/src/gallium/frontends/rusticl/core/queue.rs b/src/gallium/frontends/rusticl/core/queue.rs index ca000f7e232..d85f5e7560c 100644 --- a/src/gallium/frontends/rusticl/core/queue.rs +++ b/src/gallium/frontends/rusticl/core/queue.rs @@ -3,6 +3,7 @@ use crate::core::context::*; use crate::core::device::*; use crate::core::event::*; use crate::core::kernel::*; +use crate::core::memory::PipeSamplerState; use crate::core::platform::*; use crate::impl_cl_type_trait; @@ -16,6 +17,7 @@ use mesa_rust_util::properties::*; use rusticl_opencl_gen::*; use std::cmp; +use std::collections::HashMap; use std::ffi::c_void; use std::mem; use std::mem::ManuallyDrop; @@ -72,6 +74,7 @@ impl<'a> QueueContext<'a> { cso: None, use_stream: self.dev.prefers_real_buffer_in_cb0(), bound_sampler_views: 0, + samplers: HashMap::new(), } } } @@ -86,6 +89,7 @@ pub struct QueueContextWithState<'a> { variant: NirKernelVariant, cso: Option>, bound_sampler_views: u32, + samplers: HashMap, } impl QueueContextWithState<'_> { @@ -126,6 +130,21 @@ impl QueueContextWithState<'_> { Ok(()) } + pub fn bind_sampler_states(&mut self, samplers: Vec) { + let samplers = samplers + .into_iter() + .map(PipeSamplerState::from) + .map(|sampler| { + *self + .samplers + .entry(sampler) + .or_insert_with_key(|sampler| self.ctx.create_sampler_state(sampler.pipe())) + }) + .collect::>(); + + self.ctx.bind_sampler_states(&samplers); + } + pub fn bind_sampler_views(&mut self, views: Vec) { let cnt = views.len() as u32; let unbind_cnt = self.bound_sampler_views.saturating_sub(cnt); @@ -160,6 +179,11 @@ impl Drop for QueueContextWithState<'_> { fn drop(&mut self) { self.set_constant_buffer(0, &[]); self.ctx.clear_sampler_views(self.bound_sampler_views); + self.ctx.clear_sampler_states(self.dev.max_samplers()); + self.samplers + .values() + .for_each(|&sampler| self.ctx.delete_sampler_state(sampler)); + self.ctx.clear_shader_images(self.dev.caps.max_write_images); if self.builds.is_some() { // SAFETY: We simply unbind here. The bound cso will only be dropped at the end of this