rusticl/queue: cache samplers
OpenCL doesn't really allow a wide range of different samplers, so the cache hit rate is pretty high across all applications. This also allows us to stop unbinding samplers after each kernel launch. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36243>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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<pipe_sampler_state> for PipeSamplerState {
|
||||
fn from(value: pipe_sampler_state) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for PipeSamplerState {
|
||||
fn hash<H: std::hash::Hasher>(&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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<CSOWrapper<'a>>,
|
||||
bound_sampler_views: u32,
|
||||
samplers: HashMap<PipeSamplerState, *mut c_void>,
|
||||
}
|
||||
|
||||
impl QueueContextWithState<'_> {
|
||||
@@ -126,6 +130,21 @@ impl QueueContextWithState<'_> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn bind_sampler_states(&mut self, samplers: Vec<pipe_sampler_state>) {
|
||||
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::<Vec<_>>();
|
||||
|
||||
self.ctx.bind_sampler_states(&samplers);
|
||||
}
|
||||
|
||||
pub fn bind_sampler_views(&mut self, views: Vec<PipeSamplerView>) {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user