Video processing is an inherently parallel domain: every frame comprises millions of independent pixels, and most spatial operations (such as Sobel edge detection, Gaussian blurs, and bilateral smoothing) exhibit strong 2D spatial locality.
However, naive CUDA implementations that read pixel neighborhoods directly from device global memory quickly saturate memory bandwidth, resulting in poor hardware utilization.
Shared Memory Tiling & Halo Regions
To maximize memory efficiency, our capstone processor partitions each frame into 2D tiles (e.g., 16×16 pixels) mapped to CUDA thread blocks.
Because filter kernels (like a 5×5 convolution) require pixels outside the primary tile—the **halo region**—we allocate shared memory with an apron:
__shared__ float s_Tile[TILE_H + 2 * RADIUS][TILE_W + 2 * RADIUS];Each thread loads its primary pixel into shared memory, while edge threads cooperatively fetch halo boundary pixels. Once a `__syncthreads()` barrier completes, all filter computations operate purely on on-chip SRAM at negligible latency.
Overlapping Memory Transfers with Streams
PCIe bus transfer between host and device is the primary bottleneck for continuous video feeds. By allocating **page-locked (pinned) host memory** and multiplexing across multiple `cudaStream_t` queues, we pipeline:
- Transferring Frame $N+1$ from Host to Device
- Executing Convolution Kernel on Frame $N$
- Transferring Frame $N-1$ from Device to Host
This concurrent pipeline sustains uninterrupted 60+ FPS processing on high-resolution streams.