1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//! Boilerplate-reducing helpers for launching OxiProj's 1-D GPU kernels.
use ;
/// Default threads-per-block for OxiProj's element-wise (one-thread-per-point)
/// kernels. 256 is a good occupancy default across Turing→Blackwell.
pub const BLOCK: u32 = 256;
/// Launch `kernel` over `n` threads (one per coordinate / point) with a 1-D grid
/// of [`BLOCK`]-thread blocks, then block until the stream completes.
///
/// `args` is the kernel argument tuple (device pointers as `u64`, the element
/// count as `u32`, then any `f64` scalars), in the order the kernel's `.entry`
/// parameters declare them.
///
/// # Errors
///
/// Propagates any launch or synchronisation error from the driver.
/// Allocate a device buffer of `src.len()` elements and enqueue the host→device
/// copy of `src` **onto `stream`**, returning the buffer to feed a kernel.
///
/// Use this — not [`DeviceBuffer::from_host`] — to stage a kernel's inputs.
/// `from_host` issues the *synchronous* `cuMemcpyHtoD`, which for pageable host
/// memory (an ordinary `&[T]`) merely stages into the driver's internal buffer
/// and then runs the DMA to the device on the **default (NULL) stream**. Every
/// OxiProj stream is created `CU_STREAM_NON_BLOCKING`, so it does **not**
/// implicitly synchronise with the NULL stream: a kernel launched on `stream`
/// would race that still-in-flight DMA and read not-yet-copied (zero) device
/// memory — yielding `f(0)` for whichever elements the DMA had not yet reached.
/// Enqueuing the copy on the *same* `stream` the kernel uses makes the kernel
/// correctly stream-ordered after it.
///
/// The copy is enqueued, not awaited: `src` must remain valid until `stream` is
/// synchronised (the [`launch_1d`] that consumes the returned buffer does this).
///
/// # Errors
///
/// Propagates any allocation or host→device copy error from the driver
/// (including `CudaError::InvalidValue` when `src` is empty).
/// Run an **in-place** element-wise kernel over `data` (a flat `f64` buffer)
/// using page-locked (pinned) host staging for fast, consistent DMA.
///
/// Pageable host↔device copies fall back to a slow staged path inside the driver;
/// pinned memory enables true DMA, which on bandwidth-bound element-wise kernels
/// (e.g. coordinate reprojection) is several times faster and far less variable.
/// The host→device copy, kernel launch, and device→host copy are all enqueued on
/// one stream and awaited with a single synchronisation.
///
/// `n_threads` is the number of threads to launch (e.g. coordinate *pairs*, not
/// the `f64` element count). `make_args` builds the kernel argument tuple from the
/// device buffer pointer; its first parameter must be that pointer.
///
/// # Errors
///
/// Propagates any allocation, copy, launch, or synchronisation error.