mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
168 lines
6.2 KiB
Rust
168 lines
6.2 KiB
Rust
use std::borrow::Cow;
|
|
use wgpu::util::DeviceExt;
|
|
|
|
pub struct GpuContext {
|
|
pub device: wgpu::Device,
|
|
pub queue: wgpu::Queue,
|
|
pub pipeline: wgpu::ComputePipeline,
|
|
pub bind_group_layout: wgpu::BindGroupLayout,
|
|
}
|
|
|
|
impl GpuContext {
|
|
pub async fn new() -> anyhow::Result<Self> {
|
|
let instance = wgpu::Instance::default();
|
|
let adapter = instance
|
|
.request_adapter(&wgpu::RequestAdapterOptions {
|
|
power_preference: wgpu::PowerPreference::HighPerformance,
|
|
compatible_surface: None,
|
|
force_fallback_adapter: false,
|
|
})
|
|
.await
|
|
.ok_or_else(|| anyhow::anyhow!("No adapter found"))?;
|
|
|
|
let mut limits = wgpu::Limits::default();
|
|
limits.max_storage_buffer_binding_size = adapter.limits().max_storage_buffer_binding_size;
|
|
limits.max_buffer_size = adapter.limits().max_buffer_size;
|
|
limits.max_compute_invocations_per_workgroup =
|
|
adapter.limits().max_compute_invocations_per_workgroup;
|
|
|
|
let (device, queue) = adapter
|
|
.request_device(
|
|
&wgpu::DeviceDescriptor {
|
|
label: None,
|
|
required_features: wgpu::Features::empty(),
|
|
required_limits: limits,
|
|
},
|
|
None,
|
|
)
|
|
.await?;
|
|
|
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
|
label: Some("XOR Shader"),
|
|
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shaders/xor.wgsl"))),
|
|
});
|
|
|
|
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
label: None,
|
|
entries: &[
|
|
wgpu::BindGroupLayoutEntry {
|
|
binding: 0,
|
|
visibility: wgpu::ShaderStages::COMPUTE,
|
|
ty: wgpu::BindingType::Buffer {
|
|
ty: wgpu::BufferBindingType::Storage { read_only: true },
|
|
has_dynamic_offset: false,
|
|
min_binding_size: None,
|
|
},
|
|
count: None,
|
|
},
|
|
wgpu::BindGroupLayoutEntry {
|
|
binding: 1,
|
|
visibility: wgpu::ShaderStages::COMPUTE,
|
|
ty: wgpu::BindingType::Buffer {
|
|
ty: wgpu::BufferBindingType::Storage { read_only: false },
|
|
has_dynamic_offset: false,
|
|
min_binding_size: None,
|
|
},
|
|
count: None,
|
|
},
|
|
],
|
|
});
|
|
|
|
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
label: None,
|
|
bind_group_layouts: &[&bind_group_layout],
|
|
push_constant_ranges: &[],
|
|
});
|
|
|
|
let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
|
|
label: None,
|
|
layout: Some(&pipeline_layout),
|
|
module: &shader,
|
|
entry_point: "main",
|
|
});
|
|
|
|
Ok(Self {
|
|
device,
|
|
queue,
|
|
pipeline,
|
|
bind_group_layout,
|
|
})
|
|
}
|
|
|
|
pub fn run_xor_transform(&self, data: &[u8], _key: u8) -> anyhow::Result<Vec<u8>> {
|
|
let padded_len = (data.len() + 3) & !3;
|
|
let mut padded_data = vec![0u8; padded_len];
|
|
padded_data[..data.len()].copy_from_slice(data);
|
|
|
|
let input_buffer = self
|
|
.device
|
|
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
|
label: Some("Input Buffer"),
|
|
contents: bytemuck::cast_slice(&padded_data),
|
|
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_SRC,
|
|
});
|
|
|
|
let output_buffer = self.device.create_buffer(&wgpu::BufferDescriptor {
|
|
label: Some("Output Buffer"),
|
|
size: padded_len as u64,
|
|
usage: wgpu::BufferUsages::STORAGE
|
|
| wgpu::BufferUsages::COPY_SRC
|
|
| wgpu::BufferUsages::COPY_DST,
|
|
mapped_at_creation: false,
|
|
});
|
|
|
|
let staging_buffer = self.device.create_buffer(&wgpu::BufferDescriptor {
|
|
label: Some("Staging Buffer"),
|
|
size: padded_len as u64,
|
|
usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
|
|
mapped_at_creation: false,
|
|
});
|
|
|
|
let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
|
label: None,
|
|
layout: &self.bind_group_layout,
|
|
entries: &[
|
|
wgpu::BindGroupEntry {
|
|
binding: 0,
|
|
resource: input_buffer.as_entire_binding(),
|
|
},
|
|
wgpu::BindGroupEntry {
|
|
binding: 1,
|
|
resource: output_buffer.as_entire_binding(),
|
|
},
|
|
],
|
|
});
|
|
|
|
let mut encoder = self
|
|
.device
|
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
|
{
|
|
let mut compute_pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
|
|
label: None,
|
|
timestamp_writes: None,
|
|
});
|
|
compute_pass.set_pipeline(&self.pipeline);
|
|
compute_pass.set_bind_group(0, &bind_group, &[]);
|
|
|
|
let total_elements = (padded_len / 4) as u32;
|
|
let workgroups_x = ((total_elements + 255) / 256).min(65535);
|
|
let workgroups_y = (total_elements + 256 * 65535 - 1) / (256 * 65535);
|
|
compute_pass.dispatch_workgroups(workgroups_x, workgroups_y.max(1), 1);
|
|
}
|
|
|
|
encoder.copy_buffer_to_buffer(&output_buffer, 0, &staging_buffer, 0, padded_len as u64);
|
|
self.queue.submit(Some(encoder.finish()));
|
|
|
|
let (sender, receiver) = std::sync::mpsc::channel();
|
|
let buffer_slice = staging_buffer.slice(..);
|
|
buffer_slice.map_async(wgpu::MapMode::Read, move |v| sender.send(v).unwrap());
|
|
|
|
self.device.poll(wgpu::Maintain::Wait);
|
|
receiver.recv()??;
|
|
|
|
let data_bytes = buffer_slice.get_mapped_range().to_vec();
|
|
staging_buffer.unmap();
|
|
|
|
Ok(data_bytes[..data.len()].to_vec())
|
|
}
|
|
}
|