use crate::context::Context;
use crate::{Error, GpuCountPlan, GpuProfile, common::buffers::BufferRange};
use super::core::{RadixSorter, validate_key_for_bits};
use super::counted::CountedSorter;
use super::pipeline::SortItemKind;
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, bytemuck::Pod, bytemuck::Zeroable)]
pub struct KeyValue {
pub key: u32,
pub value: u32,
}
impl KeyValue {
pub const fn new(key: u32, value: u32) -> Self {
Self { key, value }
}
}
pub struct KeyValueSorter {
core: RadixSorter,
counted: Option<CountedSorter>,
device: wgpu::Device,
queue: wgpu::Queue,
adapter_info: Option<wgpu::AdapterInfo>,
}
impl KeyValueSorter {
pub fn new(device: &wgpu::Device, queue: &wgpu::Queue) -> Self {
Self {
core: RadixSorter::new(device, queue, SortItemKind::KeyValue),
counted: None,
device: device.clone(),
queue: queue.clone(),
adapter_info: None,
}
}
pub fn new_for_adapter(
device: &wgpu::Device,
queue: &wgpu::Queue,
adapter_info: &wgpu::AdapterInfo,
) -> Self {
Self {
core: RadixSorter::new_for_adapter(device, queue, SortItemKind::KeyValue, adapter_info),
counted: None,
device: device.clone(),
queue: queue.clone(),
adapter_info: Some(adapter_info.clone()),
}
}
pub fn from_context(ctx: &Context) -> Self {
Self::new_for_adapter(&ctx.device, &ctx.queue, &ctx.adapter_info)
}
pub async fn sort(&mut self, input: &[KeyValue]) -> Result<Vec<KeyValue>, Error> {
self.core.sort_slice(input).await
}
pub async fn sort_with_key_bits(
&mut self,
input: &[KeyValue],
key_bits: u32,
) -> Result<Vec<KeyValue>, Error> {
for item in input {
validate_key_for_bits(item.key, key_bits)?;
}
self.core.sort_slice_with_key_bits(input, key_bits).await
}
pub fn sort_gpu_to_gpu(
&mut self,
input: &wgpu::Buffer,
output: &wgpu::Buffer,
num_items: u32,
) -> Result<(), Error> {
self.core.sort_gpu_to_gpu(input, output, num_items)
}
pub fn sort_gpu_to_gpu_with_key_bits(
&mut self,
input: &wgpu::Buffer,
output: &wgpu::Buffer,
num_items: u32,
key_bits: u32,
) -> Result<(), Error> {
self.core
.sort_gpu_to_gpu_with_key_bits(input, output, num_items, key_bits)
}
pub async fn profile_sort_gpu_to_gpu(
&mut self,
input: &wgpu::Buffer,
output: &wgpu::Buffer,
num_items: u32,
) -> Result<GpuProfile, Error> {
self.core
.profile_sort_gpu_to_gpu(input, output, num_items)
.await
}
pub async fn profile_sort_gpu_to_gpu_with_key_bits(
&mut self,
input: &wgpu::Buffer,
output: &wgpu::Buffer,
num_items: u32,
key_bits: u32,
) -> Result<GpuProfile, Error> {
self.core
.profile_sort_gpu_to_gpu_with_key_bits(input, output, num_items, key_bits)
.await
}
pub fn record_sort(
&mut self,
encoder: &mut wgpu::CommandEncoder,
input: &wgpu::Buffer,
output: &wgpu::Buffer,
num_items: u32,
) -> Result<(), Error> {
self.core.record_sort(encoder, input, output, num_items)
}
pub fn record_sort_with_key_bits(
&mut self,
encoder: &mut wgpu::CommandEncoder,
input: &wgpu::Buffer,
output: &wgpu::Buffer,
num_items: u32,
key_bits: u32,
) -> Result<(), Error> {
self.core
.record_sort_with_key_bits(encoder, input, output, num_items, key_bits)
}
pub(crate) fn record_sort_ranges(
&mut self,
encoder: &mut wgpu::CommandEncoder,
input: BufferRange<'_>,
output: BufferRange<'_>,
num_items: u32,
key_bits: u32,
) -> Result<(), Error> {
self.core
.record_sort_ranges(encoder, input, output, num_items, key_bits)
}
pub(crate) fn reserve_fixed(&mut self, capacity: u32) -> Result<(), Error> {
self.core.reserve(capacity)
}
pub(crate) fn reserve_counted(&mut self, capacity: u32) -> Result<(), Error> {
if let Some(sorter) = self.core.eight_bit_mut() {
sorter.reserve_counted(capacity)
} else {
self.counted().reserve(capacity)
}
}
pub fn sort_counted_gpu_to_gpu(
&mut self,
input: &wgpu::Buffer,
output: &wgpu::Buffer,
count: &wgpu::Buffer,
capacity: u32,
) -> Result<(), Error> {
self.sort_counted_gpu_to_gpu_with_key_bits(input, output, count, capacity, u32::BITS)
}
pub fn sort_counted_gpu_to_gpu_with_key_bits(
&mut self,
input: &wgpu::Buffer,
output: &wgpu::Buffer,
count: &wgpu::Buffer,
capacity: u32,
key_bits: u32,
) -> Result<(), Error> {
if let Some(sorter) = self.core.eight_bit_mut() {
sorter.sort_counted_gpu_to_gpu(input, output, count, 0, capacity, key_bits)
} else {
self.counted()
.sort_gpu_to_gpu(input, output, count, capacity, key_bits)
}
}
pub fn record_sort_counted(
&mut self,
encoder: &mut wgpu::CommandEncoder,
input: &wgpu::Buffer,
output: &wgpu::Buffer,
count: &wgpu::Buffer,
capacity: u32,
) -> Result<(), Error> {
self.record_sort_counted_with_key_bits(encoder, input, output, count, capacity, u32::BITS)
}
pub fn record_sort_counted_with_key_bits(
&mut self,
encoder: &mut wgpu::CommandEncoder,
input: &wgpu::Buffer,
output: &wgpu::Buffer,
count: &wgpu::Buffer,
capacity: u32,
key_bits: u32,
) -> Result<(), Error> {
if let Some(sorter) = self.core.eight_bit_mut() {
sorter.record_sort_counted(encoder, input, output, count, 0, capacity, key_bits)
} else {
self.counted()
.record_sort(encoder, input, output, count, capacity, key_bits)
}
}
pub fn record_sort_with_count_plan(
&mut self,
encoder: &mut wgpu::CommandEncoder,
input: &wgpu::Buffer,
output: &wgpu::Buffer,
plan: &GpuCountPlan,
) -> Result<(), Error> {
self.counted()
.record_sort_with_plan(encoder, input, output, plan, u32::BITS)
}
pub fn record_sort_with_count_plan_and_key_bits(
&mut self,
encoder: &mut wgpu::CommandEncoder,
input: &wgpu::Buffer,
output: &wgpu::Buffer,
plan: &GpuCountPlan,
key_bits: u32,
) -> Result<(), Error> {
self.counted()
.record_sort_with_plan(encoder, input, output, plan, key_bits)
}
pub(crate) fn record_sort_ranges_with_count_plan(
&mut self,
encoder: &mut wgpu::CommandEncoder,
input: BufferRange<'_>,
output: BufferRange<'_>,
plan: &GpuCountPlan,
key_bits: u32,
) -> Result<(), Error> {
self.counted()
.record_sort_ranges_with_plan(encoder, input, output, plan, key_bits)
}
pub async fn profile_sort_counted_gpu_to_gpu(
&mut self,
input: &wgpu::Buffer,
output: &wgpu::Buffer,
count: &wgpu::Buffer,
capacity: u32,
) -> Result<GpuProfile, Error> {
self.profile_sort_counted_gpu_to_gpu_with_key_bits(
input,
output,
count,
capacity,
u32::BITS,
)
.await
}
pub async fn profile_sort_counted_gpu_to_gpu_with_key_bits(
&mut self,
input: &wgpu::Buffer,
output: &wgpu::Buffer,
count: &wgpu::Buffer,
capacity: u32,
key_bits: u32,
) -> Result<GpuProfile, Error> {
if let Some(sorter) = self.core.eight_bit_mut() {
sorter
.profile_sort_counted(input, output, count, 0, capacity, key_bits)
.await
} else {
self.counted()
.profile_sort(input, output, count, capacity, key_bits)
.await
}
}
fn counted(&mut self) -> &mut CountedSorter {
if self.counted.is_none() {
self.counted = Some(match &self.adapter_info {
Some(adapter_info) => CountedSorter::new_for_adapter(
&self.device,
&self.queue,
SortItemKind::KeyValue,
adapter_info,
),
None => CountedSorter::new(&self.device, &self.queue, SortItemKind::KeyValue),
});
}
self.counted
.as_mut()
.expect("counted key-value sorter is initialized")
}
}